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.
Signed-off-by: Kai Huang <kai.hu...@linux.intel.com> --- xen/arch/x86/mm/hap/hap.c | 15 ++++++++-- xen/arch/x86/mm/p2m-ept.c | 73 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c index 25f2f58..15fb5de 100644 --- a/xen/arch/x86/mm/hap/hap.c +++ b/xen/arch/x86/mm/hap/hap.c @@ -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); } diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index 8650092..9a719f6 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -102,7 +102,8 @@ static int atomic_write_ept_entry(ept_entry_t *entryptr, ept_entry_t new, return rc; } -static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_access_t access) +static void ept_p2m_type_to_flags(struct p2m_domain *p2m, ept_entry_t *entry, + p2m_type_t type, p2m_access_t access) { /* First apply type permissions */ switch(type) @@ -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; 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) ) + { + entry->w = 1; + entry->d = 0; + } + else + entry->w = 0; + } + else + entry->w = 0; + break; case p2m_ram_ro: case p2m_ram_shared: entry->r = entry->x = 1; @@ -250,7 +277,7 @@ static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry, /* A/D bits are inherited from superpage */ ASSERT(!epte->avail3); - ept_p2m_type_to_flags(epte, epte->sa_p2mt, epte->access); + ept_p2m_type_to_flags(p2m, epte, epte->sa_p2mt, epte->access); if ( (level - 1) == target ) continue; @@ -492,7 +519,7 @@ static int resolve_misconfig(struct p2m_domain *p2m, unsigned long gfn) { e.sa_p2mt = p2m_is_logdirty_range(p2m, gfn + i, gfn + i) ? p2m_ram_logdirty : p2m_ram_rw; - ept_p2m_type_to_flags(&e, e.sa_p2mt, e.access); + ept_p2m_type_to_flags(p2m, &e, e.sa_p2mt, e.access); } e.recalc = 0; wrc = atomic_write_ept_entry(&epte[i], e, level); @@ -544,7 +571,7 @@ static int resolve_misconfig(struct p2m_domain *p2m, unsigned long gfn) e.ipat = ipat; e.recalc = 0; if ( recalc && p2m_is_changeable(e.sa_p2mt) ) - ept_p2m_type_to_flags(&e, e.sa_p2mt, e.access); + ept_p2m_type_to_flags(p2m, &e, e.sa_p2mt, e.access); wrc = atomic_write_ept_entry(&epte[i], e, level); ASSERT(wrc == 0); } @@ -755,7 +782,7 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn, if ( ept_entry->mfn == new_entry.mfn ) need_modify_vtd_table = 0; - ept_p2m_type_to_flags(&new_entry, p2mt, p2ma); + ept_p2m_type_to_flags(p2m, &new_entry, p2mt, p2ma); } rc = atomic_write_ept_entry(ept_entry, new_entry, target); @@ -1057,6 +1084,35 @@ void ept_sync_domain(struct p2m_domain *p2m) __ept_sync_domain, p2m, 1); } +static void ept_enable_pml(struct p2m_domain *p2m) +{ + /* + * No need to check if vmx_domain_enable_pml has succeeded or not, as + * ept_p2m_type_to_flags will check if PML has been enabled or not, and + * traditional write protection will be used if PML has not been enabled. + */ + if ( vmx_domain_pml_enabled(p2m->domain) ) + return; + + vmx_domain_enable_pml(p2m->domain); +} + +static void ept_disable_pml(struct p2m_domain *p2m) +{ + if ( !vmx_domain_pml_enabled(p2m->domain) ) + return; + + vmx_domain_disable_pml(p2m->domain); +} + +static void ept_flush_pml_buffers(struct p2m_domain *p2m) +{ + if ( !vmx_domain_pml_enabled(p2m->domain) ) + return; + + vmx_domain_flush_pml_buffers(p2m->domain); +} + int ept_p2m_init(struct p2m_domain *p2m) { struct ept_data *ept = &p2m->ept; @@ -1077,6 +1133,13 @@ int ept_p2m_init(struct p2m_domain *p2m) /* Enable EPT A/D bit if it's supported by hardware */ ept->ept_ad = cpu_has_vmx_ept_ad_bit ? 1 : 0; + if ( cpu_has_vmx_pml ) + { + p2m->enable_hardware_log_dirty = ept_enable_pml; + p2m->disable_hardware_log_dirty = ept_disable_pml; + p2m->flush_hardware_cached_dirty = ept_flush_pml_buffers; + } + if ( !zalloc_cpumask_var(&ept->synced_mask) ) return -ENOMEM; -- 2.1.0 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel