Skip to contentSkip to conversation

PML (Paging Modification Logging) support

PATCH Superseded Kai Huang 4 participants 65 messages Mar 27, 2015 – Apr 10, 2015

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

Kai Huang

author
#0 lore raw

cover PML (Paging Modification Logging) support

Hi all,

This patch series adds PML support to Xen. Please kindly help to review it.

The patches were organized in below way:

patch 0:
enables EPT A/D bit support, which is a dependence of PML
patch 1 to 8:
changes in VMX to enable PML
patch 9:
change log-dirty common code to support PML
patch 10:
change p2m-ept.c to support PML

The design has already been discussed previously at below thread:

http://lists.xen.org/archives/html/xen-devel/2015-02/msg01305.html

I listed the brief changes to previous design according to your comments for your quick reference, while the complete updated design was also pasted below.

- Instead of flushing PML buffer at beginning of every VMEXIT, at peek/clear log-dirty op, we explicitly flush all vcpus' PML buffers before reporting dirty pages to userspace.

- Address creating vcpu when domain is already in log-dirty mode, suggested by Tim.

- In flushing PML buffer, instead of calling paging_mark_dirty unconditionally for all logged dirty pages, we call p2m_type_change_one to change guest page from log-dirty mode to normal mode, and only when the p2m_type_change_one has been successfully done, the guest page will be marked dirty. This is required by video ram tracking, and it's also reasonable to do it.

I also did some performance measure which was pasted after the design for your reference.

====================== The Design ======================================

PML (Page Modification Logging) is a new feature on Intel's Boardwell server platfrom targeted to reduce overhead of dirty logging mechanism. This patch series add PML support to Xen.

Background
==========

Currently, dirty logging is done via write protection, which basically sets guest memory we want to log to be read-only, then when guest performs first write to that memory, write fault (EPT violation in case of EPT is used) happens, in which we are able to log the dirty GFN, and set the W permission bit. This mechanism works but at cost of one write fault for each first write from the guest.

PML Introduction
================

PML is a hardware-assisted efficient way, based on EPT mechanism, for dirty logging. Briefly, PML logs dirty GPA automatically to a 4K PML buffer when CPU changes EPT table's D-bit from 0 to 1. To accomplish this, a new PML buffer base address (machine address), a PML index, and a new PML buffer full VMEXIT were added to VMCS. Initially PML index can be set to 511 (8 bytes for each GPA) to indicate the buffer is empty, and CPU decreases PML index by 1 after logging GPA. Before performing GPA logging, PML checks PML index to see if PML buffer has been fully logged, in which case a PML buffer full VMEXIT happens, and VMM should flush logged GPAs (to data structure keeps dirty pages) and reset PML index so that further GPAs can be logged again.

The specification of PML can be found at:
http://www.intel.com/content/www/us/en/processors/page-modification-logging-vmm-white-paper.html

With PML, we don't have to use write protection but just clear D-bit of EPT entry of guest memory to do dirty logging, with an additional PML buffer full VMEXIT for 512 dirty GPAs. Theoretically, this can reduce hypervisor overhead when guest is in dirty logging mode, and more CPU cycles can be allocated to guest, therefore it's expected benchmarks in guest will have better performance comparing to non-PML.

Design
======

- PML feature is used globally

A new Xen boot parameter will be added to control PML feature detection. Once PML feature is detected, it will be used for dirty logging for all domains globally. Currently we don't support to use PML on basis of per-domain as it will require additional control from XL tool.

The new parameter is a top level parameter 'ept=<options>' with a sub-boolean 'pml_enable'. PML is disabled by default and 'ept=pml' enables it.

- PML enable/disable for particular Domain

Enabling PML means:
- allocate PML buffer, set PML base address
- initialize PML index to 511
- turn on PML in VMCS

PML needs to be enabled globally for all vcpus of a domain, as PML buffer and PML index are per-vcpu, but EPT table is shared by vcpus, therefore enabling PML on partial vcpus of a domain won't work.

PML will be enabled for the domain when it is switched to log-dirty mode, and vice versa will be disabled when domain is switched back to normal mode.

Also commented by Tim Deegan, there have been cases where VMs are put into log-dirty mode before their VCPUs are assigned, so we also need to handle enabling PML for new vcpus. In this case, when creating vcpu, we check if the domain has already been in log-dirty mode or not. If domain has been in log-dirty mode, we enable PML for it, and failure of enabling PML results in failure of vcpu creation.

After PML is enabled for the domain, we only need to clear EPT entry's D-bit for guest memory in order to log dirty pages, instead of setting EPT entry to be read-only. And for partial log-dirty, if PML is used, we also manually set D-bit for guest memory that is in normal mode to avoid unnecessary GPA logging, as PML works globally at entire EPT table.

However, for super pages, we still write protect them even with PML as we still need to split super page to 4K page in log-dirty mode.

- PML buffer flush

PML buffer flush means:
- read out PML index
- go through all logged dirty GPAs, and update them to log-dirty radix tree
- reset PML index to 511

There are two places we need to flush PML buffer. The first place is PML buffer full VMEXIT handler (apparently), and the second place is in paging_log_dirty_op (either peek or clean), as vcpus are running asynchronously along with paging_log_dirty_op is called from userspace via hypercall, and it's possible there are dirty GPAs logged in vcpus' PML buffers but not full, therefore we'd better to flush all vcpus' PML buffers before reporting dirty GPAs to userspace.

Suggested by Jan and Tim, we flush PML buffer of vcpu on PML buffer full VMEXIT, and in peek/clean path, we explicitly flush PML buffer of all vcpus of the domain.

- Video RAM tracking (and partial dirty logging for guest memory range)

Video RAM is in dirty logging mode unconditionally during guest's run-time, and it is partial memory range of the guest. However, PML operates on the whole guest memory (the whole valid EPT table, more precisely), so we need to choose whether to use PML if only partial guest memory ranges are in dirty logging mode.

Currently, PML will be used as long as there's guest memory in dirty logging mode, no matter globally or partially.

In flushing PML buffer, we will call p2m_type_change_one to change guest memory from log-dirty to normal mode, and only the guest memory, which has been successfully changed from log-dirty to normal mode, will be updated to log-dirty radix tree. This is required by current video RAM tracking implementation.

======================== specjbb performance ===========================

I measured specjbb performance in guest when guest is in video ram tracking mode (the most usual case I think), and when guest is in global log-dirty mode (I made some change in XL tool to put guest global log-dirty mode infinitely, see below), from which we can see that PML does improved the specjbb performance in guest while guest is in log-dirty mode, and the more frequently dirty pages are queried, the more performance gain we will have. So while PML probably can't speed up live migration process directly, it will be benefical for use cases such as guest memory dirty speed monitoring.

- video ram tracking:

    WP              PML         
    122805          123887
    120792          123249
    118577          123348
    121856          125195
    121286          122056
    120139          123037

avg 120909 123462

    100%            102.11%    

performance gain: 2.11%

- global log-dirty:

    WP              PML
    72862           79511
    73466           81173
    72989           81177
    73138           81777
    72811           80257
    72486           80413

avg 72959 80718

    100%            110.63%

performance gain: 10.63%

Test machine: Boardwell server with 16 CPUs (1.6G) + 4G memory. Xen hypervisor: lastest upstream Xen
dom0 kernel: 3.16.0
guest: 4 vcpus + 1G memory.
guest os: ubuntu 14.04 with 3.13.0-24-generic kernel.

Note: global log-dirty data was measured with below change, and running 'xl migrate <dom> localhost'.

tools/libxc/xc_domain_save.c +5 -0
index 254fdb3..88a10f1 100644
@@ -335,7 +335,12 @@ static int analysis_phase(xc_interface *xch, uint32_t domid, struct save_ctx *ct
         
    start = llgettimeofday();
              
+#define PML_TEST
+#ifdef  PML_TEST
+    for ( j = 0; true; j++ )
+#else
    for ( j = 0; j < runs; j++ )
+#endif
    {
        int i;
 

Kai Huang (10):
VMX: Enable EPT A/D bit support
VMX: New parameter to control PML enabling
VMX: Add PML definition and feature detection.
VMX: 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.

 xen/arch/x86/hvm/vmx/vmcs.c        | 241 +++++++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/vmx/vmx.c         |  37 ++++++
 xen/arch/x86/mm/hap/hap.c          |  31 ++++-
 xen/arch/x86/mm/p2m-ept.c          |  81 ++++++++++++-
 xen/arch/x86/mm/p2m.c              |  36 ++++++
 xen/arch/x86/mm/paging.c           |  15 ++-
 xen/arch/x86/mm/shadow/common.c    |   2 +-
 xen/include/asm-x86/domain.h       |   1 +
 xen/include/asm-x86/hvm/vmx/vmcs.h |  25 +++-
 xen/include/asm-x86/hvm/vmx/vmx.h  |   6 +-
 xen/include/asm-x86/p2m.h          |  11 ++
 xen/include/asm-x86/paging.h       |   3 +-
 12 files changed, 474 insertions(+), 15 deletions(-)
Signature · 1 line
2.1.0
author
#1 lore raw

PATCH 1/10 VMX: Enable EPT A/D bit support

PML requires A/D bit support so enable it for further use.

---
 xen/arch/x86/hvm/vmx/vmcs.c        | 1 +
 xen/arch/x86/mm/p2m-ept.c          | 8 +++++++-
 xen/include/asm-x86/hvm/vmx/vmcs.h | 4 +++-
 xen/include/asm-x86/hvm/vmx/vmx.h  | 5 ++++-
 4 files changed, 15 insertions(+), 3 deletions(-)
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
index d614638..2f645fe 100644
@@ -103,6 +103,7 @@ static void __init vmx_display_features(void)
     P(cpu_has_vmx_tpr_shadow, "APIC TPR shadow");
     P(cpu_has_vmx_ept, "Extended Page Tables (EPT)");
     P(cpu_has_vmx_vpid, "Virtual-Processor Identifiers (VPID)");
+    P(cpu_has_vmx_ept_ad_bit, "EPT A/D bit");
     P(cpu_has_vmx_vnmi, "Virtual NMI");
     P(cpu_has_vmx_msr_bitmap, "MSR direct-access bitmap");
     P(cpu_has_vmx_unrestricted_guest, "Unrestricted Guest");
xen/arch/x86/mm/p2m-ept.c +7 -1
index c2d7720..8650092 100644
@@ -233,6 +233,9 @@ static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry,
     if ( !ept_set_middle_entry(p2m, &new_ept) )
         return 0;
 
+    /* It's better to copy A bit of Middle entry from original entry */
+    new_ept.a = ept_entry->a;
+
     table = map_domain_page(new_ept.mfn);
     trunk = 1UL << ((level - 1) * EPT_TABLE_ORDER);
 
@@ -244,7 +247,7 @@ 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);
+        /* A/D bits are inherited from superpage */
         ASSERT(!epte->avail3);
 
         ept_p2m_type_to_flags(epte, epte->sa_p2mt, epte->access);
@@ -1071,6 +1074,9 @@ 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;
 
+    /* Enable EPT A/D bit if it's supported by hardware */
+    ept->ept_ad = cpu_has_vmx_ept_ad_bit ? 1 : 0;
+
     if ( !zalloc_cpumask_var(&ept->synced_mask) )
         return -ENOMEM;
 
xen/include/asm-x86/hvm/vmx/vmcs.h +3 -1
index 6fce6aa..4528346 100644
@@ -62,7 +62,8 @@ struct ept_data {
     struct {
             u64 ept_mt :3,
                 ept_wl :3,
-                rsvd   :6,
+                ept_ad :1,
+                rsvd   :5,
                 asr    :52;
         };
         u64 eptp;
@@ -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_SUPPORT                  0x00200000
 
 #define VMX_MISC_VMWRITE_ALL                    0x20000000
 
xen/include/asm-x86/hvm/vmx/vmx.h +4 -1
index 91c5e18..9afd351 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 */
@@ -261,6 +262,8 @@ extern uint8_t posted_intr_vector;
     (vmx_ept_vpid_cap & VMX_EPT_SUPERPAGE_2MB)
 #define cpu_has_vmx_ept_invept_single_context   \
     (vmx_ept_vpid_cap & VMX_EPT_INVEPT_SINGLE_CONTEXT)
+#define cpu_has_vmx_ept_ad_bit                  \
+    (vmx_ept_vpid_cap & VMX_EPT_AD_BIT_SUPPORT)
 
 #define EPT_2MB_SHIFT     16
 #define EPT_1GB_SHIFT     17
Signature · 1 line
2.1.0
#2 lore raw

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

Quoted 27 lines · Kai Huang

PML requires A/D bit support so enable it for further use.

---
 xen/arch/x86/hvm/vmx/vmcs.c        | 1 +
 xen/arch/x86/mm/p2m-ept.c          | 8 +++++++-
 xen/include/asm-x86/hvm/vmx/vmcs.h | 4 +++-
 xen/include/asm-x86/hvm/vmx/vmx.h  | 5 ++++-
 4 files changed, 15 insertions(+), 3 deletions(-)
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
index d614638..2f645fe 100644
@@ -103,6 +103,7 @@ static void __init vmx_display_features(void)
     P(cpu_has_vmx_tpr_shadow, "APIC TPR shadow");
     P(cpu_has_vmx_ept, "Extended Page Tables (EPT)");
     P(cpu_has_vmx_vpid, "Virtual-Processor Identifiers (VPID)");
+    P(cpu_has_vmx_ept_ad_bit, "EPT A/D bit");
     P(cpu_has_vmx_vnmi, "Virtual NMI");
     P(cpu_has_vmx_msr_bitmap, "MSR direct-access bitmap");
     P(cpu_has_vmx_unrestricted_guest, "Unrestricted Guest");
xen/arch/x86/mm/p2m-ept.c +0 -0
index c2d7720..8650092 100644

xen/arch/x86/mm/p2m-ept.c static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry, · line 237

Quoted 5 lines
xen/arch/x86/mm/p2m-ept.c +2 -0
@@ -233,6 +233,9 @@ static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry,
     if ( !ept_set_middle_entry(p2m, &new_ept) )
         return 0;
 
+    /* It's better to copy A bit of Middle entry from original entry */
+    new_ept.a = ept_entry->a;

Surely d needs to be propagated as well? Would it make sense to extend ept_set_middle_entry() to do all of new_ept setup in one location?

Quoted 14 lines
xen/arch/x86/mm/p2m-ept.c +2 -1
+
     table = map_domain_page(new_ept.mfn);
     trunk = 1UL << ((level - 1) * EPT_TABLE_ORDER);
 
@@ -244,7 +247,7 @@ 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);
+        /* A/D bits are inherited from superpage */
         ASSERT(!epte->avail3);
 
         ept_p2m_type_to_flags(epte, epte->sa_p2mt, epte->access);

xen/arch/x86/mm/p2m-ept.c int ept_p2m_init(struct p2m_domain *p2m) · line 1078

Quoted 5 lines
xen/arch/x86/mm/p2m-ept.c +2 -0
@@ -1071,6 +1074,9 @@ 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;
 
+    /* Enable EPT A/D bit if it's supported by hardware */
+    ept->ept_ad = cpu_has_vmx_ept_ad_bit ? 1 : 0;

This will incur overhead on all EPT operations. It should only be enabled if pml is going to be in use. (I think you need reverse patches 1 and 2 in the series, and gate on pml_enable here)

Quoted 9 lines
xen/arch/x86/mm/p2m-ept.c +1 -0
+
     if ( !zalloc_cpumask_var(&ept->synced_mask) )
         return -ENOMEM;
 
xen/include/asm-x86/hvm/vmx/vmcs.h +0 -0
index 6fce6aa..4528346 100644

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

Quoted 7 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +2 -1
@@ -62,7 +62,8 @@ struct ept_data {
     struct {
             u64 ept_mt :3,
                 ept_wl :3,
-                rsvd   :6,
+                ept_ad :1,
+                rsvd   :5,
                 asr    :52;

While you are making this change, can you add comments similar to ept_entry_t describing the bits?

Quoted 25 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +1 -0
         };
         u64 eptp;
@@ -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_SUPPORT                  0x00200000
 
 #define VMX_MISC_VMWRITE_ALL                    0x20000000
 
xen/include/asm-x86/hvm/vmx/vmx.h +2 -1
index 91c5e18..9afd351 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 */

xen/include/asm-x86/hvm/vmx/vmx.h extern uint8_t posted_intr_vector; · line 266

Quoted 5 lines
xen/include/asm-x86/hvm/vmx/vmx.h +2 -0
@@ -261,6 +262,8 @@ extern uint8_t posted_intr_vector;
     (vmx_ept_vpid_cap & VMX_EPT_SUPERPAGE_2MB)
 #define cpu_has_vmx_ept_invept_single_context   \
     (vmx_ept_vpid_cap & VMX_EPT_INVEPT_SINGLE_CONTEXT)
+#define cpu_has_vmx_ept_ad_bit                  \
+    (vmx_ept_vpid_cap & VMX_EPT_AD_BIT_SUPPORT)

I think cpu_has_vmx_ept_ad is sufficient, without the _bit suffix making it longer.

~Andrew

Quoted 3 lines
xen/include/asm-x86/hvm/vmx/vmx.h +0 -0
 #define EPT_2MB_SHIFT     16
 #define EPT_1GB_SHIFT     17
author
#3 lore raw

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

Quoted 31 lines · Andrew Cooper
Quoted 30 lines · Kai Huang

PML requires A/D bit support so enable it for further use.

---
  xen/arch/x86/hvm/vmx/vmcs.c        | 1 +
  xen/arch/x86/mm/p2m-ept.c          | 8 +++++++-
  xen/include/asm-x86/hvm/vmx/vmcs.h | 4 +++-
  xen/include/asm-x86/hvm/vmx/vmx.h  | 5 ++++-
  4 files changed, 15 insertions(+), 3 deletions(-)
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
index d614638..2f645fe 100644
@@ -103,6 +103,7 @@ static void __init vmx_display_features(void)
      P(cpu_has_vmx_tpr_shadow, "APIC TPR shadow");
      P(cpu_has_vmx_ept, "Extended Page Tables (EPT)");
      P(cpu_has_vmx_vpid, "Virtual-Processor Identifiers (VPID)");
+    P(cpu_has_vmx_ept_ad_bit, "EPT A/D bit");
      P(cpu_has_vmx_vnmi, "Virtual NMI");
      P(cpu_has_vmx_msr_bitmap, "MSR direct-access bitmap");
      P(cpu_has_vmx_unrestricted_guest, "Unrestricted Guest");
xen/arch/x86/mm/p2m-ept.c +0 -0
index c2d7720..8650092 100644
@@ -233,6 +233,9 @@ static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry,
      if ( !ept_set_middle_entry(p2m, &new_ept) )
          return 0;
 
Quoted 3 lines

xen/arch/x86/mm/p2m-ept.c static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry, · line 237

Quoted 2 lines
xen/arch/x86/mm/p2m-ept.c +2 -0
+    /* It's better to copy A bit of Middle entry from original entry */
+    new_ept.a = ept_entry->a;

Surely d needs to be propagated as well?

No it's not necessary. D-bit is not defined in middle level EPT table. Only leaf table entry has D-bit definition.

Quoted 2 lines

Would it make sense to extend
ept_set_middle_entry() to do all of new_ept setup in one location?

Yes it certainly makes sense to move A-bit propagation into ept_set_middle_entry, but this also requires adding additional original EPT entry pointer to ept_set_middle_entry as parameter. And ept_set_middle_entry is also called by ept_next_level, therefore changing it requires more code change, something like below. While I am fine with both, which solution do you prefer?

+++ b/xen/arch/x86/mm/p2m-ept.c
@@ -208,7 +208,8 @@ static void ept_p2m_type_to_flags(struct p2m_domain *p2m, ept_entry_t *entry,
#define GUEST_TABLE_POD_PAGE 3

/* Fill in middle levels of ept table */
-static int ept_set_middle_entry(struct p2m_domain *p2m, ept_entry_t *ept_entry) +static int ept_set_middle_entry(struct p2m_domain *p2m, ept_entry_t *new_entry,
+ ept_entry_t *ori_entry)

 {
     struct page_info *pg;

@@ -216,11 +217,13 @@ static int ept_set_middle_entry(struct p2m_domain *p2m, ept_entry_t *ept_entry)

     if ( pg == NULL )
         return 0;
-    ept_entry->epte = 0;
-    ept_entry->mfn = page_to_mfn(pg);
-    ept_entry->access = p2m->default_access;
+    new_entry->epte = 0;
+    new_entry->mfn = page_to_mfn(pg);
+    new_entry->access = p2m->default_access;

- ept_entry->r = ept_entry->w = ept_entry->x = 1;
+ new_entry->r = new_entry->w = new_entry->x = 1;
+
+ new_entry->a = ori_entry->a;

     return 1;

}
@@ -257,7 +260,7 @@ static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry,

     ASSERT(is_epte_superpage(ept_entry));

- if ( !ept_set_middle_entry(p2m, &new_ept) )
+ if ( !ept_set_middle_entry(p2m, &new_ept, ept_entry) )

         return 0;

     table = map_domain_page(new_ept.mfn);

@@ -337,7 +340,7 @@ static int ept_next_level(struct p2m_domain *p2m, bool_t read_only,
if ( read_only )
return GUEST_TABLE_MAP_FAILED;

- if ( !ept_set_middle_entry(p2m, ept_entry) )
+ if ( !ept_set_middle_entry(p2m, ept_entry, &e) )
return GUEST_TABLE_MAP_FAILED;
else
e = atomic_read_ept_entry(ept_entry); /* Refresh */

Quoted 18 lines
Quoted 18 lines
xen/arch/x86/mm/p2m-ept.c +2 -1
+
      table = map_domain_page(new_ept.mfn);
      trunk = 1UL << ((level - 1) * EPT_TABLE_ORDER);
 
@@ -244,7 +247,7 @@ 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);
+        /* A/D bits are inherited from superpage */
          ASSERT(!epte->avail3);
 
          ept_p2m_type_to_flags(epte, epte->sa_p2mt, epte->access);
@@ -1071,6 +1074,9 @@ 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;
 
Quoted 5 lines

xen/arch/x86/mm/p2m-ept.c int ept_p2m_init(struct p2m_domain *p2m) · line 1078

Quoted 2 lines
xen/arch/x86/mm/p2m-ept.c +2 -0
+    /* Enable EPT A/D bit if it's supported by hardware */
+    ept->ept_ad = cpu_has_vmx_ept_ad_bit ? 1 : 0;

This will incur overhead on all EPT operations. It should only be enabled if pml is going to be in use. (I think you need reverse patches 1 and 2 in the series, and gate on pml_enable here)

Sure. Will do.

Quoted 5 lines
Quoted 5 lines
xen/arch/x86/mm/p2m-ept.c +1 -0
+
      if ( !zalloc_cpumask_var(&ept->synced_mask) )
          return -ENOMEM;
 
Quoted 14 lines

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

Quoted 12 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +2 -1
index 6fce6aa..4528346 100644
@@ -62,7 +62,8 @@ struct ept_data {
      struct {
              u64 ept_mt :3,
                  ept_wl :3,
-                rsvd   :6,
+                ept_ad :1,
+                rsvd   :5,
                  asr    :52;

While you are making this change, can you add comments similar to ept_entry_t describing the bits?

Sure. I can add a comment for 'ept_ad' bit here. I didn't do it as there's no comments for other bits neither.

Quoted 25 lines
Quoted 25 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +1 -0
          };
          u64 eptp;
@@ -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_SUPPORT                  0x00200000
 
  #define VMX_MISC_VMWRITE_ALL                    0x20000000
 
xen/include/asm-x86/hvm/vmx/vmx.h +2 -1
index 91c5e18..9afd351 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 */
Quoted 8 lines

xen/include/asm-x86/hvm/vmx/vmx.h extern uint8_t posted_intr_vector; · line 266

Quoted 6 lines
xen/include/asm-x86/hvm/vmx/vmx.h +2 -0
@@ -261,6 +262,8 @@ extern uint8_t posted_intr_vector;
      (vmx_ept_vpid_cap & VMX_EPT_SUPERPAGE_2MB)
  #define cpu_has_vmx_ept_invept_single_context   \
      (vmx_ept_vpid_cap & VMX_EPT_INVEPT_SINGLE_CONTEXT)
+#define cpu_has_vmx_ept_ad_bit                  \
+    (vmx_ept_vpid_cap & VMX_EPT_AD_BIT_SUPPORT)

I think cpu_has_vmx_ept_ad is sufficient, without the _bit suffix making it longer.

Sure. Will do.

Thanks,
-Kai

Quoted 11 lines

~Andrew

xen/include/asm-x86/hvm/vmx/vmx.h extern uint8_t posted_intr_vector; · line 269

Quoted 3 lines
xen/include/asm-x86/hvm/vmx/vmx.h +0 -0
  #define EPT_2MB_SHIFT     16
  #define EPT_1GB_SHIFT     17

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

#4 lore raw

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

Quoted 38 lines · Kai Huang
Quoted 27 lines · Andrew Cooper
Quoted 26 lines · Kai Huang

PML requires A/D bit support so enable it for further use.

---
  xen/arch/x86/hvm/vmx/vmcs.c        | 1 +
  xen/arch/x86/mm/p2m-ept.c          | 8 +++++++-
  xen/include/asm-x86/hvm/vmx/vmcs.h | 4 +++-
  xen/include/asm-x86/hvm/vmx/vmx.h  | 5 ++++-
  4 files changed, 15 insertions(+), 3 deletions(-)
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
index d614638..2f645fe 100644
@@ -103,6 +103,7 @@ static void __init vmx_display_features(void)
      P(cpu_has_vmx_tpr_shadow, "APIC TPR shadow");
      P(cpu_has_vmx_ept, "Extended Page Tables (EPT)");
      P(cpu_has_vmx_vpid, "Virtual-Processor Identifiers (VPID)");
+    P(cpu_has_vmx_ept_ad_bit, "EPT A/D bit");
      P(cpu_has_vmx_vnmi, "Virtual NMI");
      P(cpu_has_vmx_msr_bitmap, "MSR direct-access bitmap");
      P(cpu_has_vmx_unrestricted_guest, "Unrestricted Guest");
xen/arch/x86/mm/p2m-ept.c +0 -0
index c2d7720..8650092 100644
Quoted 8 lines
Quoted 7 lines
xen/arch/x86/mm/p2m-ept.c +0 -0
@@ -233,6 +233,9 @@ static int ept_split_super_page(struct
 p2m_domain *p2m, ept_entry_t *ept_entry,
      if ( !ept_set_middle_entry(p2m, &new_ept) )
          return 0;
  +    /* It's better to copy A bit of Middle entry from original

entry */
+ new_ept.a = ept_entry->a;

Surely d needs to be propagated as well?

Quoted 2 lines

No it's not necessary. D-bit is not defined in middle level EPT table. Only leaf table entry has D-bit definition.

Ok - so the middle doesn't have a D.

What about the superpage having D set? Surely that needs propagated down to the new shattered leaves?

Quoted 11 lines
Quoted 2 lines

Would it make sense to extend
ept_set_middle_entry() to do all of new_ept setup in one location?

Yes it certainly makes sense to move A-bit propagation into ept_set_middle_entry, but this also requires adding additional original EPT entry pointer to ept_set_middle_entry as parameter. And ept_set_middle_entry is also called by ept_next_level, therefore changing it requires more code change, something like below. While I am fine with both, which solution do you prefer?

+++ b/xen/arch/x86/mm/p2m-ept.c

Review static void ept_p2m_type_to_flags(struct · line 215

Quoted 9 lines
(quoted diff) +2 -1
@@ -208,7 +208,8 @@ static void ept_p2m_type_to_flags(struct
 p2m_domain *p2m, ept_entry_t *entry,
 #define GUEST_TABLE_POD_PAGE    3
 
 /* Fill in middle levels of ept table */
-static int ept_set_middle_entry(struct p2m_domain *p2m, ept_entry_t
 *ept_entry)
+static int ept_set_middle_entry(struct p2m_domain *p2m, ept_entry_t
 *new_entry,
+        ept_entry_t *ori_entry)

const ept_entry_t *old_entry (for consistency with other similar functions, or even just 'new' and 'old' as you are already changing the names)

This looks fine. Being a static function with only two callsites, it is very likely to be inlined by the compiler.

~Andrew

#5 lore raw

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

Quoted 26 lines · Andrew Cooper
Quoted 25 lines · Kai Huang
Quoted 22 lines · Andrew Cooper
Quoted 21 lines · Kai Huang

PML requires A/D bit support so enable it for further use.

---
  xen/arch/x86/hvm/vmx/vmcs.c        | 1 +
  xen/arch/x86/mm/p2m-ept.c          | 8 +++++++-
  xen/include/asm-x86/hvm/vmx/vmcs.h | 4 +++-
  xen/include/asm-x86/hvm/vmx/vmx.h  | 5 ++++-
  4 files changed, 15 insertions(+), 3 deletions(-)
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
index d614638..2f645fe 100644
@@ -103,6 +103,7 @@ static void __init vmx_display_features(void)
      P(cpu_has_vmx_tpr_shadow, "APIC TPR shadow");
      P(cpu_has_vmx_ept, "Extended Page Tables (EPT)");
      P(cpu_has_vmx_vpid, "Virtual-Processor Identifiers (VPID)");
+    P(cpu_has_vmx_ept_ad_bit, "EPT A/D bit");
      P(cpu_has_vmx_vnmi, "Virtual NMI");
      P(cpu_has_vmx_msr_bitmap, "MSR direct-access bitmap");
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

xen/arch/x86/mm/p2m-ept.c static int ept_split_super_page(struct · line 234

Quoted 8 lines
xen/arch/x86/hvm/vmx/vmcs.c +0 -0
      P(cpu_has_vmx_unrestricted_guest, "Unrestricted Guest");
xen/arch/x86/mm/p2m-ept.c +0 -0
index c2d7720..8650092 100644
@@ -233,6 +233,9 @@ static int ept_split_super_page(struct
 p2m_domain *p2m, ept_entry_t *ept_entry,
      if ( !ept_set_middle_entry(p2m, &neThanks,

-Kaiw_ept) )

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
xen/arch/x86/mm/p2m-ept.c +0 -0
          return 0;
  +    /* It's better to copy A bit of Middle entry from original

entry */
+ new_ept.a = ept_entry->a;

Quoted 8 lines
Quoted 3 lines
Quoted 1 line

Surely d needs to be propagated as well?

No it's not necessary. D-bit is not defined in middle level EPT table. Only leaf table entry has D-bit definition.

Ok - so the middle doesn't have a D.

What about the superpage having D set? Surely that needs propagated down to the new shattered leaves?

Yes shattered leaves will inherit both A and D bits from the original superpage entry in " *epte = *ept_entry; " statement in below code in ept_split_super_page.

    for ( int i = 0; i < EPT_PAGETABLE_ENTRIES; i++ )
    {
        ept_entry_t *epte = table + i;

        *epte = *ept_entry;
        ......
Quoted 26 lines
Quoted 12 lines
Quoted 3 lines

Would it make sense to extend
ept_set_middle_entry() to do all of new_ept setup in one location?

Yes it certainly makes sense to move A-bit propagation into ept_set_middle_entry, but this also requires adding additional original EPT entry pointer to ept_set_middle_entry as parameter. And ept_set_middle_entry is also called by ept_next_level, therefore changing it requires more code change, something like below. While I am fine with both, which solution do you prefer?

+++ b/xen/arch/x86/mm/p2m-ept.c

Review static void ept_p2m_type_to_flags(struct · line 215

Quoted 9 lines
(quoted diff) +2 -1
@@ -208,7 +208,8 @@ static void ept_p2m_type_to_flags(struct
 p2m_domain *p2m, ept_entry_t *entry,
 #define GUEST_TABLE_POD_PAGE    3
 
 /* Fill in middle levels of ept table */
-static int ept_set_middle_entry(struct p2m_domain *p2m, ept_entry_t
 *ept_entry)
+static int ept_set_middle_entry(struct p2m_domain *p2m, ept_entry_t
 *new_entry,
+        ept_entry_t *ori_entry)

const ept_entry_t *old_entry (for consistency with other similar functions, or even just 'new' and 'old' as you are already changing the names)

Quoted 2 lines

This looks fine. Being a static function with only two callsites, it is very likely to be inlined by the compiler.

Sure I will do in this way.

Quoted 7 lines

~Andrew

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

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

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

Quoted 51 lines · Kai Huang
Quoted 25 lines · Andrew Cooper
Quoted 24 lines · Kai Huang
Quoted 22 lines · Andrew Cooper
Quoted 21 lines · Kai Huang

PML requires A/D bit support so enable it for further use.

---
  xen/arch/x86/hvm/vmx/vmcs.c        | 1 +
  xen/arch/x86/mm/p2m-ept.c          | 8 +++++++-
  xen/include/asm-x86/hvm/vmx/vmcs.h | 4 +++-
  xen/include/asm-x86/hvm/vmx/vmx.h  | 5 ++++-
  4 files changed, 15 insertions(+), 3 deletions(-)
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
index d614638..2f645fe 100644
@@ -103,6 +103,7 @@ static void __init vmx_display_features(void)
      P(cpu_has_vmx_tpr_shadow, "APIC TPR shadow");
      P(cpu_has_vmx_ept, "Extended Page Tables (EPT)");
      P(cpu_has_vmx_vpid, "Virtual-Processor Identifiers (VPID)");
+    P(cpu_has_vmx_ept_ad_bit, "EPT A/D bit");
      P(cpu_has_vmx_vnmi, "Virtual NMI");
      P(cpu_has_vmx_msr_bitmap, "MSR direct-access bitmap");
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

xen/arch/x86/mm/p2m-ept.c static int ept_split_super_page(struct · line 234

Quoted 8 lines
xen/arch/x86/hvm/vmx/vmcs.c +0 -0
      P(cpu_has_vmx_unrestricted_guest, "Unrestricted Guest");
xen/arch/x86/mm/p2m-ept.c +0 -0
index c2d7720..8650092 100644
@@ -233,6 +233,9 @@ static int ept_split_super_page(struct
 p2m_domain *p2m, ept_entry_t *ept_entry,
      if ( !ept_set_middle_entry(p2m, &neThanks,

-Kaiw_ept) )

Quoted 11 lines
Quoted 7 lines
Quoted 5 lines
Quoted 4 lines
xen/arch/x86/mm/p2m-ept.c +0 -0
          return 0;
  +    /* It's better to copy A bit of Middle entry from original

entry */
+ new_ept.a = ept_entry->a;

Surely d needs to be propagated as well?

No it's not necessary. D-bit is not defined in middle level EPT table. Only leaf table entry has D-bit definition.

Ok - so the middle doesn't have a D.

What about the superpage having D set? Surely that needs propagated down to the new shattered leaves?

Yes shattered leaves will inherit both A and D bits from the original superpage entry in " *epte = *ept_entry; " statement in below code in ept_split_super_page.

Quoted 6 lines
    for ( int i = 0; i < EPT_PAGETABLE_ENTRIES; i++ )
    {
        ept_entry_t *epte = table + i;

        *epte = *ept_entry;
        ......

So you are. Apologies for the confusion.

~Andrew

author
#7 lore raw

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

In reply to Andrew Cooper
Quoted 53 lines · Andrew Cooper
Quoted 27 lines · Kai Huang

PML requires A/D bit support so enable it for further use.

---
  xen/arch/x86/hvm/vmx/vmcs.c        | 1 +
  xen/arch/x86/mm/p2m-ept.c          | 8 +++++++-
  xen/include/asm-x86/hvm/vmx/vmcs.h | 4 +++-
  xen/include/asm-x86/hvm/vmx/vmx.h  | 5 ++++-
  4 files changed, 15 insertions(+), 3 deletions(-)
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
index d614638..2f645fe 100644
@@ -103,6 +103,7 @@ static void __init vmx_display_features(void)
      P(cpu_has_vmx_tpr_shadow, "APIC TPR shadow");
      P(cpu_has_vmx_ept, "Extended Page Tables (EPT)");
      P(cpu_has_vmx_vpid, "Virtual-Processor Identifiers (VPID)");
+    P(cpu_has_vmx_ept_ad_bit, "EPT A/D bit");
      P(cpu_has_vmx_vnmi, "Virtual NMI");
      P(cpu_has_vmx_msr_bitmap, "MSR direct-access bitmap");
      P(cpu_has_vmx_unrestricted_guest, "Unrestricted Guest");
xen/arch/x86/mm/p2m-ept.c +0 -0
index c2d7720..8650092 100644

xen/arch/x86/mm/p2m-ept.c static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry, · line 237

Quoted 5 lines
xen/arch/x86/mm/p2m-ept.c +2 -0
@@ -233,6 +233,9 @@ static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry,
      if ( !ept_set_middle_entry(p2m, &new_ept) )
          return 0;
 
+    /* It's better to copy A bit of Middle entry from original entry */
+    new_ept.a = ept_entry->a;

Surely d needs to be propagated as well? Would it make sense to extend ept_set_middle_entry() to do all of new_ept setup in one location?

Quoted 17 lines
xen/arch/x86/mm/p2m-ept.c +2 -1
+
      table = map_domain_page(new_ept.mfn);
      trunk = 1UL << ((level - 1) * EPT_TABLE_ORDER);
 
@@ -244,7 +247,7 @@ 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);
+        /* A/D bits are inherited from superpage */
          ASSERT(!epte->avail3);
 
          ept_p2m_type_to_flags(epte, epte->sa_p2mt, epte->access);
@@ -1071,6 +1074,9 @@ 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;
 
Quoted 5 lines

xen/arch/x86/mm/p2m-ept.c int ept_p2m_init(struct p2m_domain *p2m) · line 1078

Quoted 2 lines
xen/arch/x86/mm/p2m-ept.c +2 -0
+    /* Enable EPT A/D bit if it's supported by hardware */
+    ept->ept_ad = cpu_has_vmx_ept_ad_bit ? 1 : 0;

This will incur overhead on all EPT operations. It should only be enabled if pml is going to be in use. (I think you need reverse patches 1 and 2 in the series, and gate on pml_enable here)

Hi Andrew,

I'd like to also put patch 3 (PML feature detection) before this patch, as it's better to use cpu_has_vmx_pml to gate A/D bit enabling here. Theoretically simple "pml_enable = 1" here doesn't guarantee cpu_has_vmx_pml to be true, as PML may be turned off during vmx_init_vmcs_config.

And in this case I also want to delete below code, as if PML is not enabled, below code will print but actually EPT A/D bits is not enabled in hardware.

   P(cpu_has_vmx_ept_ad, "EPT A/D bit");

Thanks,
-Kai

Quoted 62 lines
Quoted 9 lines
xen/arch/x86/mm/p2m-ept.c +1 -0
+
      if ( !zalloc_cpumask_var(&ept->synced_mask) )
          return -ENOMEM;
 
xen/include/asm-x86/hvm/vmx/vmcs.h +0 -0
index 6fce6aa..4528346 100644

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

Quoted 7 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +2 -1
@@ -62,7 +62,8 @@ struct ept_data {
      struct {
              u64 ept_mt :3,
                  ept_wl :3,
-                rsvd   :6,
+                ept_ad :1,
+                rsvd   :5,
                  asr    :52;

While you are making this change, can you add comments similar to ept_entry_t describing the bits?

Quoted 25 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +1 -0
          };
          u64 eptp;
@@ -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_SUPPORT                  0x00200000
 
  #define VMX_MISC_VMWRITE_ALL                    0x20000000
 
xen/include/asm-x86/hvm/vmx/vmx.h +2 -1
index 91c5e18..9afd351 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 */

xen/include/asm-x86/hvm/vmx/vmx.h extern uint8_t posted_intr_vector; · line 266

Quoted 5 lines
xen/include/asm-x86/hvm/vmx/vmx.h +2 -0
@@ -261,6 +262,8 @@ extern uint8_t posted_intr_vector;
      (vmx_ept_vpid_cap & VMX_EPT_SUPERPAGE_2MB)
  #define cpu_has_vmx_ept_invept_single_context   \
      (vmx_ept_vpid_cap & VMX_EPT_INVEPT_SINGLE_CONTEXT)
+#define cpu_has_vmx_ept_ad_bit                  \
+    (vmx_ept_vpid_cap & VMX_EPT_AD_BIT_SUPPORT)

I think cpu_has_vmx_ept_ad is sufficient, without the _bit suffix making it longer.

~Andrew

xen/include/asm-x86/hvm/vmx/vmx.h extern uint8_t posted_intr_vector; · line 269

Quoted 3 lines
xen/include/asm-x86/hvm/vmx/vmx.h +0 -0
  #define EPT_2MB_SHIFT     16
  #define EPT_1GB_SHIFT     17

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

#8 lore raw

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

Quoted 30 lines · Kai Huang
Quoted 14 lines
Quoted 14 lines

+

      table = map_domain_page(new_ept.mfn);
      trunk = 1UL << ((level - 1) * EPT_TABLE_ORDER);
  @@ -244,7 +247,7 @@ 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);
xen/arch/x86/mm/p2m-ept.c +1 -1
-        ASSERT(!epte->rsvd1);
+        /* A/D bits are inherited from superpage */
          ASSERT(!epte->avail3);
            ept_p2m_type_to_flags(epte, epte->sa_p2mt, epte->access);
@@ -1071,6 +1074,9 @@ int ept_p2m_init(struct p2m_domain *p2m)
Quoted 8 lines
Quoted 5 lines
(quoted diff) +0 -0
      /* set EPT page-walk length, now it's actual walk length - 1,

i.e. 3 */

      ept->ept_wl = 3;

+ /* Enable EPT A/D bit if it's supported by hardware */
+ ept->ept_ad = cpu_has_vmx_ept_ad_bit ? 1 : 0;

This will incur overhead on all EPT operations. It should only be enabled if pml is going to be in use. (I think you need reverse patches 1 and 2 in the series, and gate on pml_enable here)

Hi Andrew,

I'd like to also put patch 3 (PML feature detection) before this patch, as it's better to use cpu_has_vmx_pml to gate A/D bit enabling here. Theoretically simple "pml_enable = 1" here doesn't guarantee cpu_has_vmx_pml to be true, as PML may be turned off during vmx_init_vmcs_config.

Quoted 6 lines

And in this case I also want to delete below code, as if PML is not enabled, below code will print but actually EPT A/D bits is not enabled in hardware.

   P(cpu_has_vmx_ept_ad, "EPT A/D bit");

Sounds sensible.

#9 lore raw

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

In reply to Kai Huang

xen/arch/x86/mm/p2m-ept.c static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry, · line 237

Quoted 6 lines · Kai Huang
xen/arch/x86/mm/p2m-ept.c +2 -0
@@ -233,6 +233,9 @@ static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry,
     if ( !ept_set_middle_entry(p2m, &new_ept) )
         return 0;
 
+    /* It's better to copy A bit of Middle entry from original entry */
+    new_ept.a = ept_entry->a;

Shouldn't this A bit always be set to 1? After all we're not using it for anything, and it doesn't mean the same thing as the A bit in the superpage entry did.

In fact, thinking about that, we should probably be setting _all_ the A bits to 1, even in leaf entries, to avoid the overhead of the MMU having to write them later.

Cheers,

Tim.

author
#10 lore raw

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

Quoted 10 lines · Tim Deegan

xen/arch/x86/mm/p2m-ept.c static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry, · line 237

Quoted 6 lines · Kai Huang
xen/arch/x86/mm/p2m-ept.c +2 -0
@@ -233,6 +233,9 @@ static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry,
      if ( !ept_set_middle_entry(p2m, &new_ept) )
          return 0;
 
+    /* It's better to copy A bit of Middle entry from original entry */
+    new_ept.a = ept_entry->a;

Shouldn't this A bit always be set to 1? After all we're not using it for anything, and it doesn't mean the same thing as the A bit in the superpage entry did.

This is the statement in Intel's SDM:

"Whenever the processor uses an EPT paging-structure entry as part of guest-physical-address translation, it sets the accessed flag in that entry (if it is not already set)".

In my understanding, once the guest-physical-address is used by processor, all EPT entries used for that translation will have their A bits set, from top level entry to leaf entry, therefore A bits of EPT entries for one translation should be consistent, in which case looks it's reasonable to inherit A bit from superpage's leaf entry to middle entry of new shattered 4K pages.

Do I have misunderstanding on this?

But this is really not an important issue, and we can safely set A bit of middle entry to 1. It is Yang's idea that it's better to inherit it.

Yang, would you comment here?

Quoted 4 lines

In fact, thinking about that, we should probably be setting _all_ the A bits to 1, even in leaf entries, to avoid the overhead of the MMU having to write them later.

I suppose you mean A bits of leaf entries of new shattered 4K pages? Yes we can, but looks it's more reasonable to inherit according to original A bit of super page. But as I said, I don't think A bit matters a lot, so I am OK with both. Maybe others can provide some comments here?

Thanks,
-Kai

Quoted 4 lines

Cheers,

Tim.

#11 lore raw

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

Quoted 6 lines · Kai Huang
Quoted 3 lines

In fact, thinking about that, we should probably be setting _all_ the A bits to 1, even in leaf entries, to avoid the overhead of the MMU having to write them later.

I suppose you mean A bits of leaf entries of new shattered 4K pages? Yes we can, but looks it's more reasonable to inherit according to original A bit of super page.

Yes, inheriting is best, but we should have already set the A bit of the superpage to 1 as well, for the same reasons. IOW we should set every A bit in the whole system to 1 all the time.

BTW, this is what we do with A/D bits in normal pagetables in Xen too -- the default is to set them all the time, so the MMU doesn't have to fix them up later.

Cheers,

Tim.

author
#12 lore raw

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

Quoted 7 lines · Tim Deegan
Quoted 6 lines · Kai Huang
Quoted 3 lines

In fact, thinking about that, we should probably be setting _all_ the A bits to 1, even in leaf entries, to avoid the overhead of the MMU having to write them later.

I suppose you mean A bits of leaf entries of new shattered 4K pages? Yes we can, but looks it's more reasonable to inherit according to original A bit of super page.

Quoted 7 lines

Yes, inheriting is best, but we should have already set the A bit of the superpage to 1 as well, for the same reasons. IOW we should set every A bit in the whole system to 1 all the time.

BTW, this is what we do with A/D bits in normal pagetables in Xen too -- the default is to set them all the time, so the MMU doesn't have to fix them up later.

Sure then we can set all A bit to 1, which can be done by setting A bit properly in ept_p2m_type_to_flags I think.

What does normal pagetables mean here? I don't think you mean shadow page table, as shadow page table needs to sync A/D bits with guest table, right?

Thanks,
-Kai

Quoted 4 lines

Cheers,

Tim.

#13 lore raw

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

Quoted 17 lines · Kai Huang
Quoted 7 lines · Tim Deegan
Quoted 6 lines · Kai Huang
Quoted 3 lines

In fact, thinking about that, we should probably be setting _all_ the A bits to 1, even in leaf entries, to avoid the overhead of the MMU having to write them later.

I suppose you mean A bits of leaf entries of new shattered 4K pages? Yes we can, but looks it's more reasonable to inherit according to original A bit of super page.

Quoted 7 lines

Yes, inheriting is best, but we should have already set the A bit of the superpage to 1 as well, for the same reasons. IOW we should set every A bit in the whole system to 1 all the time.

BTW, this is what we do with A/D bits in normal pagetables in Xen too -- the default is to set them all the time, so the MMU doesn't have to fix them up later.

Quoted 6 lines

Sure then we can set all A bit to 1, which can be done by setting A bit properly in ept_p2m_type_to_flags I think.

What does normal pagetables mean here? I don't think you mean shadow page table, as shadow page table needs to sync A/D bits with guest table, right?

I meant xen's own pagetables, that it maps its own text and data with. But IIRC we also set the Accessed bit in all shadow pagetable entries -- fixing up the A/D bits in the guest PTEs happens in the pagefault handler.

Tim.

#14 lore raw

Re: [PATCH 01/10] VMX: Enable EPT A/D bit support

Quoted 21 lines · Tim Deegan
Quoted 20 lines · Kai Huang
Quoted 7 lines · Tim Deegan
Quoted 6 lines · Kai Huang
Quoted 3 lines

In fact, thinking about that, we should probably be setting _all_ the A bits to 1, even in leaf entries, to avoid the overhead of the MMU having to write them later.

I suppose you mean A bits of leaf entries of new shattered 4K pages? Yes we can, but looks it's more reasonable to inherit according to original A bit of super page.

Quoted 7 lines

Yes, inheriting is best, but we should have already set the A bit of the superpage to 1 as well, for the same reasons. IOW we should set every A bit in the whole system to 1 all the time.

BTW, this is what we do with A/D bits in normal pagetables in Xen too -- the default is to set them all the time, so the MMU doesn't have to fix them up later.

Sure then we can set all A bit to 1, which can be done by setting A bit properly in ept_p2m_type_to_flags I think.

Quoted 8 lines
Quoted 3 lines

What does normal pagetables mean here? I don't think you mean shadow page table, as shadow page table needs to sync A/D bits with guest table, right?

I meant xen's own pagetables, that it maps its own text and data with. But IIRC we also set the Accessed bit in all shadow pagetable entries -- fixing up the A/D bits in the guest PTEs happens in the pagefault handler.

Interesting. Thanks for pointing out. I should read that code when I get spare time :)

Thanks,
-Kai

Quoted 7 lines

Tim.

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

Signature · 2 lines
Thanks,
-Kai
author
#15 lore raw

PATCH 2/10 VMX: New parameter to control PML enabling

In reply to Kai Huang

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

---
 xen/arch/x86/hvm/vmx/vmcs.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +32 -0
index 2f645fe..9b20a4b 100644
@@ -50,6 +50,16 @@ boolean_param("unrestricted_guest", opt_unrestricted_guest_enabled);
 static bool_t __read_mostly opt_apicv_enabled = 1;
 boolean_param("apicv", opt_apicv_enabled);
 
+static void parse_ept_param(char *s);
+/*
+ * The 'ept' parameter controls functionalities that depend on, or impact the
+ * EPT mechanism. Optional comma separated value may contain:
+ *
+ *  pml                 Enable PML
+ */
+custom_param("ept", parse_ept_param);
+static bool_t __read_mostly pml_enable = 0;
+
 /*
  * These two parameters are used to config the controls for Pause-Loop Exiting:
  * ple_gap:    upper bound on the amount of time between two successive
@@ -92,6 +102,28 @@ DEFINE_PER_CPU(bool_t, vmxon);
 static u32 vmcs_revision_id __read_mostly;
 u64 __read_mostly vmx_basic_msr;
 
+/* Copied from parse_iommu_param */
+static void 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") )
+            pml_enable = val;
+
+        s = ss + 1;
+    } while ( ss );
+}
+
 static void __init vmx_display_features(void)
 {
     int printed = 0;
Signature · 1 line
2.1.0
#16 lore raw

Re: [PATCH 02/10] VMX: New parameter to control PML enabling

Quoted 5 lines · Kai Huang

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

Please patch docs/misc/xen-command-line.markdown as well. See the existing "psr" option as a similar example.

Also, as indicated in patch 1, I think patches 1 and 2 need swapping in the series.

Quoted 10 lines
---
 xen/arch/x86/hvm/vmx/vmcs.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +0 -0
index 2f645fe..9b20a4b 100644
@@ -50,6 +50,16 @@ boolean_param("unrestricted_guest", opt_unrestricted_guest_enabled);
 static bool_t __read_mostly opt_apicv_enabled = 1;

xen/arch/x86/hvm/vmx/vmcs.c boolean_param("unrestricted_guest", opt_unrestricted_guest_enabled); · line 60

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +8 -0
 boolean_param("apicv", opt_apicv_enabled);
 
+static void parse_ept_param(char *s);
+/*
+ * The 'ept' parameter controls functionalities that depend on, or impact the
+ * EPT mechanism. Optional comma separated value may contain:
+ *
+ *  pml                 Enable PML
+ */
+custom_param("ept", parse_ept_param);

It is common to put the custom_param() call below parse_ept_param() so you don't need to forward-declare the function. The comment can happily live at the top of parse_ept_param().

xen/arch/x86/hvm/vmx/vmcs.c DEFINE_PER_CPU(bool_t, vmxon); · line 105

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+static bool_t __read_mostly pml_enable = 0;
+
 /*
  * These two parameters are used to config the controls for Pause-Loop Exiting:
  * ple_gap:    upper bound on the amount of time between two successive
@@ -92,6 +102,28 @@ DEFINE_PER_CPU(bool_t, vmxon);
 static u32 vmcs_revision_id __read_mostly;
 u64 __read_mostly vmx_basic_msr;
 
+/* Copied from parse_iommu_param */

Not a useful comment, as it is likely to diverge in the future.

xen/arch/x86/hvm/vmx/vmcs.c DEFINE_PER_CPU(bool_t, vmxon); · line 106

Quoted 1 line
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
+static void parse_ept_param(char *s)

__init

~Andrew

Quoted 23 lines
xen/arch/x86/hvm/vmx/vmcs.c +20 -0
+{
+    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") )
+            pml_enable = val;
+
+        s = ss + 1;
+    } while ( ss );
+}
+
 static void __init vmx_display_features(void)
 {
     int printed = 0;
author
#17 lore raw

Re: [PATCH 02/10] VMX: New parameter to control PML enabling

Quoted 8 lines · Andrew Cooper
Quoted 5 lines · Kai Huang

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

Please patch docs/misc/xen-command-line.markdown as well. See the existing "psr" option as a similar example.

Will do. Thanks for pointing out.

Quoted 3 lines

Also, as indicated in patch 1, I think patches 1 and 2 need swapping in the series.

Sure.

Quoted 13 lines
Quoted 13 lines
---
  xen/arch/x86/hvm/vmx/vmcs.c | 32 ++++++++++++++++++++++++++++++++
  1 file changed, 32 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +0 -0
index 2f645fe..9b20a4b 100644
@@ -50,6 +50,16 @@ boolean_param("unrestricted_guest", opt_unrestricted_guest_enabled);
  static bool_t __read_mostly opt_apicv_enabled = 1;
  boolean_param("apicv", opt_apicv_enabled);
 
Quoted 11 lines

xen/arch/x86/hvm/vmx/vmcs.c boolean_param("unrestricted_guest", opt_unrestricted_guest_enabled); · line 60

Quoted 8 lines
xen/arch/x86/hvm/vmx/vmcs.c +8 -0
+static void parse_ept_param(char *s);
+/*
+ * The 'ept' parameter controls functionalities that depend on, or impact the
+ * EPT mechanism. Optional comma separated value may contain:
+ *
+ *  pml                 Enable PML
+ */
+custom_param("ept", parse_ept_param);

It is common to put the custom_param() call below parse_ept_param() so you don't need to forward-declare the function. The comment can happily live at the top of parse_ept_param().

Will do.

Quoted 10 lines
Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +2 -0
+static bool_t __read_mostly pml_enable = 0;
+
  /*
   * These two parameters are used to config the controls for Pause-Loop Exiting:
   * ple_gap:    upper bound on the amount of time between two successive
@@ -92,6 +102,28 @@ DEFINE_PER_CPU(bool_t, vmxon);
  static u32 vmcs_revision_id __read_mostly;
  u64 __read_mostly vmx_basic_msr;
 
Quoted 2 lines

xen/arch/x86/hvm/vmx/vmcs.c DEFINE_PER_CPU(bool_t, vmxon); · line 105

Quoted 1 line
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
+/* Copied from parse_iommu_param */

Not a useful comment, as it is likely to diverge in the future.

I will move comments for 'custom_param("ept", parse_ept_param)' here, as you suggested above, and this useless comment can be eliminated.

Quoted 3 lines

xen/arch/x86/hvm/vmx/vmcs.c DEFINE_PER_CPU(bool_t, vmxon); · line 106

Quoted 2 lines
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
+static void parse_ept_param(char *s)

__init

Will do.

Thanks,
-Kai

Quoted 31 lines

~Andrew

Quoted 13 lines
xen/arch/x86/hvm/vmx/vmcs.c +13 -0
+{
+    char *ss;
+    int val;
+
+    do {
+        val = !!strncmp(s, "no-", 3);
+        if ( !val )
+            s += 3;
+
+        ss = strchr(s, ',');
+        if ( ss )
+            *ss = '\0';
+

xen/arch/x86/hvm/vmx/vmcs.c DEFINE_PER_CPU(bool_t, vmxon); · line 129

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +7 -0
+        if ( !strcmp(s, "pml") )
+            pml_enable = val;
+
+        s = ss + 1;
+    } while ( ss );
+}
+
  static void __init vmx_display_features(void)
  {
      int printed = 0;

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

author
#18 lore raw

Re: [PATCH 02/10] VMX: New parameter to control PML enabling

In reply to Andrew Cooper
Quoted 24 lines · Andrew Cooper
Quoted 5 lines · Kai Huang

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

Please patch docs/misc/xen-command-line.markdown as well. See the existing "psr" option as a similar example.

Also, as indicated in patch 1, I think patches 1 and 2 need swapping in the series.

Quoted 12 lines
---
  xen/arch/x86/hvm/vmx/vmcs.c | 32 ++++++++++++++++++++++++++++++++
  1 file changed, 32 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +0 -0
index 2f645fe..9b20a4b 100644
@@ -50,6 +50,16 @@ boolean_param("unrestricted_guest", opt_unrestricted_guest_enabled);
  static bool_t __read_mostly opt_apicv_enabled = 1;
  boolean_param("apicv", opt_apicv_enabled);
 
Quoted 11 lines

xen/arch/x86/hvm/vmx/vmcs.c boolean_param("unrestricted_guest", opt_unrestricted_guest_enabled); · line 60

Quoted 8 lines
xen/arch/x86/hvm/vmx/vmcs.c +8 -0
+static void parse_ept_param(char *s);
+/*
+ * The 'ept' parameter controls functionalities that depend on, or impact the
+ * EPT mechanism. Optional comma separated value may contain:
+ *
+ *  pml                 Enable PML
+ */
+custom_param("ept", parse_ept_param);

It is common to put the custom_param() call below parse_ept_param() so you don't need to forward-declare the function. The comment can happily live at the top of parse_ept_param().

Hi Andrew,

Looks it's better to keep parse_ept_param() below custom_param(), as simply moving parse_ept_param() above custom_param() results in below error (I also changed pml_enable to opt_pml_enabled), as it references opt_pml_enabled variable, which is defined below custom_param(). Actually for "iommu=<options>" parameter, parse_iommu_param() was also placed below custom_param().

What do you think?

vmcs.c: In function ‘parse_ept_param’:
vmcs.c:74:13: error: ‘opt_pml_enabled’ undeclared (first use in this function)

             opt_pml_enabled = val;
             ^

vmcs.c:74:13: note: each undeclared identifier is reported only once for each function it appears in vmcs.c: At top level:
vmcs.c:81:29: error: ‘opt_pml_enabled’ defined but not used [-Werror=unused-variable]
static bool_t __read_mostly opt_pml_enabled = 0;

Thanks,
-Kai

Quoted 46 lines

xen/arch/x86/hvm/vmx/vmcs.c DEFINE_PER_CPU(bool_t, vmxon); · line 105

Quoted 11 lines
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+static bool_t __read_mostly pml_enable = 0;
+
  /*
   * These two parameters are used to config the controls for Pause-Loop Exiting:
   * ple_gap:    upper bound on the amount of time between two successive
@@ -92,6 +102,28 @@ DEFINE_PER_CPU(bool_t, vmxon);
  static u32 vmcs_revision_id __read_mostly;
  u64 __read_mostly vmx_basic_msr;
 
+/* Copied from parse_iommu_param */

Not a useful comment, as it is likely to diverge in the future.

xen/arch/x86/hvm/vmx/vmcs.c DEFINE_PER_CPU(bool_t, vmxon); · line 106

Quoted 1 line
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
+static void parse_ept_param(char *s)

__init

~Andrew

Quoted 13 lines
xen/arch/x86/hvm/vmx/vmcs.c +13 -0
+{
+    char *ss;
+    int val;
+
+    do {
+        val = !!strncmp(s, "no-", 3);
+        if ( !val )
+            s += 3;
+
+        ss = strchr(s, ',');
+        if ( ss )
+            *ss = '\0';
+

xen/arch/x86/hvm/vmx/vmcs.c DEFINE_PER_CPU(bool_t, vmxon); · line 129

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +7 -0
+        if ( !strcmp(s, "pml") )
+            pml_enable = val;
+
+        s = ss + 1;
+    } while ( ss );
+}
+
  static void __init vmx_display_features(void)
  {
      int printed = 0;

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

#19 lore raw

Re: [PATCH 02/10] VMX: New parameter to control PML enabling

Quoted 55 lines · Kai Huang
Quoted 30 lines · Andrew Cooper
Quoted 7 lines · Kai Huang

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

Please patch docs/misc/xen-command-line.markdown as well. See the existing "psr" option as a similar example.

Also, as indicated in patch 1, I think patches 1 and 2 need swapping in the series.

Quoted 16 lines
---
  xen/arch/x86/hvm/vmx/vmcs.c | 32 ++++++++++++++++++++++++++++++++
  1 file changed, 32 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +2 -0
index 2f645fe..9b20a4b 100644
@@ -50,6 +50,16 @@ boolean_param("unrestricted_guest",
 opt_unrestricted_guest_enabled);
  static bool_t __read_mostly opt_apicv_enabled = 1;
  boolean_param("apicv", opt_apicv_enabled);
  +static void parse_ept_param(char *s);
+/*
+ * The 'ept' parameter controls functionalities that depend on, or

impact the

Quoted 8 lines
Quoted 5 lines

+ * EPT mechanism. Optional comma separated value may contain:
+ *
+ * pml Enable PML
+ */
+custom_param("ept", parse_ept_param);

It is common to put the custom_param() call below parse_ept_param() so you don't need to forward-declare the function. The comment can happily live at the top of parse_ept_param().

Hi Andrew,

Looks it's better to keep parse_ept_param() below custom_param(), as simply moving parse_ept_param() above custom_param() results in below error (I also changed pml_enable to opt_pml_enabled), as it references opt_pml_enabled variable, which is defined below custom_param(). Actually for "iommu=<options>" parameter, parse_iommu_param() was also placed below custom_param().

What do you think?

vmcs.c: In function ‘parse_ept_param’:
vmcs.c:74:13: error: ‘opt_pml_enabled’ undeclared (first use in this function)

Quoted 8 lines
             opt_pml_enabled = val;
             ^

vmcs.c:74:13: note: each undeclared identifier is reported only once for each function it appears in
vmcs.c: At top level:
vmcs.c:81:29: error: ‘opt_pml_enabled’ defined but not used [-Werror=unused-variable]
static bool_t __read_mostly opt_pml_enabled = 0;

The most concise way of doing this is:

static bool_t __read_mostly opt_pml_enabled = 0;

static void parse_ept_param(char *s)
{
...
}
custom_param("ept", parse_ept_param);

~Andrew

#20 lore raw

Re: [PATCH 02/10] VMX: New parameter to control PML enabling

Quoted 67 lines · Andrew Cooper
Quoted 55 lines · Kai Huang
Quoted 30 lines · Andrew Cooper
Quoted 7 lines · Kai Huang

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

Please patch docs/misc/xen-command-line.markdown as well. See the existing "psr" option as a similar example.

Also, as indicated in patch 1, I think patches 1 and 2 need swapping in the series.

Quoted 16 lines
---
  xen/arch/x86/hvm/vmx/vmcs.c | 32 ++++++++++++++++++++++++++++++++
  1 file changed, 32 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +2 -0
index 2f645fe..9b20a4b 100644
@@ -50,6 +50,16 @@ boolean_param("unrestricted_guest",
 opt_unrestricted_guest_enabled);
  static bool_t __read_mostly opt_apicv_enabled = 1;
  boolean_param("apicv", opt_apicv_enabled);
  +static void parse_ept_param(char *s);
+/*
+ * The 'ept' parameter controls functionalities that depend on, or

impact the

Quoted 8 lines
Quoted 5 lines

+ * EPT mechanism. Optional comma separated value may contain:
+ *
+ * pml Enable PML
+ */
+custom_param("ept", parse_ept_param);

It is common to put the custom_param() call below parse_ept_param() so you don't need to forward-declare the function. The comment can happily live at the top of parse_ept_param().

Hi Andrew,

Looks it's better to keep parse_ept_param() below custom_param(), as simply moving parse_ept_param() above custom_param() results in below error (I also changed pml_enable to opt_pml_enabled), as it references opt_pml_enabled variable, which is defined below custom_param(). Actually for "iommu=<options>" parameter, parse_iommu_param() was also placed below custom_param().

What do you think?

vmcs.c: In function ‘parse_ept_param’:
vmcs.c:74:13: error: ‘opt_pml_enabled’ undeclared (first use in this function)

Quoted 8 lines
             opt_pml_enabled = val;
             ^

vmcs.c:74:13: note: each undeclared identifier is reported only once for each function it appears in
vmcs.c: At top level:
vmcs.c:81:29: error: ‘opt_pml_enabled’ defined but not used [-Werror=unused-variable]
static bool_t __read_mostly opt_pml_enabled = 0;

The most concise way of doing this is:

Quoted 8 lines

static bool_t __read_mostly opt_pml_enabled = 0;

static void parse_ept_param(char *s)
{
...
}
custom_param("ept", parse_ept_param);

Sure. Thanks.

Quoted 6 lines

~Andrew

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

Signature · 7 lines
Thanks,
-Kai

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel
author
#21 lore raw

PATCH 3/10 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        | 18 ++++++++++++++++++
 xen/include/asm-x86/hvm/vmx/vmcs.h |  5 +++++
 xen/include/asm-x86/hvm/vmx/vmx.h  |  1 +
 3 files changed, 24 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +18 -0
index 9b20a4b..2798b0b 100644
@@ -143,6 +143,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 )
@@ -240,6 +241,8 @@ static int vmx_init_vmcs_config(void)
             opt |= SECONDARY_EXEC_ENABLE_VPID;
         if ( opt_unrestricted_guest_enabled )
             opt |= SECONDARY_EXEC_UNRESTRICTED_GUEST;
+        if ( pml_enable )
+            opt |= SECONDARY_EXEC_ENABLE_PML;
 
         /*
          * "APIC Register Virtualization" and "Virtual Interrupt Delivery"
@@ -286,6 +289,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 it anyway.
+	 */
+	if ( !(_vmx_ept_vpid_cap & VMX_EPT_AD_BIT_SUPPORT) )
+		_vmx_secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
     }
 
     if ( _vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT )
@@ -306,6 +317,10 @@ static int vmx_init_vmcs_config(void)
                   SECONDARY_EXEC_UNRESTRICTED_GUEST);
     }
 
+    /* PML cannot be supported if we don't use EPT */
+    if ( !(_vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT) )
+        _vmx_secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
+
     if ( (_vmx_secondary_exec_control & SECONDARY_EXEC_PAUSE_LOOP_EXITING) &&
           ple_gap == 0 )
     {
@@ -1041,6 +1056,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 +5 -0
index 4528346..47b4df2 100644
@@ -216,6 +216,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
@@ -276,6 +277,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
 
@@ -320,6 +323,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,
@@ -333,6 +337,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 9afd351..c0e352d 100644
@@ -186,6 +186,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
#22 lore raw

Re: [PATCH 03/10] VMX: Add PML definition and feature detection.

Quoted 24 lines · 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        | 18 ++++++++++++++++++
 xen/include/asm-x86/hvm/vmx/vmcs.h |  5 +++++
 xen/include/asm-x86/hvm/vmx/vmx.h  |  1 +
 3 files changed, 24 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
index 9b20a4b..2798b0b 100644
@@ -143,6 +143,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 )

xen/arch/x86/hvm/vmx/vmcs.c static int vmx_init_vmcs_config(void) · line 244

Quoted 4 lines
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
@@ -240,6 +241,8 @@ static int vmx_init_vmcs_config(void)
             opt |= SECONDARY_EXEC_ENABLE_VPID;
         if ( opt_unrestricted_guest_enabled )
             opt |= SECONDARY_EXEC_UNRESTRICTED_GUEST;
+        if ( pml_enable )

This should be named opt_pml_enable in patch 1 or 2 to identify that it is a command line option.

Quoted 20 lines
xen/arch/x86/hvm/vmx/vmcs.c +9 -0
+            opt |= SECONDARY_EXEC_ENABLE_PML;
 
         /*
          * "APIC Register Virtualization" and "Virtual Interrupt Delivery"
@@ -286,6 +289,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 it anyway.
+	 */
+	if ( !(_vmx_ept_vpid_cap & VMX_EPT_AD_BIT_SUPPORT) )
+		_vmx_secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
     }
 
     if ( _vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT )

xen/arch/x86/hvm/vmx/vmcs.c static int vmx_init_vmcs_config(void) · line 323

Quoted 7 lines
xen/arch/x86/hvm/vmx/vmcs.c +4 -0
@@ -306,6 +317,10 @@ static int vmx_init_vmcs_config(void)
                   SECONDARY_EXEC_UNRESTRICTED_GUEST);
     }
 
+    /* PML cannot be supported if we don't use EPT */
+    if ( !(_vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT) )
+        _vmx_secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
+

Somewhere in here you should clear pml_enable if hardware doesn't support it.

~Andrew

Quoted 62 lines
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
     if ( (_vmx_secondary_exec_control & SECONDARY_EXEC_PAUSE_LOOP_EXITING) &&
           ple_gap == 0 )
     {
@@ -1041,6 +1056,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 +5 -0
index 4528346..47b4df2 100644
@@ -216,6 +216,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
@@ -276,6 +277,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
 
@@ -320,6 +323,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,
@@ -333,6 +337,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 9afd351..c0e352d 100644
@@ -186,6 +186,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
author
#23 lore raw

Re: [PATCH 03/10] VMX: Add PML definition and feature detection.

Quoted 23 lines · Andrew Cooper
Quoted 22 lines · 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        | 18 ++++++++++++++++++
  xen/include/asm-x86/hvm/vmx/vmcs.h |  5 +++++
  xen/include/asm-x86/hvm/vmx/vmx.h  |  1 +
  3 files changed, 24 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
index 9b20a4b..2798b0b 100644
@@ -143,6 +143,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
 
Quoted 8 lines

xen/arch/x86/hvm/vmx/vmcs.c static int vmx_init_vmcs_config(void) · line 244

Quoted 6 lines
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
      if ( !printed )
@@ -240,6 +241,8 @@ static int vmx_init_vmcs_config(void)
              opt |= SECONDARY_EXEC_ENABLE_VPID;
          if ( opt_unrestricted_guest_enabled )
              opt |= SECONDARY_EXEC_UNRESTRICTED_GUEST;
+        if ( pml_enable )

This should be named opt_pml_enable in patch 1 or 2 to identify that it is a command line option.

Sure.

Quoted 24 lines
Quoted 24 lines
xen/arch/x86/hvm/vmx/vmcs.c +9 -0
+            opt |= SECONDARY_EXEC_ENABLE_PML;
 
          /*
           * "APIC Register Virtualization" and "Virtual Interrupt Delivery"
@@ -286,6 +289,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 it anyway.
+	 */
+	if ( !(_vmx_ept_vpid_cap & VMX_EPT_AD_BIT_SUPPORT) )
+		_vmx_secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
      }
 
      if ( _vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT )
@@ -306,6 +317,10 @@ static int vmx_init_vmcs_config(void)
                    SECONDARY_EXEC_UNRESTRICTED_GUEST);
      }
 
Quoted 6 lines

xen/arch/x86/hvm/vmx/vmcs.c static int vmx_init_vmcs_config(void) · line 323

Quoted 4 lines
xen/arch/x86/hvm/vmx/vmcs.c +4 -0
+    /* PML cannot be supported if we don't use EPT */
+    if ( !(_vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT) )
+        _vmx_secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
+

Somewhere in here you should clear pml_enable if hardware doesn't support it.

Will do. Thanks for catching.

Thanks,
-Kai

Quoted 70 lines

~Andrew

Quoted 55 lines
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
      if ( (_vmx_secondary_exec_control & SECONDARY_EXEC_PAUSE_LOOP_EXITING) &&
            ple_gap == 0 )
      {
@@ -1041,6 +1056,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 +5 -0
index 4528346..47b4df2 100644
@@ -216,6 +216,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
@@ -276,6 +277,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
 
@@ -320,6 +323,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,
@@ -333,6 +337,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 +0 -0
index 9afd351..c0e352d 100644

xen/include/asm-x86/hvm/vmx/vmx.h static inline unsigned long pi_get_pir(struct pi_desc *pi_desc, int group) · line 192

Quoted 7 lines
xen/include/asm-x86/hvm/vmx/vmx.h +1 -0
@@ -186,6 +186,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

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

author
#24 lore raw

PATCH 4/10 VMX: 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 47b4df2..8cc1122 100644
@@ -71,8 +71,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 {
@@ -143,6 +147,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 PML_ENTITY_NUM      512
+    struct page_info	*pml_pg;
 };
 
 int vmx_create_vmcs(struct vcpu *v);
Signature · 1 line
2.1.0
#25 lore raw

Re: [PATCH 04/10] VMX: New data structure member to support PML

Quoted 31 lines · 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 +4 -0
index 47b4df2..8cc1122 100644
@@ -71,8 +71,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 5 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +2 -0
@@ -143,6 +147,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 PML_ENTITY_NUM      512

This is the number of pml entries, not entities. NR_PML_ENTRIES perhaps?

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

Quoted 1 line
xen/include/asm-x86/hvm/vmx/vmcs.h +1 -0
+    struct page_info	*pml_pg;

Please align the fields vertically like vmwrite_bitmap.

~Andrew

Quoted 3 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +0 -0
 };
 
 int vmx_create_vmcs(struct vcpu *v);
author
#26 lore raw

Re: [PATCH 04/10] VMX: New data structure member to support PML

Quoted 30 lines · Andrew Cooper
Quoted 29 lines · 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 +4 -0
index 47b4df2..8cc1122 100644
@@ -71,8 +71,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 8 lines

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

Quoted 7 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +2 -0
  struct pi_desc {
@@ -143,6 +147,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 PML_ENTITY_NUM      512

This is the number of pml entries, not entities. NR_PML_ENTRIES perhaps?

Yours is better indeed. Will do.

Quoted 3 lines

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

Quoted 2 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +1 -0
+    struct page_info	*pml_pg;

Please align the fields vertically like vmwrite_bitmap.

Sure.

Thanks,
-Kai

Quoted 11 lines

~Andrew

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

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

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

author
#27 lore raw

PATCH 5/10 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        | 190 +++++++++++++++++++++++++++++++++++++
 xen/include/asm-x86/hvm/vmx/vmcs.h |   9 ++
 2 files changed, 199 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +190 -0
index 2798b0b..17cbef4 100644
@@ -1326,6 +1326,196 @@ void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector)
                 &v->arch.hvm_vmx.eoi_exitmap_changed);
 }
 
+int vmx_vcpu_pml_enabled(struct vcpu *v)
+{
+    return (v->arch.hvm_vmx.secondary_exec_control &
+            SECONDARY_EXEC_ENABLE_PML) ? 1 : 0;
+}
+
+int vmx_vcpu_enable_pml(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+
+    ASSERT(!vmx_vcpu_pml_enabled(v));
+
+    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, PML_ENTITY_NUM - 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)
+{
+    ASSERT(vmx_vcpu_pml_enabled(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 == (PML_ENTITY_NUM - 1) )
+        goto out;
+
+    pml_buf = map_domain_page(page_to_mfn(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 >= PML_ENTITY_NUM)
+        pml_idx = 0;
+    else
+        pml_idx++;
+
+    for ( ; pml_idx < PML_ENTITY_NUM; pml_idx++ )
+    {
+        struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
+        unsigned long gfn;
+        mfn_t mfn;
+        p2m_type_t t;
+        p2m_access_t a;
+
+        gfn = pml_buf[pml_idx] >> PAGE_SHIFT;
+        mfn = p2m->get_entry(p2m, gfn, &t, &a, 0, NULL);
+        if ( mfn_x(mfn) == INVALID_MFN )
+        {
+            /*
+             * Either EPT table entry for mapping the GFN has been destroyed, or
+             * there's something wrong with hardware behavior, in both cases we
+             * should report a warning.
+             */
+            dprintk(XENLOG_WARNING, "PML: vcpu %d: invalid GPA 0x%lx logged\n",
+                    v->vcpu_id, pml_buf[pml_idx]);
+            continue;
+        }
+
+        /*
+         * 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_dirty(v->domain, mfn_x(mfn));
+    }
+
+    unmap_domain_page(pml_buf);
+
+    /* Reset PML index */
+    __vmwrite(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+
+out:
+    vmx_vmcs_exit(v);
+}
+
+int vmx_domain_pml_enabled(struct domain *d)
+{
+    return (d->arch.hvm_domain.vmx.status & VMX_DOMAIN_PML_ENABLED) ? 1 : 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.
+ */
+int vmx_domain_enable_pml(struct domain *d)
+{
+    struct vcpu *v;
+
+    ASSERT(!vmx_domain_pml_enabled(d));
+
+    for_each_vcpu( d, v )
+    {
+        if ( vmx_vcpu_enable_pml(v) )
+            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 -EINVAL;
+}
+
+/*
+ * 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(vmx_domain_pml_enabled(d));
+
+    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(vmx_domain_pml_enabled(d));
+
+    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 8cc1122..939d097 100644
@@ -499,6 +499,15 @@ static inline int vmx_add_host_load_msr(u32 msr)
 
 DECLARE_PER_CPU(bool_t, vmxon);
 
+int vmx_vcpu_pml_enabled(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);
+int vmx_domain_pml_enabled(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
#28 lore raw

Re: [PATCH 05/10] VMX: add help functions to support PML

Quoted 14 lines · 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        | 190 +++++++++++++++++++++++++++++++++++++
 xen/include/asm-x86/hvm/vmx/vmcs.h |   9 ++
 2 files changed, 199 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +0 -0
index 2798b0b..17cbef4 100644

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

Quoted 4 lines
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
@@ -1326,6 +1326,196 @@ void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector)
                 &v->arch.hvm_vmx.eoi_exitmap_changed);
 }
 
+int vmx_vcpu_pml_enabled(struct vcpu *v)

bool_t vmx_vcpu_pml_enabled(const struct vcpu *v)

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

Quoted 3 lines
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+{
+    return (v->arch.hvm_vmx.secondary_exec_control &
+            SECONDARY_EXEC_ENABLE_PML) ? 1 : 0;

This would be slightly shorter as !!(v->arch.hvm_vmx.secondary_exec_control & SECONDARY_EXEC_ENABLE_PML)

Quoted 11 lines
xen/arch/x86/hvm/vmx/vmcs.c +11 -0
+}
+
+int vmx_vcpu_enable_pml(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+
+    ASSERT(!vmx_vcpu_pml_enabled(v));
+
+    v->arch.hvm_vmx.pml_pg = d->arch.paging.alloc_page(d);
+    if ( !v->arch.hvm_vmx.pml_pg )
+        return -ENOMEM;

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

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+
+    vmx_vmcs_enter(v);
+
+    __vmwrite(PML_ADDRESS, page_to_mfn(v->arch.hvm_vmx.pml_pg) << PAGE_SHIFT);
+    __vmwrite(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+
+    v->arch.hvm_vmx.secondary_exec_control |= SECONDARY_EXEC_ENABLE_PML;
+
+    __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+            v->arch.hvm_vmx.secondary_exec_control);

Alignment.

Quoted 28 lines
xen/arch/x86/hvm/vmx/vmcs.c +28 -0
+
+    vmx_vmcs_exit(v);
+
+    return 0;
+}
+
+void vmx_vcpu_disable_pml(struct vcpu *v)
+{
+    ASSERT(vmx_vcpu_pml_enabled(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));

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

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);
+
+    /* Do nothing if PML buffer is empty */
+    if ( pml_idx == (PML_ENTITY_NUM - 1) )
+        goto out;
+
+    pml_buf = map_domain_page(page_to_mfn(v->arch.hvm_vmx.pml_pg));

__map_domain_page() is a wrapper which takes a struct page_info

Quoted 4 lines
xen/arch/x86/hvm/vmx/vmcs.c +4 -0
+
+    /*
+     * 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 1405

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+     * entity.
+     */
+    if (pml_idx >= PML_ENTITY_NUM)
+        pml_idx = 0;
+    else
+        pml_idx++;
+
+    for ( ; pml_idx < PML_ENTITY_NUM; pml_idx++ )
+    {
+        struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);

This p2m_get_host_p2m() call should be hoisted out of the loop.

Quoted 6 lines
xen/arch/x86/hvm/vmx/vmcs.c +6 -0
+        unsigned long gfn;
+        mfn_t mfn;
+        p2m_type_t t;
+        p2m_access_t a;
+
+        gfn = pml_buf[pml_idx] >> PAGE_SHIFT;

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

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+        mfn = p2m->get_entry(p2m, gfn, &t, &a, 0, NULL);
+        if ( mfn_x(mfn) == INVALID_MFN )
+        {
+            /*
+             * Either EPT table entry for mapping the GFN has been destroyed, or
+             * there's something wrong with hardware behavior, in both cases we
+             * should report a warning.
+             */
+            dprintk(XENLOG_WARNING, "PML: vcpu %d: invalid GPA 0x%lx logged\n",
+                    v->vcpu_id, pml_buf[pml_idx]);

It would be shorter to log gfn rather than gpa.

Quoted 14 lines
xen/arch/x86/hvm/vmx/vmcs.c +14 -0
+            continue;
+        }
+
+        /*
+         * 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_dirty(v->domain, mfn_x(mfn));
+    }
+

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

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+    unmap_domain_page(pml_buf);
+
+    /* Reset PML index */
+    __vmwrite(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+
+out:
+    vmx_vmcs_exit(v);
+}
+
+int vmx_domain_pml_enabled(struct domain *d)

bool_t and const as per vcpu variant.

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

Quoted 7 lines
xen/arch/x86/hvm/vmx/vmcs.c +7 -0
+{
+    return (d->arch.hvm_domain.vmx.status & VMX_DOMAIN_PML_ENABLED) ? 1 : 0;
+}
+
+/*
+ * This function enables PML for particular domain. It should be called when
+ * domain is paused.

In which case assert that the domain is paused, or call domain_pause() yourself to take an extra pause refcount.

Quoted 5 lines
xen/arch/x86/hvm/vmx/vmcs.c +5 -0
+ *
+ * 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 void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1467

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+int vmx_domain_enable_pml(struct domain *d)
+{
+    struct vcpu *v;
+
+    ASSERT(!vmx_domain_pml_enabled(d));
+
+    for_each_vcpu( d, v )
+    {
+        if ( vmx_vcpu_enable_pml(v) )
+            goto error;

Please catch the actual rc from vmx_vcpu_enable_pml() and propagate out of this function, rather than clobbering -ENOMEM with -EINVAL.

Also, per Xen style, you can drop the braces.

~Andrew

Quoted 74 lines
xen/arch/x86/hvm/vmx/vmcs.c +51 -0
+    }
+
+    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 -EINVAL;
+}
+
+/*
+ * 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(vmx_domain_pml_enabled(d));
+
+    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(vmx_domain_pml_enabled(d));
+
+    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 8cc1122..939d097 100644
@@ -499,6 +499,15 @@ static inline int vmx_add_host_load_msr(u32 msr)
 
 DECLARE_PER_CPU(bool_t, vmxon);
 
+int vmx_vcpu_pml_enabled(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);
+int vmx_domain_pml_enabled(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__ */
 
 /*
author
#29 lore raw

Re: [PATCH 05/10] VMX: add help functions to support PML

Quoted 18 lines · Andrew Cooper
Quoted 17 lines · 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        | 190 +++++++++++++++++++++++++++++++++++++
  xen/include/asm-x86/hvm/vmx/vmcs.h |   9 ++
  2 files changed, 199 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +0 -0
index 2798b0b..17cbef4 100644
@@ -1326,6 +1326,196 @@ void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector)
                  &v->arch.hvm_vmx.eoi_exitmap_changed);
  }
 
Quoted 2 lines

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

Quoted 1 line
xen/arch/x86/hvm/vmx/vmcs.c +1 -0
+int vmx_vcpu_pml_enabled(struct vcpu *v)

bool_t vmx_vcpu_pml_enabled(const struct vcpu *v)

Will do.

Quoted 6 lines

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

Quoted 4 lines
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+{
+    return (v->arch.hvm_vmx.secondary_exec_control &
+            SECONDARY_EXEC_ENABLE_PML) ? 1 : 0;

This would be slightly shorter as !!(v->arch.hvm_vmx.secondary_exec_control & SECONDARY_EXEC_ENABLE_PML)

Will do.

Quoted 15 lines
Quoted 15 lines
xen/arch/x86/hvm/vmx/vmcs.c +14 -0
+}
+
+int vmx_vcpu_enable_pml(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+
+    ASSERT(!vmx_vcpu_pml_enabled(v));
+
+    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);
+
Quoted 8 lines

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

Quoted 7 lines
xen/arch/x86/hvm/vmx/vmcs.c +7 -0
+    __vmwrite(PML_ADDRESS, page_to_mfn(v->arch.hvm_vmx.pml_pg) << PAGE_SHIFT);
+    __vmwrite(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+
+    v->arch.hvm_vmx.secondary_exec_control |= SECONDARY_EXEC_ENABLE_PML;
+
+    __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+            v->arch.hvm_vmx.secondary_exec_control);

Alignment.

Do you mean to put 'v->arch.hvm_vmx.secondary_exec_control' to the same line with '__vmwrite(SECONDARY_VM_EXEC_CONTROL,'? In this case the number of characters will be 81.

Quoted 32 lines
Quoted 32 lines
xen/arch/x86/hvm/vmx/vmcs.c +31 -0
+
+    vmx_vmcs_exit(v);
+
+    return 0;
+}
+
+void vmx_vcpu_disable_pml(struct vcpu *v)
+{
+    ASSERT(vmx_vcpu_pml_enabled(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);
+
Quoted 8 lines

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

Quoted 7 lines
xen/arch/x86/hvm/vmx/vmcs.c +7 -0
+    __vmread(GUEST_PML_INDEX, &pml_idx);
+
+    /* Do nothing if PML buffer is empty */
+    if ( pml_idx == (PML_ENTITY_NUM - 1) )
+        goto out;
+
+    pml_buf = map_domain_page(page_to_mfn(v->arch.hvm_vmx.pml_pg));

__map_domain_page() is a wrapper which takes a struct page_info

Will do.

Quoted 16 lines
Quoted 5 lines
xen/arch/x86/hvm/vmx/vmcs.c +4 -0
+
+    /*
+     * 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 1405

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+     * entity.
+     */
+    if (pml_idx >= PML_ENTITY_NUM)
+        pml_idx = 0;
+    else
+        pml_idx++;
+
+    for ( ; pml_idx < PML_ENTITY_NUM; pml_idx++ )
+    {
+        struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);

This p2m_get_host_p2m() call should be hoisted out of the loop.

Will do.

Quoted 17 lines
Quoted 7 lines
xen/arch/x86/hvm/vmx/vmcs.c +6 -0
+        unsigned long gfn;
+        mfn_t mfn;
+        p2m_type_t t;
+        p2m_access_t a;
+
+        gfn = pml_buf[pml_idx] >> PAGE_SHIFT;

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

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+        mfn = p2m->get_entry(p2m, gfn, &t, &a, 0, NULL);
+        if ( mfn_x(mfn) == INVALID_MFN )
+        {
+            /*
+             * Either EPT table entry for mapping the GFN has been destroyed, or
+             * there's something wrong with hardware behavior, in both cases we
+             * should report a warning.
+             */
+            dprintk(XENLOG_WARNING, "PML: vcpu %d: invalid GPA 0x%lx logged\n",
+                    v->vcpu_id, pml_buf[pml_idx]);
Quoted 1 line

It would be shorter to log gfn rather than gpa.

Will do. And I'd also like to add the domain ID in the warning info.

Quoted 18 lines
Quoted 18 lines
xen/arch/x86/hvm/vmx/vmcs.c +17 -0
+            continue;
+        }
+
+        /*
+         * 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_dirty(v->domain, mfn_x(mfn));
+    }
+
+    unmap_domain_page(pml_buf);
+
+    /* Reset PML index */
Quoted 8 lines

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

Quoted 7 lines
xen/arch/x86/hvm/vmx/vmcs.c +7 -0
+    __vmwrite(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+
+out:
+    vmx_vmcs_exit(v);
+}
+
+int vmx_domain_pml_enabled(struct domain *d)

bool_t and const as per vcpu variant.

Will do.

Quoted 10 lines

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

Quoted 8 lines
xen/arch/x86/hvm/vmx/vmcs.c +7 -0
+{
+    return (d->arch.hvm_domain.vmx.status & VMX_DOMAIN_PML_ENABLED) ? 1 : 0;
+}
+
+/*
+ * This function enables PML for particular domain. It should be called when
+ * domain is paused.

In which case assert that the domain is paused, or call domain_pause() yourself to take an extra pause refcount.

Which function should I use to assert domain is paused? I didn't find a function like "domain_paused". Is below good enough?

ASSERT(atomic_read(&d->pause_count));

Quoted 19 lines
Quoted 6 lines
xen/arch/x86/hvm/vmx/vmcs.c +5 -0
+ *
+ * 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 void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1467

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+int vmx_domain_enable_pml(struct domain *d)
+{
+    struct vcpu *v;
+
+    ASSERT(!vmx_domain_pml_enabled(d));
+
+    for_each_vcpu( d, v )
+    {
+        if ( vmx_vcpu_enable_pml(v) )
+            goto error;

Please catch the actual rc from vmx_vcpu_enable_pml() and propagate out of this function, rather than clobbering -ENOMEM with -EINVAL.

Quoted 1 line

Also, per Xen style, you can drop the braces.

Will do. And I'll drop the braces in other functions I added in this patch as well.

Quoted 82 lines

~Andrew

Quoted 64 lines
xen/arch/x86/hvm/vmx/vmcs.c +51 -0
+    }
+
+    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 -EINVAL;
+}
+
+/*
+ * 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(vmx_domain_pml_enabled(d));
+
+    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(vmx_domain_pml_enabled(d));
+
+    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 +2 -0
index 8cc1122..939d097 100644
@@ -499,6 +499,15 @@ static inline int vmx_add_host_load_msr(u32 msr)
 
  DECLARE_PER_CPU(bool_t, vmxon);
 
+int vmx_vcpu_pml_enabled(struct vcpu *v);
+int vmx_vcpu_enable_pml(struct vcpu *v);

xen/include/asm-x86/hvm/vmx/vmcs.h static inline int vmx_add_host_load_msr(u32 msr) · line 513

Quoted 10 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +7 -0
+void vmx_vcpu_disable_pml(struct vcpu *v);
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v);
+int vmx_domain_pml_enabled(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__ */
 
  /*

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

#30 lore raw

Re: [PATCH 05/10] VMX: add help functions to support PML

Quoted 29 lines · Kai Huang
Quoted 18 lines · Andrew Cooper
Quoted 16 lines · Kai Huang
xen/arch/x86/hvm/vmx/vmcs.c +15 -0
+}
+
+int vmx_vcpu_enable_pml(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+
+    ASSERT(!vmx_vcpu_pml_enabled(v));
+
+    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);

Quoted 8 lines

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

Quoted 7 lines
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+    __vmwrite(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+
+    v->arch.hvm_vmx.secondary_exec_control |=

SECONDARY_EXEC_ENABLE_PML;

xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+
+    __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+            v->arch.hvm_vmx.secondary_exec_control);

Alignment.

Quoted 3 lines

Do you mean to put 'v->arch.hvm_vmx.secondary_exec_control' to the same line with '__vmwrite(SECONDARY_VM_EXEC_CONTROL,'? In this case the number of characters will be 81.

Splitting the line is fine. The v should be vertically in line with S from SECONDARY

Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
xen/arch/x86/hvm/vmx/vmcs.c +11 -0
+        unsigned long gfn;
+        mfn_t mfn;
+        p2m_type_t t;
+        p2m_access_t a;
+
+        gfn = pml_buf[pml_idx] >> PAGE_SHIFT;
+        mfn = p2m->get_entry(p2m, gfn, &t, &a, 0, NULL);
+        if ( mfn_x(mfn) == INVALID_MFN )
+        {
+            /*
+             * Either EPT table entry for mapping the GFN has been

destroyed, or
+ * there's something wrong with hardware behavior, in
both cases we

xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+             * should report a warning.
+             */
+            dprintk(XENLOG_WARNING, "PML: vcpu %d: invalid GPA

0x%lx logged\n",
+ v->vcpu_id, pml_buf[pml_idx]);

Quoted 2 lines
Quoted 1 line

It would be shorter to log gfn rather than gpa.

Will do. And I'd also like to add the domain ID in the warning info.

Ah of course - dprintk() doesn't identify current(). Use %pv with v.

Quoted 13 lines
Quoted 13 lines
Quoted 11 lines
(quoted diff) +2 -0
+{
+    return (d->arch.hvm_domain.vmx.status & VMX_DOMAIN_PML_ENABLED)

? 1 : 0;

xen/arch/x86/hvm/vmx/vmcs.c +4 -0
+}
+
+/*
+ * This function enables PML for particular domain. It should be

called when
+ * domain is paused.

In which case assert that the domain is paused, or call domain_pause() yourself to take an extra pause refcount.

Quoted 4 lines

Which function should I use to assert domain is paused? I didn't find a function like "domain_paused". Is below good enough?

ASSERT(atomic_read(&d->pause_count));

Hmm - we indeed don't have an appropriate helper. That ASSERT() will do for now.

~Andrew

#31 lore raw

Re: [PATCH 05/10] VMX: add help functions to support PML

Quoted 30 lines · Andrew Cooper
Quoted 29 lines · Kai Huang
Quoted 26 lines · Andrew Cooper
Quoted 20 lines · Kai Huang
xen/arch/x86/hvm/vmx/vmcs.c +15 -0
+}
+
+int vmx_vcpu_enable_pml(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+
+    ASSERT(!vmx_vcpu_pml_enabled(v));
+
+    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);

xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+    __vmwrite(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+
+    v->arch.hvm_vmx.secondary_exec_control |=

SECONDARY_EXEC_ENABLE_PML;

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

Quoted 3 lines
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+
+    __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+            v->arch.hvm_vmx.secondary_exec_control);

Alignment.

Quoted 6 lines
Quoted 3 lines

Do you mean to put 'v->arch.hvm_vmx.secondary_exec_control' to the same line with '__vmwrite(SECONDARY_VM_EXEC_CONTROL,'? In this case the number of characters will be 81.

Splitting the line is fine. The v should be vertically in line with S from SECONDARY

Oh I got your point. Thanks. Will do.

Quoted 54 lines
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
xen/arch/x86/hvm/vmx/vmcs.c +11 -0
+        unsigned long gfn;
+        mfn_t mfn;
+        p2m_type_t t;
+        p2m_access_t a;
+
+        gfn = pml_buf[pml_idx] >> PAGE_SHIFT;
+        mfn = p2m->get_entry(p2m, gfn, &t, &a, 0, NULL);
+        if ( mfn_x(mfn) == INVALID_MFN )
+        {
+            /*
+             * Either EPT table entry for mapping the GFN has been

destroyed, or
+ * there's something wrong with hardware behavior, in
both cases we

xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+             * should report a warning.
+             */
+            dprintk(XENLOG_WARNING, "PML: vcpu %d: invalid GPA

0x%lx logged\n",
+ v->vcpu_id, pml_buf[pml_idx]);

Quoted 2 lines
Quoted 1 line

It would be shorter to log gfn rather than gpa.

Will do. And I'd also like to add the domain ID in the warning info.

Ah of course - dprintk() doesn't identify current(). Use %pv with v.

Quoted 13 lines
Quoted 13 lines
Quoted 11 lines
(quoted diff) +2 -0
+{
+    return (d->arch.hvm_domain.vmx.status & VMX_DOMAIN_PML_ENABLED)

? 1 : 0;

xen/arch/x86/hvm/vmx/vmcs.c +4 -0
+}
+
+/*
+ * This function enables PML for particular domain. It should be

called when
+ * domain is paused.

In which case assert that the domain is paused, or call domain_pause() yourself to take an extra pause refcount.

Quoted 4 lines

Which function should I use to assert domain is paused? I didn't find a function like "domain_paused". Is below good enough?

ASSERT(atomic_read(&d->pause_count));

Hmm - we indeed don't have an appropriate helper. That ASSERT() will do for now.

~Andrew

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

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

Re: [PATCH 05/10] VMX: add help functions to support PML

In reply to Kai Huang

Hi,

Quoted 27 lines · Kai Huang
xen/arch/x86/hvm/vmx/vmcs.c +27 -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);
+
+    /* Do nothing if PML buffer is empty */
+    if ( pml_idx == (PML_ENTITY_NUM - 1) )
+        goto out;
+
+    pml_buf = map_domain_page(page_to_mfn(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 >= PML_ENTITY_NUM)
+        pml_idx = 0;
+    else
+        pml_idx++;
+

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
+    for ( ; pml_idx < PML_ENTITY_NUM; pml_idx++ )
+    {
+        struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
+        unsigned long gfn;
+        mfn_t mfn;
+        p2m_type_t t;
+        p2m_access_t a;
+
+        gfn = pml_buf[pml_idx] >> PAGE_SHIFT;
+        mfn = p2m->get_entry(p2m, gfn, &t, &a, 0, NULL);

Please don't call p2m->get_entry() directly -- that interface should only be used inside the p2m code. As it happens, I don't think this lookup is correct anyway: the logging only sees races (which are not interesting) or buggy hardware (which is not worth the extra lookup to detect).

So you only need this to get 'mfn' to pass to paging_mark_dirty(). That's also buggy, because there's no locking here to make sure gfn->mfn->gfn ends up in the right place. :(

I think the right thing to do is:

- split paging_park_dirty() into paging_mark_gfn_dirty() (the bulk of the current function) and a paging_mark_dirty() wrapper that does get_gpfn_from_mfn(mfn_x(gmfn)) and calls paging_mark_gfn_dirty().

- call paging_mark_gfn_dirty() from vmx_vcpu_flush_pml_buffer().

That will avoid _two_ p2m lookups in this function. :)

Cheers,

Tim.

author
#33 lore raw

Re: [PATCH 05/10] VMX: add help functions to support PML

Quoted 46 lines · Tim Deegan

Hi,

Quoted 27 lines · Kai Huang
xen/arch/x86/hvm/vmx/vmcs.c +27 -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);
+
+    /* Do nothing if PML buffer is empty */
+    if ( pml_idx == (PML_ENTITY_NUM - 1) )
+        goto out;
+
+    pml_buf = map_domain_page(page_to_mfn(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 >= PML_ENTITY_NUM)
+        pml_idx = 0;
+    else
+        pml_idx++;
+

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
+    for ( ; pml_idx < PML_ENTITY_NUM; pml_idx++ )
+    {
+        struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
+        unsigned long gfn;
+        mfn_t mfn;
+        p2m_type_t t;
+        p2m_access_t a;
+
+        gfn = pml_buf[pml_idx] >> PAGE_SHIFT;
+        mfn = p2m->get_entry(p2m, gfn, &t, &a, 0, NULL);

Please don't call p2m->get_entry() directly -- that interface should only be used inside the p2m code. As it happens, I don't think this lookup is correct anyway: the logging only sees races (which are not interesting) or buggy hardware (which is not worth the extra lookup to detect).

Quoted 1 line

So you only need this to get 'mfn' to pass to paging_mark_dirty().

True.

Quoted 2 lines

That's also buggy, because there's no locking here to make sure gfn->mfn->gfn ends up in the right place. :(

Yes you are right. Thanks for pointing out.

Just curious, looks if I use get_gfn_type_access and put_gfn here, the gfn->mfn->gfn can be guaranteed, and it's safe to use them here, right?

Quoted 10 lines

I think the right thing to do is:

- split paging_park_dirty() into paging_mark_gfn_dirty() (the bulk of the current function) and a paging_mark_dirty() wrapper that does get_gpfn_from_mfn(mfn_x(gmfn)) and calls paging_mark_gfn_dirty().

- call paging_mark_gfn_dirty() from vmx_vcpu_flush_pml_buffer().

That will avoid _two_ p2m lookups in this function. :)

Yours is indeed much better! Will do in this way.

Thanks,
-Kai

Quoted 4 lines

Cheers,

Tim.

#34 lore raw

Re: [PATCH 05/10] VMX: add help functions to support PML

Quoted 11 lines · Kai Huang
Quoted 4 lines · Tim Deegan

Hi,

That's also buggy, because there's no locking here to make sure gfn->mfn->gfn ends up in the right place. :(

Yes you are right. Thanks for pointing out.

Just curious, looks if I use get_gfn_type_access and put_gfn here, the gfn->mfn->gfn can be guaranteed, and it's safe to use them here, right?

Yes, that would be the right way to do it.

In this particular case, there's another race too: the gfn might have been entirely deleted after it's logged by PML but before the entry is processed here. I don't think that's a problem here, because if the gfn's not mapped any more it's not relevant that it's dirty. Just mentioning it out of interest.

Cheers,

Tim.

author
#35 lore raw

Re: [PATCH 05/10] VMX: add help functions to support PML

Quoted 11 lines · Tim Deegan
Quoted 10 lines · Kai Huang
Quoted 4 lines · Tim Deegan

Hi,

That's also buggy, because there's no locking here to make sure gfn->mfn->gfn ends up in the right place. :(

Yes you are right. Thanks for pointing out.

Just curious, looks if I use get_gfn_type_access and put_gfn here, the gfn->mfn->gfn can be guaranteed, and it's safe to use them here, right?

Quoted 7 lines

Yes, that would be the right way to do it.

In this particular case, there's another race too: the gfn might have been entirely deleted after it's logged by PML but before the entry is processed here. I don't think that's a problem here, because if the gfn's not mapped any more it's not relevant that it's dirty. Just mentioning it out of interest.

Agreed. I think the gone gfn should be irrelevant. Thanks.

Thanks,
-Kai

Quoted 4 lines

Cheers,

Tim.

#36 lore raw

Re: [PATCH 05/10] VMX: add help functions to support PML

In reply to Kai Huang

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

Quoted 4 lines · Kai Huang
xen/arch/x86/hvm/vmx/vmcs.c +4 -0
+void vmx_vcpu_disable_pml(struct vcpu *v)
+{
+    ASSERT(vmx_vcpu_pml_enabled(v));
+

I think this function ought to call vmx_vcpu_flush_pml_buffer() before disabling PML. That way we don't need to worry about losing any information if a guest vcpu is reset or offlined during migration.

Cheers,

Tim.

author
#37 lore raw

Re: [PATCH 05/10] VMX: add help functions to support PML

Quoted 8 lines · Tim Deegan

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

Quoted 4 lines · Kai Huang
xen/arch/x86/hvm/vmx/vmcs.c +4 -0
+void vmx_vcpu_disable_pml(struct vcpu *v)
+{
+    ASSERT(vmx_vcpu_pml_enabled(v));
+

I think this function ought to call vmx_vcpu_flush_pml_buffer() before disabling PML. That way we don't need to worry about losing any information if a guest vcpu is reset or offlined during migration.

Good point. Thanks for catching. Will do :)

Thanks,
-Kai

Quoted 4 lines

Cheers,

Tim.

author
#38 lore raw

PATCH 6/10 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 e1c55ce..453bcc5 100644
@@ -3171,6 +3171,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
#39 lore raw

PATCH 7/10 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 | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
xen/arch/x86/hvm/vmx/vmx.c +24 -0
index 453bcc5..fce3aa2 100644
@@ -116,6 +116,30 @@ 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, "Failed to enable PML for vcpu %d\n",
+                    v->vcpu_id);
+            vmx_destroy_vmcs(v);
+            return rc;
+        }
+    }
+
     vpmu_initialise(v);
 
     vmx_install_vlapic_mapping(v);
Signature · 1 line
2.1.0
#40 lore raw

Re: [PATCH 07/10] VMX: handle PML enabling in vmx_vcpu_initialise

Quoted 23 lines · 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 | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
xen/arch/x86/hvm/vmx/vmx.c +6 -0
index 453bcc5..fce3aa2 100644
@@ -116,6 +116,30 @@ 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.
+     *

xen/arch/x86/hvm/vmx/vmx.c static int vmx_vcpu_initialise(struct vcpu *v) · line 134

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmx.c +10 -0
+     * 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 )

Given the comment here, is the assertion in the top of vmx_vcpu_enable_pml() liable to trip?

xen/arch/x86/hvm/vmx/vmx.c static int vmx_vcpu_initialise(struct vcpu *v) · line 137

Quoted 3 lines
xen/arch/x86/hvm/vmx/vmx.c +3 -0
+        {
+            dprintk(XENLOG_ERR, "Failed to enable PML for vcpu %d\n",
+                    v->vcpu_id);

Please use %pv to identify the domain as well as vcpu.

~Andrew

Quoted 8 lines
xen/arch/x86/hvm/vmx/vmx.c +5 -0
+            vmx_destroy_vmcs(v);
+            return rc;
+        }
+    }
+
     vpmu_initialise(v);
 
     vmx_install_vlapic_mapping(v);
author
#41 lore raw

Re: [PATCH 07/10] VMX: handle PML enabling in vmx_vcpu_initialise

Quoted 28 lines · Andrew Cooper
Quoted 27 lines · 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 | 24 ++++++++++++++++++++++++
  1 file changed, 24 insertions(+)
xen/arch/x86/hvm/vmx/vmx.c +10 -0
index 453bcc5..fce3aa2 100644
@@ -116,6 +116,30 @@ 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
Quoted 8 lines

xen/arch/x86/hvm/vmx/vmx.c static int vmx_vcpu_initialise(struct vcpu *v) · line 134

Quoted 6 lines
xen/arch/x86/hvm/vmx/vmx.c +6 -0
+     * 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 )

Given the comment here, is the assertion in the top of vmx_vcpu_enable_pml() liable to trip?

Do you mean below assertion at beginning of vmx_vcpu_enable_pml might not work here?

    ASSERT(!vmx_vcpu_pml_enabled(v));

To me it asserts for this particular vcpu, not the domain, so even in this case the assertion is reasonable and should work fine, shouldn't it?

Quoted 5 lines

xen/arch/x86/hvm/vmx/vmx.c static int vmx_vcpu_initialise(struct vcpu *v) · line 137

Quoted 4 lines
xen/arch/x86/hvm/vmx/vmx.c +3 -0
+        {
+            dprintk(XENLOG_ERR, "Failed to enable PML for vcpu %d\n",
+                    v->vcpu_id);

Please use %pv to identify the domain as well as vcpu.

Sure.

Thanks,
-Kai

Quoted 16 lines

~Andrew

xen/arch/x86/hvm/vmx/vmx.c static int vmx_vcpu_initialise(struct vcpu *v) · line 145

Quoted 8 lines
xen/arch/x86/hvm/vmx/vmx.c +5 -0
+            vmx_destroy_vmcs(v);
+            return rc;
+        }
+    }
+
      vpmu_initialise(v);
 
      vmx_install_vlapic_mapping(v);

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

#42 lore raw

Re: [PATCH 07/10] VMX: handle PML enabling in vmx_vcpu_initialise

Quoted 47 lines · Kai Huang
Quoted 36 lines · Andrew Cooper
Quoted 35 lines · 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 | 24 ++++++++++++++++++++++++
  1 file changed, 24 insertions(+)
xen/arch/x86/hvm/vmx/vmx.c +1 -0
index 453bcc5..fce3aa2 100644
@@ -116,6 +116,30 @@ 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,

xen/arch/x86/hvm/vmx/vmx.c +3 -0
+     * 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

xen/arch/x86/hvm/vmx/vmx.c +2 -0
+     * 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

Quoted 8 lines

xen/arch/x86/hvm/vmx/vmx.c static int vmx_vcpu_initialise(struct vcpu *v) · line 134

Quoted 6 lines

revert PML

xen/arch/x86/hvm/vmx/vmx.c +5 -0
+     * style EPT table to non-PML style EPT table.
+     */
+    if ( vmx_domain_pml_enabled(v->domain) )
+    {
+        if ( (rc = vmx_vcpu_enable_pml(v)) != 0 )

Given the comment here, is the assertion in the top of vmx_vcpu_enable_pml() liable to trip?

Quoted 7 lines

Do you mean below assertion at beginning of vmx_vcpu_enable_pml might not work here?

    ASSERT(!vmx_vcpu_pml_enabled(v));

To me it asserts for this particular vcpu, not the domain, so even in this case the assertion is reasonable and should work fine, shouldn't it?

You are correct. I was getting vcpus and domains mixed up. Sorry for the noise.

~Andrew

author
#43 lore raw

PATCH 8/10 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 | 9 +++++++++
 1 file changed, 9 insertions(+)
xen/arch/x86/hvm/vmx/vmx.c +9 -0
index fce3aa2..75ac44b 100644
@@ -153,6 +153,15 @@ 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.
+     */
+    if ( vmx_vcpu_pml_enabled(v) )
+        vmx_vcpu_disable_pml(v);
     vmx_destroy_vmcs(v);
     vpmu_destroy(v);
     passive_domain_destroy(v);
Signature · 1 line
2.1.0
#44 lore raw

Re: [PATCH 08/10] VMX: disable PML in vmx_vcpu_destroy

Quoted 15 lines · 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 | 9 +++++++++
 1 file changed, 9 insertions(+)
xen/arch/x86/hvm/vmx/vmx.c +0 -0
index fce3aa2..75ac44b 100644
@@ -153,6 +153,15 @@ static int vmx_vcpu_initialise(struct vcpu *v)
 
 static void vmx_vcpu_destroy(struct vcpu *v)

xen/arch/x86/hvm/vmx/vmx.c static int vmx_vcpu_initialise(struct vcpu *v) · line 164

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmx.c +9 -0
 {
+    /*
+     * 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.
+     */
+    if ( vmx_vcpu_pml_enabled(v) )
+        vmx_vcpu_disable_pml(v);

Looking at this and other callers of these enable/disable functions, I think it would be better to make those functions idempotent (i.e. *_{en,dis}able_pml() should just return success if PML is already enabled/disabled). Then you don't need to check in every caller, and there's no risk of a crash if one caller is missing the check.

Cheers,

Tim.

author
#45 lore raw

Re: [PATCH 08/10] VMX: disable PML in vmx_vcpu_destroy

Quoted 15 lines · Tim Deegan
Quoted 14 lines · 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 | 9 +++++++++
  1 file changed, 9 insertions(+)
xen/arch/x86/hvm/vmx/vmx.c +0 -0
index fce3aa2..75ac44b 100644
@@ -153,6 +153,15 @@ static int vmx_vcpu_initialise(struct vcpu *v)
 
Quoted 16 lines

xen/arch/x86/hvm/vmx/vmx.c static int vmx_vcpu_initialise(struct vcpu *v) · line 164

Quoted 11 lines
xen/arch/x86/hvm/vmx/vmx.c +9 -0
  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.
+     */
+    if ( vmx_vcpu_pml_enabled(v) )
+        vmx_vcpu_disable_pml(v);

Looking at this and other callers of these enable/disable functions, I think it would be better to make those functions idempotent (i.e. *_{en,dis}able_pml() should just return success if PML is already enabled/disabled). Then you don't need to check in every caller, and there's no risk of a crash if one caller is missing the check.

Do you mean something like below?

bool_t vmx_vcpu_enable_pml(struct vcpu *v)

{
    if ( vmx_vcpu_pml_enabled(v) )
        return success;
    ......    /* code to enable */

    return success;
error:
    ...
    return failure;
}

This should be also fine. I will do this. But I think vmx_{vcpu|domain}_disable_pml should remain return value of void.

Thanks,
-Kai

Quoted 4 lines

Cheers,

Tim.

#46 lore raw

Re: [PATCH 08/10] VMX: disable PML in vmx_vcpu_destroy

Quoted 22 lines · Kai Huang
Quoted 5 lines · Tim Deegan

Looking at this and other callers of these enable/disable functions, I think it would be better to make those functions idempotent (i.e. *_{en,dis}able_pml() should just return success if PML is already enabled/disabled). Then you don't need to check in every caller, and there's no risk of a crash if one caller is missing the check.

Do you mean something like below?

bool_t vmx_vcpu_enable_pml(struct vcpu *v)

{
     if ( vmx_vcpu_pml_enabled(v) )
         return success;
     ......    /* code to enable */

     return success;
error:
     ...
     return failure;
}
Quoted 2 lines

This should be also fine. I will do this. But I think vmx_{vcpu|domain}_disable_pml should remain return value of void.

Yes, that sounds fine.

Tim.

author
#47 lore raw

PATCH 9/10 log-dirty: Refine common code to support PML

In reply to Kai Huang

This patch adds several new callbacks in paging/hap/p2m layer to support PML.

At paging layer, a new callback is added to log_dirty_domain to flush hardware cached dirty pages to log-dirty radix tree, as in case of 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 before reporting dirty pages to userspace.

At p2m layer, three new callbacks are added to p2m_domain to enable/disable PML and flush PML buffers. PML enabling/disabling callback will be called when switching to log-dirty mode / switching back to normal mode respectively. Flushing PML buffer callback will be called from paging layer when flushing PML buffer manually.

---
 xen/arch/x86/mm/hap/hap.c       | 16 +++++++++++++++-
 xen/arch/x86/mm/p2m.c           | 36 ++++++++++++++++++++++++++++++++++++
 xen/arch/x86/mm/paging.c        | 15 ++++++++++++++-
 xen/arch/x86/mm/shadow/common.c |  2 +-
 xen/include/asm-x86/domain.h    |  1 +
 xen/include/asm-x86/p2m.h       | 11 +++++++++++
 xen/include/asm-x86/paging.h    |  3 ++-
 7 files changed, 80 insertions(+), 4 deletions(-)
xen/arch/x86/mm/hap/hap.c +15 -1
index 4ecb2e2..25f2f58 100644
@@ -135,6 +135,10 @@ int hap_track_dirty_vram(struct domain *d,
 
             domain_pause(d);
 
+            /* flush dirty GFNs potentially cached by hardware */
+            if ( d->arch.paging.log_dirty.flush_cached_dirty )
+                d->arch.paging.log_dirty.flush_cached_dirty(d);
+
             /* get the bitmap */
             paging_log_dirty_range(d, begin_pfn, nr, dirty_bitmap);
 
@@ -190,6 +194,8 @@ static int hap_enable_log_dirty(struct domain *d, bool_t log_global)
     d->arch.paging.mode |= PG_log_dirty;
     paging_unlock(d);
 
+    p2m_enable_hardware_log_dirty(d);
+
     if ( log_global )
     {
         /* set l1e entries of P2M table to be read-only. */
@@ -205,6 +211,8 @@ static int hap_disable_log_dirty(struct domain *d)
     d->arch.paging.mode &= ~PG_log_dirty;
     paging_unlock(d);
 
+    p2m_disable_hardware_log_dirty(d);
+
     /* set l1e entries of P2M table with normal mode */
     p2m_change_entry_type_global(d, p2m_ram_logdirty, p2m_ram_rw);
     return 0;
@@ -217,6 +225,11 @@ static void hap_clean_dirty_bitmap(struct domain *d)
     flush_tlb_mask(d->domain_dirty_cpumask);
 }
 
+static void hap_flush_cached_dirty(struct domain *d)
+{
+    p2m_flush_hardware_cached_dirty(d);
+}
+
 /************************************************/
 /*             HAP SUPPORT FUNCTIONS            */
 /************************************************/
@@ -431,7 +444,8 @@ void hap_domain_init(struct domain *d)
     /* Use HAP logdirty mechanism. */
     paging_log_dirty_init(d, hap_enable_log_dirty,
                           hap_disable_log_dirty,
-                          hap_clean_dirty_bitmap);
+                          hap_clean_dirty_bitmap,
+                          hap_flush_cached_dirty);
 }
 
 /* return 0 for success, -errno for failure */
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 +14 -1
index b54d76a..c2d336a 100644
@@ -411,7 +411,18 @@ static int paging_log_dirty_op(struct domain *d,
     int i4, i3, i2;
 
     if ( !resuming )
+    {
         domain_pause(d);
+
+        /*
+         * Only need to flush when not resuming, as domain was paused in
+         * resuming case therefore it's not possible to have any new dirty
+         * page.
+         */
+        if ( d->arch.paging.log_dirty.flush_cached_dirty )
+            d->arch.paging.log_dirty.flush_cached_dirty(d);
+    }
+
     paging_lock(d);
 
     if ( !d->arch.paging.preempt.dom )
@@ -610,11 +621,13 @@ void paging_log_dirty_init(struct domain *d,
                            int    (*enable_log_dirty)(struct domain *d,
                                                       bool_t log_global),
                            int    (*disable_log_dirty)(struct domain *d),
-                           void   (*clean_dirty_bitmap)(struct domain *d))
+                           void   (*clean_dirty_bitmap)(struct domain *d),
+                           void   (*flush_cached_dirty)(struct domain *d))
 {
     d->arch.paging.log_dirty.enable_log_dirty = enable_log_dirty;
     d->arch.paging.log_dirty.disable_log_dirty = disable_log_dirty;
     d->arch.paging.log_dirty.clean_dirty_bitmap = clean_dirty_bitmap;
+    d->arch.paging.log_dirty.flush_cached_dirty = flush_cached_dirty;
 }
 
 /************************************************/
xen/arch/x86/mm/shadow/common.c +1 -1
index 2e43d6d..f8451e8 100644
@@ -54,7 +54,7 @@ int shadow_domain_init(struct domain *d, unsigned int domcr_flags)
 
     /* Use shadow pagetables for log-dirty support */
     paging_log_dirty_init(d, sh_enable_log_dirty,
-                          sh_disable_log_dirty, sh_clean_dirty_bitmap);
+                          sh_disable_log_dirty, sh_clean_dirty_bitmap, NULL);
 
 #if (SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC)
     d->arch.paging.shadow.oos_active = 0;
xen/include/asm-x86/domain.h +1 -0
index 9cdffa8..0dc90d2 100644
@@ -178,6 +178,7 @@ struct log_dirty_domain {
     int            (*enable_log_dirty   )(struct domain *d, bool_t log_global);
     int            (*disable_log_dirty  )(struct domain *d);
     void           (*clean_dirty_bitmap )(struct domain *d);
+    void           (*flush_cached_dirty )(struct domain *d);
 };
 
 struct paging_domain {
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, 
xen/include/asm-x86/paging.h +2 -1
index 53de715..9fa8d9d 100644
@@ -152,7 +152,8 @@ void paging_log_dirty_init(struct domain *d,
                            int  (*enable_log_dirty)(struct domain *d,
                                                     bool_t log_global),
                            int  (*disable_log_dirty)(struct domain *d),
-                           void (*clean_dirty_bitmap)(struct domain *d));
+                           void (*clean_dirty_bitmap)(struct domain *d),
+                           void (*flush_cached_dirty)(struct domain *d));
 
 /* mark a page as dirty */
 void paging_mark_dirty(struct domain *d, unsigned long guest_mfn);
Signature · 1 line
2.1.0
#48 lore raw

Re: [PATCH 09/10] log-dirty: Refine common code to support PML

Quoted 6 lines · Kai Huang
xen/arch/x86/mm/paging.c +0 -0
@@ -411,7 +411,18 @@ static int paging_log_dirty_op(struct domain *d,
     int i4, i3, i2;
 
     if ( !resuming )

xen/arch/x86/mm/paging.c static int paging_log_dirty_op(struct domain *d, · line 423

Quoted 10 lines
xen/arch/x86/mm/paging.c +9 -0
+    {
         domain_pause(d);
+
+        /*
+         * Only need to flush when not resuming, as domain was paused in
+         * resuming case therefore it's not possible to have any new dirty
+         * page.
+         */
+        if ( d->arch.paging.log_dirty.flush_cached_dirty )
+            d->arch.paging.log_dirty.flush_cached_dirty(d);

I think there are too many layers of indirection here. :) How about:
- don't add a flush_cached_dirty() function to the log_dirty ops.
- just call p2m_flush_hardware_cached_dirty(d) here.

Would that work OK?

Cheers,

Tim.

author
#49 lore raw

Re: [PATCH 09/10] log-dirty: Refine common code to support PML

Quoted 21 lines · Tim Deegan
Quoted 6 lines · Kai Huang
xen/arch/x86/mm/paging.c +0 -0
@@ -411,7 +411,18 @@ static int paging_log_dirty_op(struct domain *d,
      int i4, i3, i2;
 
      if ( !resuming )

xen/arch/x86/mm/paging.c static int paging_log_dirty_op(struct domain *d, · line 423

Quoted 10 lines
xen/arch/x86/mm/paging.c +9 -0
+    {
          domain_pause(d);
+
+        /*
+         * Only need to flush when not resuming, as domain was paused in
+         * resuming case therefore it's not possible to have any new dirty
+         * page.
+         */
+        if ( d->arch.paging.log_dirty.flush_cached_dirty )
+            d->arch.paging.log_dirty.flush_cached_dirty(d);

I think there are too many layers of indirection here. :) How about:
- don't add a flush_cached_dirty() function to the log_dirty ops.
- just call p2m_flush_hardware_cached_dirty(d) here.

Quoted 1 line

Would that work OK?

Thanks for pointing out.

Is it nature to call p2m layer functions in paging.c? If there's no restriction on it, calling p2m_flush_hardware_cached_dirty is more clear, and it should work.

Thanks,
-Kai

Quoted 4 lines

Cheers,

Tim.

#50 lore raw

Re: [PATCH 09/10] log-dirty: Refine common code to support PML

Quoted 24 lines · Kai Huang
Quoted 21 lines · Tim Deegan
Quoted 6 lines · Kai Huang
xen/arch/x86/mm/paging.c +0 -0
@@ -411,7 +411,18 @@ static int paging_log_dirty_op(struct domain *d,
      int i4, i3, i2;
 
      if ( !resuming )

xen/arch/x86/mm/paging.c static int paging_log_dirty_op(struct domain *d, · line 423

Quoted 10 lines
xen/arch/x86/mm/paging.c +9 -0
+    {
          domain_pause(d);
+
+        /*
+         * Only need to flush when not resuming, as domain was paused in
+         * resuming case therefore it's not possible to have any new dirty
+         * page.
+         */
+        if ( d->arch.paging.log_dirty.flush_cached_dirty )
+            d->arch.paging.log_dirty.flush_cached_dirty(d);

I think there are too many layers of indirection here. :) How about:
- don't add a flush_cached_dirty() function to the log_dirty ops.
- just call p2m_flush_hardware_cached_dirty(d) here.

Quoted 6 lines
Quoted 1 line

Would that work OK?

Thanks for pointing out.

Is it nature to call p2m layer functions in paging.c? If there's no restriction on it, calling p2m_flush_hardware_cached_dirty is more clear, and it should work.

Yes, calling public p2m functions directly is OK -- it's the internal function pointers like ->get_entry() that aren't supposed to be called from outside p2m code. I guess that's not terribly clear - maybe it needs some better comments.

Tim.

author
#51 lore raw

Re: [PATCH 09/10] log-dirty: Refine common code to support PML

Quoted 27 lines · Tim Deegan
Quoted 26 lines · Kai Huang
Quoted 21 lines · Tim Deegan
Quoted 6 lines · Kai Huang
xen/arch/x86/mm/paging.c +0 -0
@@ -411,7 +411,18 @@ static int paging_log_dirty_op(struct domain *d,
       int i4, i3, i2;
 
       if ( !resuming )

xen/arch/x86/mm/paging.c static int paging_log_dirty_op(struct domain *d, · line 423

Quoted 10 lines
xen/arch/x86/mm/paging.c +9 -0
+    {
           domain_pause(d);
+
+        /*
+         * Only need to flush when not resuming, as domain was paused in
+         * resuming case therefore it's not possible to have any new dirty
+         * page.
+         */
+        if ( d->arch.paging.log_dirty.flush_cached_dirty )
+            d->arch.paging.log_dirty.flush_cached_dirty(d);

I think there are too many layers of indirection here. :) How about:
- don't add a flush_cached_dirty() function to the log_dirty ops.
- just call p2m_flush_hardware_cached_dirty(d) here.

Quoted 1 line

Would that work OK?

Thanks for pointing out.

Quoted 7 lines
Quoted 3 lines

Is it nature to call p2m layer functions in paging.c? If there's no restriction on it, calling p2m_flush_hardware_cached_dirty is more clear, and it should work.

Yes, calling public p2m functions directly is OK -- it's the internal function pointers like ->get_entry() that aren't supposed to be called from outside p2m code. I guess that's not terribly clear - maybe it needs some better comments.

Pretty clear to me now. Thanks. Will do.:)

Thanks,
-Kai

Quoted 2 lines

Tim.

author
#52 lore raw

PATCH 10/10 p2m/ept: Enable PML in p2m-ept for log-dirty.

In reply to Kai Huang

This patch adds PML support in p2m-ept for log-dirty.

In case of PML is used, we just need to clear EPT entry's D-bit in order to log that GFN instead of setting EPT entry to read-only. And for partial log-dirty, we also set D-bit for guest memory in normal mode to avoid unnecessary GPA logging, as PML works globally at entire valid EPT table.

---
 xen/arch/x86/mm/hap/hap.c | 15 ++++++++--
 xen/arch/x86/mm/p2m-ept.c | 73 +++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 80 insertions(+), 8 deletions(-)
xen/arch/x86/mm/hap/hap.c +12 -3
index 25f2f58..15fb5de 100644
@@ -198,7 +198,10 @@ static int hap_enable_log_dirty(struct domain *d, bool_t log_global)
 
     if ( log_global )
     {
-        /* set l1e entries of P2M table to be read-only. */
+        /*
+         * switch to log dirty mode. either set l1e entries of P2M table to be
+         * read-only, or enable log dirty in hardware-assisted way.
+         */
         p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
         flush_tlb_mask(d->domain_dirty_cpumask);
     }
@@ -213,14 +216,20 @@ static int hap_disable_log_dirty(struct domain *d)
 
     p2m_disable_hardware_log_dirty(d);
 
-    /* set l1e entries of P2M table with normal mode */
+    /*
+     * switch back to normal mode. either set l1e entries of P2M table with
+     * normal mode, or disable log dirty in hardware-assisted way.
+     */
     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 set l1e entries of P2M table to be
+     * read-only, or enable log dirty in hardware-assisted way.
+     */
     p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
     flush_tlb_mask(d->domain_dirty_cpumask);
 }
xen/arch/x86/mm/p2m-ept.c +68 -5

127 lines not on this page · raw message

Signature · 1 line
2.1.0
#53 lore raw

Re: [PATCH 10/10] p2m/ept: Enable PML in p2m-ept for log-dirty.

xen/arch/x86/mm/p2m-ept.c static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_acces · line 127

Quoted 10 lines · Kai Huang
xen/arch/x86/mm/p2m-ept.c +6 -0
@@ -118,6 +119,12 @@ 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;
+            /*
+             * This is about to avoid unnecessary GPA logging in PML buffer,
+             * such as normal memory in partial log-dirty
+             */
+            if ( vmx_domain_pml_enabled(p2m->domain) )
+                entry->d = 1;

I think that both A and D should be set here, even when PML is not supported, to avoid the MMU having to write them later. And indeed not just for ram_rw, but for every present leaf type.

You will still need to check whether the CPU supports the A/D bits, since AIUI those are reserved bits otherwise.

Quoted 17 lines
xen/arch/x86/mm/p2m-ept.c +10 -0
             break;
         case p2m_mmio_direct:
             entry->r = entry->x = 1;
@@ -125,6 +132,26 @@ static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_acces
                                                     entry->mfn);
             break;
         case p2m_ram_logdirty:
+            entry->r = entry->x = 1;
+            if ( vmx_domain_pml_enabled(p2m->domain) )
+            {
+                /*
+                 * In case of PML, we don't have to write protect 4K page, but
+                 * only need to clear D-bit for it. Note we still need to write
+                 * protect super page in order to split it to 4K pages in EPT
+                 * violation.
+                 */
+                if ( !is_epte_superpage(entry) )

xen/arch/x86/mm/p2m-ept.c static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_acces · line 154

Quoted 10 lines
xen/arch/x86/mm/p2m-ept.c +10 -0
+                {
+                    entry->w = 1;
+                    entry->d = 0;
+                }
+                else
+                    entry->w = 0;
+            }
+            else
+                entry->w = 0;
+            break;

This can be folded into a neater form:

            if ( vmx_domain_pml_enabled(p2m->domain)
	         && !is_epte_superpage(entry) )
            {
                /*
                 * In case of PML, we don't have to write protect 4K page, but
                 * only need to clear D-bit for it. Note we still need to write
                 * protect super page in order to split it to 4K pages in EPT
                 * violation.
                 */
                entry->w = 1;
                entry->d = 0;
            }
            else
                entry->w = 0;

Cheers,

Tim.

author
#54 lore raw

Re: [PATCH 10/10] p2m/ept: Enable PML in p2m-ept for log-dirty.

Quoted 14 lines · Tim Deegan

xen/arch/x86/mm/p2m-ept.c static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_acces · line 127

Quoted 10 lines · Kai Huang
xen/arch/x86/mm/p2m-ept.c +6 -0
@@ -118,6 +119,12 @@ 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;
+            /*
+             * This is about to avoid unnecessary GPA logging in PML buffer,
+             * such as normal memory in partial log-dirty
+             */
+            if ( vmx_domain_pml_enabled(p2m->domain) )
+                entry->d = 1;

I think that both A and D should be set here, even when PML is not supported, to avoid the MMU having to write them later. And indeed not just for ram_rw, but for every present leaf type.

I do agree we should also set A if PML is enabled for the domain, and looks there's no harm to set A bit for all present leaf types. Actually there should be no harm to set A bit even the leaf entry is not present..

But for D bit I think we should be more specific. For p2m types that are writable, we should set the D-bit to avoid unnecessary GPA logging, but for those are read-only, I think it's not reasonable to set D bit, as it's not possible for them to be dirty.

Quoted 3 lines

You will still need to check whether the CPU supports the A/D bits, since AIUI those are reserved bits otherwise.

In my understanding, A/D bits actually are ignored if EPT A/D bit is not enabled in EPTP. Citing one statement in SDM for an example:

"If bit 6 of EPTP is 1, accessed flag for EPT; indicates whether software has accessed the 4-KByte page referenced by this entry (see Section 28.2.4). Ignored if bit 6 of EPTP is 0".

Therefore I think it's unnecessary to check whether CPU supports A/D bits prior to setting A/D bits. The checking is an overhead anyway. And it reminds me we can safely set A bit in middle level entry in splitting super page case, which you pointed out in patch 1 to enable A/D bits.

Of course it's safer to operate A/D bits with whether cpu supports A/D bits checked, and we might better do it.

Is this reasonable?

Thanks,
-Kai

Quoted 30 lines
Quoted 18 lines
xen/arch/x86/mm/p2m-ept.c +10 -0
              break;
          case p2m_mmio_direct:
              entry->r = entry->x = 1;
@@ -125,6 +132,26 @@ static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_acces
                                                      entry->mfn);
              break;
          case p2m_ram_logdirty:
+            entry->r = entry->x = 1;
+            if ( vmx_domain_pml_enabled(p2m->domain) )
+            {
+                /*
+                 * In case of PML, we don't have to write protect 4K page, but
+                 * only need to clear D-bit for it. Note we still need to write
+                 * protect super page in order to split it to 4K pages in EPT
+                 * violation.
+                 */
+                if ( !is_epte_superpage(entry) )

xen/arch/x86/mm/p2m-ept.c static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_acces · line 154

Quoted 10 lines
xen/arch/x86/mm/p2m-ept.c +10 -0
+                {
+                    entry->w = 1;
+                    entry->d = 0;
+                }
+                else
+                    entry->w = 0;
+            }
+            else
+                entry->w = 0;
+            break;

This can be folded into a neater form:

Quoted 14 lines
             if ( vmx_domain_pml_enabled(p2m->domain)
	         && !is_epte_superpage(entry) )
             {
                 /*
                  * In case of PML, we don't have to write protect 4K page, but
                  * only need to clear D-bit for it. Note we still need to write
                  * protect super page in order to split it to 4K pages in EPT
                  * violation.
                  */
                 entry->w = 1;
                 entry->d = 0;
             }
             else
                 entry->w = 0;

Sure.

Thanks,
-Kai

Quoted 4 lines

Cheers,

Tim.

#55 lore raw

Re: [PATCH 10/10] p2m/ept: Enable PML in p2m-ept for log-dirty.

Quoted 17 lines · Kai Huang
Quoted 14 lines · Tim Deegan

xen/arch/x86/mm/p2m-ept.c static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_acces · line 127

Quoted 10 lines · Kai Huang
xen/arch/x86/mm/p2m-ept.c +6 -0
@@ -118,6 +119,12 @@ 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;
+            /*
+             * This is about to avoid unnecessary GPA logging in PML buffer,
+             * such as normal memory in partial log-dirty
+             */
+            if ( vmx_domain_pml_enabled(p2m->domain) )
+                entry->d = 1;

I think that both A and D should be set here, even when PML is not supported, to avoid the MMU having to write them later. And indeed not just for ram_rw, but for every present leaf type.

Quoted 8 lines

I do agree we should also set A if PML is enabled for the domain, and looks there's no harm to set A bit for all present leaf types. Actually there should be no harm to set A bit even the leaf entry is not present..

But for D bit I think we should be more specific. For p2m types that are writable, we should set the D-bit to avoid unnecessary GPA logging, but for those are read-only, I think it's not reasonable to set D bit, as it's not possible for them to be dirty.

Fair enough.

Quoted 8 lines
Quoted 2 lines

You will still need to check whether the CPU supports the A/D bits, since AIUI those are reserved bits otherwise.

In my understanding, A/D bits actually are ignored if EPT A/D bit is not enabled in EPTP. Citing one statement in SDM for an example:

"If bit 6 of EPTP is 1, accessed flag for EPT; indicates whether software has accessed the 4-KByte page referenced
by this entry (see Section 28.2.4). Ignored if bit 6 of EPTP is 0".

I see. I think I was confused by the field being called "reserved" in the struct. I've just checked an older copy of the SDM and those bits used to be "Ignored", so we can just set them on all hardware. Good!

Tim.

#56 lore raw

Re: [PATCH 10/10] p2m/ept: Enable PML in p2m-ept for log-dirty.

Quoted 34 lines · Tim Deegan
Quoted 17 lines · Kai Huang
Quoted 14 lines · Tim Deegan

xen/arch/x86/mm/p2m-ept.c static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_acces · line 127

Quoted 10 lines · Kai Huang
xen/arch/x86/mm/p2m-ept.c +6 -0
@@ -118,6 +119,12 @@ 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;
+            /*
+             * This is about to avoid unnecessary GPA logging in PML buffer,
+             * such as normal memory in partial log-dirty
+             */
+            if ( vmx_domain_pml_enabled(p2m->domain) )
+                entry->d = 1;

I think that both A and D should be set here, even when PML is not supported, to avoid the MMU having to write them later. And indeed not just for ram_rw, but for every present leaf type.

Quoted 8 lines

I do agree we should also set A if PML is enabled for the domain, and looks there's no harm to set A bit for all present leaf types. Actually there should be no harm to set A bit even the leaf entry is not present..

But for D bit I think we should be more specific. For p2m types that are writable, we should set the D-bit to avoid unnecessary GPA logging, but for those are read-only, I think it's not reasonable to set D bit, as it's not possible for them to be dirty.

Fair enough.

Quoted 5 lines
Quoted 2 lines

You will still need to check whether the CPU supports the A/D bits, since AIUI those are reserved bits otherwise.

In my understanding, A/D bits actually are ignored if EPT A/D bit is not enabled in EPTP. Citing one statement in SDM for an example:

Quoted 7 lines
Quoted 3 lines

"If bit 6 of EPTP is 1, accessed flag for EPT; indicates whether software has accessed the 4-KByte page referenced
by this entry (see Section 28.2.4). Ignored if bit 6 of EPTP is 0".

I see. I think I was confused by the field being called "reserved" in the struct. I've just checked an older copy of the SDM and those bits used to be "Ignored", so we can just set them on all hardware. Good!

So to confirm, you intend to update EPT A/D bits directly without prior checking whether cpu supports A/D bits?

Thanks,
-Kai

Quoted 7 lines

Tim.

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

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

Re: [PATCH 10/10] p2m/ept: Enable PML in p2m-ept for log-dirty.

Quoted 7 lines · Kai Huang
Quoted 3 lines · Tim Deegan

I see. I think I was confused by the field being called "reserved" in the struct. I've just checked an older copy of the SDM and those bits used to be "Ignored", so we can just set them on all hardware. Good!

So to confirm, you intend to update EPT A/D bits directly without prior checking whether cpu supports A/D bits?

Yes, that's what I meant.

Thanks,

Tim.

#58 lore raw
In reply to Kai Huang
Quoted 3 lines · Kai Huang

Hi all,

This patch series adds PML support to Xen. Please kindly help to review it.

Overall this looks like a very good series, and it is particularly helpful given the level of commenting.

Which platforms is/will PML be available for?

~Andrew

author
#59 lore raw
Quoted 8 lines · Andrew Cooper
Quoted 3 lines · Kai Huang

Hi all,

This patch series adds PML support to Xen. Please kindly help to review it.

Overall this looks like a very good series, and it is particularly helpful given the level of commenting.

Which platforms is/will PML be available for?

Hi Andrew,

Thanks for your quick review. PML will be available from Intel's "Broadwell server" platform.

Thanks,
-Kai

Quoted 7 lines

~Andrew

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

author
#60 lore raw

Hi Jan, Tim, other maintainers,

Do you have comments? Or should I send out the v2 addressing Andrew's comments, as it's been more than a week since this patch series were sent out?

Thanks,
-Kai

Quoted 30 lines · Kai Huang
Quoted 8 lines · Andrew Cooper
Quoted 3 lines · Kai Huang

Hi all,

This patch series adds PML support to Xen. Please kindly help to review it.

Overall this looks like a very good series, and it is particularly helpful given the level of commenting.

Which platforms is/will PML be available for?

Hi Andrew,

Thanks for your quick review. PML will be available from Intel's "Broadwell server" platform.

Thanks,
-Kai

Quoted 7 lines

~Andrew

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

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

#61 lore raw

Hi,

Quoted 5 lines · Kai Huang

Hi Jan, Tim, other maintainers,

Do you have comments? Or should I send out the v2 addressing Andrew's comments, as it's been more than a week since this patch series were sent out?

I'm sorry, I was away last week so I haven't had a chance to review these patches. I'll probably be able to look at them on Thursday.

Cheers,

Tim.

Quoted 34 lines · Kai Huang
Quoted 32 lines · Andrew Cooper
Quoted 9 lines · Kai Huang
Quoted 4 lines

Hi all,

This patch series adds PML support to Xen. Please kindly help to review it.

Overall this looks like a very good series, and it is particularly helpful given the level of commenting.

Which platforms is/will PML be available for?

Hi Andrew,

Thanks for your quick review. PML will be available from Intel's "Broadwell server" platform.

Thanks,
-Kai

Quoted 7 lines

~Andrew

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

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

author
#62 lore raw
Quoted 10 lines · Tim Deegan

Hi,

Quoted 5 lines · Kai Huang

Hi Jan, Tim, other maintainers,

Do you have comments? Or should I send out the v2 addressing Andrew's comments, as it's been more than a week since this patch series were sent out?

I'm sorry, I was away last week so I haven't had a chance to review these patches. I'll probably be able to look at them on Thursday.

Yeah sure. Thanks Tim!

Thanks,
-Kai

Quoted 39 lines

Cheers,

Tim.

Quoted 26 lines · Kai Huang
Quoted 25 lines · Andrew Cooper
Quoted 9 lines · Kai Huang
Quoted 4 lines

Hi all,

This patch series adds PML support to Xen. Please kindly help to review it.

Overall this looks like a very good series, and it is particularly helpful given the level of commenting.

Which platforms is/will PML be available for?

Hi Andrew,

Thanks for your quick review. PML will be available from Intel's "Broadwell server" platform.

Thanks,
-Kai

Quoted 6 lines

~Andrew

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

Quoted 4 lines
Quoted 4 lines

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

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

#63 lore raw
In reply to Tim Deegan
Quoted 11 lines · Tim Deegan

Hi,

Quoted 5 lines · Kai Huang

Hi Jan, Tim, other maintainers,

Do you have comments? Or should I send out the v2 addressing Andrew's comments, as it's been more than a week since this patch series were sent out?

I'm sorry, I was away last week so I haven't had a chance to review these patches. I'll probably be able to look at them on Thursday.

Done. They seem to be in good shape for a first cut! I've commented on the patches where there was anything I think needs improvement.

Cheers,

Tim.

author
#64 lore raw
Quoted 6 lines · Tim Deegan
Quoted 5 lines · Tim Deegan

Hi,

Quoted 2 lines · Kai Huang

Hi Jan, Tim, other maintainers,

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Do you have comments? Or should I send out the v2 addressing Andrew's comments, as it's been more than a week since this patch series were sent out?

I'm sorry, I was away last week so I haven't had a chance to review these patches. I'll probably be able to look at them on Thursday.

Done. They seem to be in good shape for a first cut! I've commented on the patches where there was anything I think needs improvement.

Thanks Tim for review! Please see my reply.

Thanks,
-Kai

Quoted 4 lines

Cheers,

Tim.