vmx: add help functions to support PML

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

Signed-off-by: Kai Huang <kai.huang@linux.intel.com>
Acked-by: Tim Deegan <tim@xen.org>
Acked-by: Kevin Tian <kevin.tian@intel.com>
This commit is contained in:
Kai Huang authored and Jan Beulich committed 2015-05-04 12:15:07 +02:00
1 parent 43ba5a967e
commit d445df7d9a
2 files changed
+188

No files matched your search

+179
View File
@@ -1324,6 +1324,185 @@ void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector)
&v->arch.hvm_vmx.eoi_exitmap_changed);
}
bool_t vmx_vcpu_pml_enabled(const struct vcpu *v)
{
return !!(v->arch.hvm_vmx.secondary_exec_control &
SECONDARY_EXEC_ENABLE_PML);
}
int vmx_vcpu_enable_pml(struct vcpu *v)
{
if ( vmx_vcpu_pml_enabled(v) )
return 0;
v->arch.hvm_vmx.pml_pg = v->domain->arch.paging.alloc_page(v->domain);
if ( !v->arch.hvm_vmx.pml_pg )
return -ENOMEM;
vmx_vmcs_enter(v);
__vmwrite(PML_ADDRESS, page_to_mfn(v->arch.hvm_vmx.pml_pg) << PAGE_SHIFT);
__vmwrite(GUEST_PML_INDEX, NR_PML_ENTRIES - 1);
v->arch.hvm_vmx.secondary_exec_control |= SECONDARY_EXEC_ENABLE_PML;
__vmwrite(SECONDARY_VM_EXEC_CONTROL,
v->arch.hvm_vmx.secondary_exec_control);
vmx_vmcs_exit(v);
return 0;
}
void vmx_vcpu_disable_pml(struct vcpu *v)
{
if ( !vmx_vcpu_pml_enabled(v) )
return;
/* Make sure we don't lose any logged GPAs. */
vmx_vcpu_flush_pml_buffer(v);
vmx_vmcs_enter(v);
v->arch.hvm_vmx.secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
__vmwrite(SECONDARY_VM_EXEC_CONTROL,
v->arch.hvm_vmx.secondary_exec_control);
vmx_vmcs_exit(v);
v->domain->arch.paging.free_page(v->domain, v->arch.hvm_vmx.pml_pg);
v->arch.hvm_vmx.pml_pg = NULL;
}
void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
{
uint64_t *pml_buf;
unsigned long pml_idx;
ASSERT((v == current) || (!vcpu_runnable(v) && !v->is_running));
ASSERT(vmx_vcpu_pml_enabled(v));
vmx_vmcs_enter(v);
__vmread(GUEST_PML_INDEX, &pml_idx);
/* Do nothing if PML buffer is empty. */
if ( pml_idx == (NR_PML_ENTRIES - 1) )
goto out;
pml_buf = __map_domain_page(v->arch.hvm_vmx.pml_pg);
/*
* PML index can be either 2^16-1 (buffer is full), or 0 ~ NR_PML_ENTRIES-1
* (buffer is not full), and in latter case PML index always points to next
* available entity.
*/
if ( pml_idx >= NR_PML_ENTRIES )
pml_idx = 0;
else
pml_idx++;
for ( ; pml_idx < NR_PML_ENTRIES; pml_idx++ )
{
unsigned long gfn = pml_buf[pml_idx] >> PAGE_SHIFT;
/*
* Need to change type from log-dirty to normal memory for logged GFN.
* hap_track_dirty_vram depends on it to work. And we mark all logged
* GFNs to be dirty, as we cannot be sure whether it's safe to ignore
* GFNs on which p2m_change_type_one returns failure. The failure cases
* are very rare, and additional cost is negligible, but a missing mark
* is extremely difficult to debug.
*/
p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty, p2m_ram_rw);
paging_mark_gfn_dirty(v->domain, gfn);
}
unmap_domain_page(pml_buf);
/* Reset PML index */
__vmwrite(GUEST_PML_INDEX, NR_PML_ENTRIES - 1);
out:
vmx_vmcs_exit(v);
}
bool_t vmx_domain_pml_enabled(const struct domain *d)
{
return !!(d->arch.hvm_domain.vmx.status & VMX_DOMAIN_PML_ENABLED);
}
/*
* This function enables PML for particular domain. It should be called when
* domain is paused.
*
* PML needs to be enabled globally for all vcpus of the domain, as PML buffer
* and PML index are pre-vcpu, but EPT table is shared by vcpus, therefore
* enabling PML on partial vcpus won't work.
*/
int vmx_domain_enable_pml(struct domain *d)
{
struct vcpu *v;
int rc;
ASSERT(atomic_read(&d->pause_count));
if ( vmx_domain_pml_enabled(d) )
return 0;
for_each_vcpu( d, v )
if ( (rc = vmx_vcpu_enable_pml(v)) != 0 )
goto error;
d->arch.hvm_domain.vmx.status |= VMX_DOMAIN_PML_ENABLED;
return 0;
error:
for_each_vcpu( d, v )
if ( vmx_vcpu_pml_enabled(v) )
vmx_vcpu_disable_pml(v);
return rc;
}
/*
* Disable PML for particular domain. Called when domain is paused.
*
* The same as enabling PML for domain, disabling PML should be done for all
* vcpus at once.
*/
void vmx_domain_disable_pml(struct domain *d)
{
struct vcpu *v;
ASSERT(atomic_read(&d->pause_count));
if ( !vmx_domain_pml_enabled(d) )
return;
for_each_vcpu( d, v )
vmx_vcpu_disable_pml(v);
d->arch.hvm_domain.vmx.status &= ~VMX_DOMAIN_PML_ENABLED;
}
/*
* Flush PML buffer of all vcpus, and update the logged dirty pages to log-dirty
* radix tree. Called when domain is paused.
*/
void vmx_domain_flush_pml_buffers(struct domain *d)
{
struct vcpu *v;
ASSERT(atomic_read(&d->pause_count));
if ( !vmx_domain_pml_enabled(d) )
return;
for_each_vcpu( d, v )
vmx_vcpu_flush_pml_buffer(v);
}
int vmx_create_vmcs(struct vcpu *v)
{
struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx;
+9
View File
@@ -499,6 +499,15 @@ static inline int vmx_add_host_load_msr(u32 msr)
DECLARE_PER_CPU(bool_t, vmxon);
bool_t vmx_vcpu_pml_enabled(const struct vcpu *v);
int vmx_vcpu_enable_pml(struct vcpu *v);
void vmx_vcpu_disable_pml(struct vcpu *v);
void vmx_vcpu_flush_pml_buffer(struct vcpu *v);
bool_t vmx_domain_pml_enabled(const struct domain *d);
int vmx_domain_enable_pml(struct domain *d);
void vmx_domain_disable_pml(struct domain *d);
void vmx_domain_flush_pml_buffers(struct domain *d);
#endif /* ASM_X86_HVM_VMX_VMCS_H__ */
/*
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.