mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
nvmx: fix resource relinquish for nested VMX
The previous order of relinquish resource is: relinquish_domain_resources() -> vcpu_destroy() -> nvmx_vcpu_destroy(). However some L1 resources like nv_vvmcx and io_bitmaps are free in nvmx_vcpu_destroy(), therefore the relinquish_domain_resources() will not reduce the refcnt of the domain to 0, therefore the latter vcpu release functions will not be called. To fix this issue, we need to release the nv_vvmcx and io_bitmaps in relinquish_domain_resources(). Besides, after destroy the nested vcpu, we need to switch the vmx->vmcs back to the L1 and let the vcpu_destroy() logic to free the L1 VMCS page. Signed-off-by: Dongxiao Xu <dongxiao.xu@intel.com> Committed-by: Keir Fraser <keir@xen.org>
This commit is contained in:
1 parent
4eae16a077
commit
a5ba0ff7c7
5 files changed
+24
-2
No files matched your search
@@ -561,6 +561,9 @@ int hvm_domain_initialise(struct domain *d)
|
||||
|
||||
void hvm_domain_relinquish_resources(struct domain *d)
|
||||
{
|
||||
if ( hvm_funcs.nhvm_domain_relinquish_resources )
|
||||
hvm_funcs.nhvm_domain_relinquish_resources(d);
|
||||
|
||||
hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.ioreq);
|
||||
hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.buf_ioreq);
|
||||
|
||||
|
||||
@@ -1547,7 +1547,8 @@ static struct hvm_function_table __read_mostly vmx_function_table = {
|
||||
.nhvm_vcpu_asid = nvmx_vcpu_asid,
|
||||
.nhvm_vmcx_guest_intercepts_trap = nvmx_intercepts_exception,
|
||||
.nhvm_vcpu_vmexit_trap = nvmx_vmexit_trap,
|
||||
.nhvm_intr_blocked = nvmx_intr_blocked
|
||||
.nhvm_intr_blocked = nvmx_intr_blocked,
|
||||
.nhvm_domain_relinquish_resources = nvmx_domain_relinquish_resources
|
||||
};
|
||||
|
||||
struct hvm_function_table * __init start_vmx(void)
|
||||
|
||||
@@ -57,7 +57,15 @@ void nvmx_vcpu_destroy(struct vcpu *v)
|
||||
{
|
||||
struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v);
|
||||
|
||||
nvmx_purge_vvmcs(v);
|
||||
/*
|
||||
* When destroying the vcpu, it may be running on behalf of L2 guest.
|
||||
* Therefore we need to switch the VMCS pointer back to the L1 VMCS,
|
||||
* in order to avoid double free of L2 VMCS and the possible memory
|
||||
* leak of L1 VMCS page.
|
||||
*/
|
||||
if ( nvcpu->nv_n1vmcx )
|
||||
v->arch.hvm_vmx.vmcs = nvcpu->nv_n1vmcx;
|
||||
|
||||
if ( nvcpu->nv_n2vmcx ) {
|
||||
__vmpclear(virt_to_maddr(nvcpu->nv_n2vmcx));
|
||||
free_xenheap_page(nvcpu->nv_n2vmcx);
|
||||
@@ -65,6 +73,14 @@ void nvmx_vcpu_destroy(struct vcpu *v)
|
||||
}
|
||||
}
|
||||
|
||||
void nvmx_domain_relinquish_resources(struct domain *d)
|
||||
{
|
||||
struct vcpu *v;
|
||||
|
||||
for_each_vcpu ( d, v )
|
||||
nvmx_purge_vvmcs(v);
|
||||
}
|
||||
|
||||
int nvmx_vcpu_reset(struct vcpu *v)
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -179,6 +179,7 @@ struct hvm_function_table {
|
||||
bool_t (*nhvm_vmcx_hap_enabled)(struct vcpu *v);
|
||||
|
||||
enum hvm_intblk (*nhvm_intr_blocked)(struct vcpu *v);
|
||||
void (*nhvm_domain_relinquish_resources)(struct domain *d);
|
||||
};
|
||||
|
||||
extern struct hvm_function_table hvm_funcs;
|
||||
|
||||
@@ -96,6 +96,7 @@ uint32_t nvmx_vcpu_asid(struct vcpu *v);
|
||||
enum hvm_intblk nvmx_intr_blocked(struct vcpu *v);
|
||||
int nvmx_intercepts_exception(struct vcpu *v,
|
||||
unsigned int trap, int error_code);
|
||||
void nvmx_domain_relinquish_resources(struct domain *d);
|
||||
|
||||
int nvmx_handle_vmxon(struct cpu_user_regs *regs);
|
||||
int nvmx_handle_vmxoff(struct cpu_user_regs *regs);
|
||||
|
||||