From: Yang Zhang Date: Thu, 13 Feb 2014 15:50:22 +0000 (+0000) Subject: When enabling log dirty mode, it sets all guest's memory to readonly. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~5571 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=077fc1c04d70ef1748ac2daa6622b3320a1a004c;p=xen.git When enabling log dirty mode, it sets all guest's memory to readonly. And in HAP enabled domain, it modifies all EPT entries to clear write bit to make sure it is readonly. This will cause problem if VT-d shares page table with EPT: the device may issue a DMA write request, then VT-d engine tells it the target memory is readonly and result in VT-d fault. Currnetly, there are two places will enable log dirty mode: migration and vram tracking. Migration with device assigned is not allowed, so it is ok. For vram, it doesn't need to set all memory to readonly. Only track the vram range is enough. Signed-off-by: Yang Zhang Acked-by: Tim Deegan --- diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c index d3f64bdb97..5f756366aa 100644 --- a/xen/arch/x86/mm/hap/hap.c +++ b/xen/arch/x86/mm/hap/hap.c @@ -82,7 +82,7 @@ int hap_track_dirty_vram(struct domain *d, if ( !paging_mode_log_dirty(d) ) { hap_logdirty_init(d); - rc = paging_log_dirty_enable(d); + rc = paging_log_dirty_enable(d, 0); if ( rc ) goto out; } @@ -167,17 +167,25 @@ out: /* HAP LOG DIRTY SUPPORT */ /************************************************/ -/* hap code to call when log_dirty is enable. return 0 if no problem found. */ -static int hap_enable_log_dirty(struct domain *d) +/* + * hap code to call when log_dirty is enable. return 0 if no problem found. + * + * NB: Domain that having device assigned should not set log_global. Because + * there is no way to track the memory updating from device. + */ +static int hap_enable_log_dirty(struct domain *d, bool_t log_global) { /* turn on PG_log_dirty bit in paging mode */ paging_lock(d); d->arch.paging.mode |= PG_log_dirty; paging_unlock(d); - /* set l1e entries of P2M table to be read-only. */ - p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty); - flush_tlb_mask(d->domain_dirty_cpumask); + if ( log_global ) + { + /* set l1e entries of P2M table to be read-only. */ + p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty); + flush_tlb_mask(d->domain_dirty_cpumask); + } return 0; } diff --git a/xen/arch/x86/mm/paging.c b/xen/arch/x86/mm/paging.c index 21344e50ff..ab5eacbb7b 100644 --- a/xen/arch/x86/mm/paging.c +++ b/xen/arch/x86/mm/paging.c @@ -164,7 +164,7 @@ void paging_free_log_dirty_bitmap(struct domain *d) paging_unlock(d); } -int paging_log_dirty_enable(struct domain *d) +int paging_log_dirty_enable(struct domain *d, bool_t log_global) { int ret; @@ -172,7 +172,7 @@ int paging_log_dirty_enable(struct domain *d) return -EINVAL; domain_pause(d); - ret = d->arch.paging.log_dirty.enable_log_dirty(d); + ret = d->arch.paging.log_dirty.enable_log_dirty(d, log_global); domain_unpause(d); return ret; @@ -489,7 +489,8 @@ void paging_log_dirty_range(struct domain *d, * These function pointers must not be followed with the log-dirty lock held. */ void paging_log_dirty_init(struct domain *d, - int (*enable_log_dirty)(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)) { @@ -590,7 +591,7 @@ int paging_domctl(struct domain *d, xen_domctl_shadow_op_t *sc, case XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY: if ( hap_enabled(d) ) hap_logdirty_init(d); - return paging_log_dirty_enable(d); + return paging_log_dirty_enable(d, 1); case XEN_DOMCTL_SHADOW_OP_OFF: if ( paging_mode_log_dirty(d) ) diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index 0bfa595298..11c6b6273c 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -3418,7 +3418,7 @@ shadow_write_p2m_entry(struct vcpu *v, unsigned long gfn, /* Shadow specific code which is called in paging_log_dirty_enable(). * Return 0 if no problem found. */ -int shadow_enable_log_dirty(struct domain *d) +int shadow_enable_log_dirty(struct domain *d, bool_t log_global) { int ret; diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index ea72db2c3e..4ff89f01ea 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -169,7 +169,7 @@ struct log_dirty_domain { unsigned int dirty_count; /* functions which are paging mode specific */ - int (*enable_log_dirty )(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); }; diff --git a/xen/include/asm-x86/paging.h b/xen/include/asm-x86/paging.h index cd7ee3be66..8dd2a61367 100644 --- a/xen/include/asm-x86/paging.h +++ b/xen/include/asm-x86/paging.h @@ -143,14 +143,15 @@ void paging_log_dirty_range(struct domain *d, uint8_t *dirty_bitmap); /* enable log dirty */ -int paging_log_dirty_enable(struct domain *d); +int paging_log_dirty_enable(struct domain *d, bool_t log_global); /* disable log dirty */ int paging_log_dirty_disable(struct domain *d); /* log dirty initialization */ void paging_log_dirty_init(struct domain *d, - int (*enable_log_dirty)(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)); diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h index 852023de79..348915e669 100644 --- a/xen/include/asm-x86/shadow.h +++ b/xen/include/asm-x86/shadow.h @@ -82,7 +82,7 @@ void shadow_teardown(struct domain *d); void shadow_final_teardown(struct domain *d); /* shadow code to call when log dirty is enabled */ -int shadow_enable_log_dirty(struct domain *d); +int shadow_enable_log_dirty(struct domain *d, bool_t log_global); /* shadow code to call when log dirty is disabled */ int shadow_disable_log_dirty(struct domain *d);