mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
[XEN] Support VCPU reset via DOMCTL_setvcpucontext.
Signed-off-by: Andrei Petrov <andrei.petrov@xensource.com>
This commit is contained in:
1 parent
115209d91b
commit
bbb6a715dc
5 files changed
+113
-52
No files matched your search
@@ -602,12 +602,13 @@ int xc_vcpu_setcontext(int xc_handle,
|
||||
domctl.u.vcpucontext.vcpu = vcpu;
|
||||
set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt);
|
||||
|
||||
if ( (rc = lock_pages(ctxt, sizeof(*ctxt))) != 0 )
|
||||
if ( (ctxt != NULL) && ((rc = lock_pages(ctxt, sizeof(*ctxt))) != 0) )
|
||||
return rc;
|
||||
|
||||
rc = do_domctl(xc_handle, &domctl);
|
||||
|
||||
unlock_pages(ctxt, sizeof(*ctxt));
|
||||
if ( ctxt != NULL )
|
||||
unlock_pages(ctxt, sizeof(*ctxt));
|
||||
|
||||
return rc;
|
||||
|
||||
|
||||
+68
-49
@@ -50,6 +50,8 @@ DEFINE_PER_CPU(struct vcpu *, curr_vcpu);
|
||||
static void paravirt_ctxt_switch_from(struct vcpu *v);
|
||||
static void paravirt_ctxt_switch_to(struct vcpu *v);
|
||||
|
||||
static void vcpu_destroy_pagetables(struct vcpu *v);
|
||||
|
||||
static void continue_idle_domain(struct vcpu *v)
|
||||
{
|
||||
reset_stack_and_jump(idle_loop);
|
||||
@@ -658,6 +660,13 @@ int arch_set_info_guest(
|
||||
#undef c
|
||||
}
|
||||
|
||||
int arch_vcpu_reset(struct vcpu *v)
|
||||
{
|
||||
destroy_gdt(v);
|
||||
vcpu_destroy_pagetables(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
long
|
||||
arch_do_vcpu_op(
|
||||
int cmd, struct vcpu *v, XEN_GUEST_HANDLE(void) arg)
|
||||
@@ -1380,63 +1389,73 @@ static void relinquish_memory(struct domain *d, struct list_head *list)
|
||||
spin_unlock_recursive(&d->page_alloc_lock);
|
||||
}
|
||||
|
||||
static void vcpu_destroy_pagetables(struct vcpu *v)
|
||||
{
|
||||
struct domain *d = v->domain;
|
||||
unsigned long pfn;
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
if ( IS_COMPAT(d) )
|
||||
{
|
||||
if ( is_hvm_vcpu(v) )
|
||||
pfn = pagetable_get_pfn(v->arch.guest_table);
|
||||
else
|
||||
pfn = l4e_get_pfn(*(l4_pgentry_t *)
|
||||
__va(pagetable_get_paddr(v->arch.guest_table)));
|
||||
|
||||
if ( pfn != 0 )
|
||||
{
|
||||
if ( shadow_mode_refcounts(d) )
|
||||
put_page(mfn_to_page(pfn));
|
||||
else
|
||||
put_page_and_type(mfn_to_page(pfn));
|
||||
}
|
||||
|
||||
v->arch.guest_table = pagetable_null();
|
||||
v->arch.cr3 = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
pfn = pagetable_get_pfn(v->arch.guest_table);
|
||||
if ( pfn != 0 )
|
||||
{
|
||||
if ( shadow_mode_refcounts(d) )
|
||||
put_page(mfn_to_page(pfn));
|
||||
else
|
||||
put_page_and_type(mfn_to_page(pfn));
|
||||
#ifdef __x86_64__
|
||||
if ( pfn == pagetable_get_pfn(v->arch.guest_table_user) )
|
||||
v->arch.guest_table_user = pagetable_null();
|
||||
#endif
|
||||
v->arch.guest_table = pagetable_null();
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
/* Drop ref to guest_table_user (from MMUEXT_NEW_USER_BASEPTR) */
|
||||
pfn = pagetable_get_pfn(v->arch.guest_table_user);
|
||||
if ( pfn != 0 )
|
||||
{
|
||||
if ( shadow_mode_refcounts(d) )
|
||||
put_page(mfn_to_page(pfn));
|
||||
else
|
||||
put_page_and_type(mfn_to_page(pfn));
|
||||
v->arch.guest_table_user = pagetable_null();
|
||||
}
|
||||
#endif
|
||||
|
||||
v->arch.cr3 = 0;
|
||||
}
|
||||
|
||||
void domain_relinquish_resources(struct domain *d)
|
||||
{
|
||||
struct vcpu *v;
|
||||
unsigned long pfn;
|
||||
|
||||
BUG_ON(!cpus_empty(d->domain_dirty_cpumask));
|
||||
|
||||
/* Drop the in-use references to page-table bases. */
|
||||
for_each_vcpu ( d, v )
|
||||
{
|
||||
/* Drop ref to guest_table (from new_guest_cr3(), svm/vmx cr3 handling,
|
||||
* or sh_update_paging_modes()) */
|
||||
#ifdef CONFIG_COMPAT
|
||||
if ( IS_COMPAT(d) )
|
||||
{
|
||||
if ( is_hvm_vcpu(v) )
|
||||
pfn = pagetable_get_pfn(v->arch.guest_table);
|
||||
else
|
||||
pfn = l4e_get_pfn(*(l4_pgentry_t *)__va(pagetable_get_paddr(v->arch.guest_table)));
|
||||
|
||||
if ( pfn != 0 )
|
||||
{
|
||||
if ( shadow_mode_refcounts(d) )
|
||||
put_page(mfn_to_page(pfn));
|
||||
else
|
||||
put_page_and_type(mfn_to_page(pfn));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
pfn = pagetable_get_pfn(v->arch.guest_table);
|
||||
if ( pfn != 0 )
|
||||
{
|
||||
if ( shadow_mode_refcounts(d) )
|
||||
put_page(mfn_to_page(pfn));
|
||||
else
|
||||
put_page_and_type(mfn_to_page(pfn));
|
||||
#ifdef __x86_64__
|
||||
if ( pfn == pagetable_get_pfn(v->arch.guest_table_user) )
|
||||
v->arch.guest_table_user = pagetable_null();
|
||||
#endif
|
||||
v->arch.guest_table = pagetable_null();
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
/* Drop ref to guest_table_user (from MMUEXT_NEW_USER_BASEPTR) */
|
||||
pfn = pagetable_get_pfn(v->arch.guest_table_user);
|
||||
if ( pfn != 0 )
|
||||
{
|
||||
if ( shadow_mode_refcounts(d) )
|
||||
put_page(mfn_to_page(pfn));
|
||||
else
|
||||
put_page_and_type(mfn_to_page(pfn));
|
||||
v->arch.guest_table_user = pagetable_null();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
vcpu_destroy_pagetables(v);
|
||||
|
||||
/* Tear down shadow mode stuff. */
|
||||
shadow_teardown(d);
|
||||
|
||||
+37
-1
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <xen/config.h>
|
||||
#include <xen/compat.h>
|
||||
#include <xen/init.h>
|
||||
#include <xen/lib.h>
|
||||
#include <xen/errno.h>
|
||||
@@ -467,7 +468,12 @@ int set_info_guest(struct domain *d,
|
||||
|
||||
if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
if ( IS_COMPAT(v->domain)
|
||||
? compat_handle_is_null(vcpucontext.cmp->ctxt)
|
||||
: guest_handle_is_null(vcpucontext.nat->ctxt) )
|
||||
return vcpu_reset(v);
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
|
||||
< sizeof(struct compat_vcpu_guest_context));
|
||||
@@ -521,6 +527,36 @@ int boot_vcpu(struct domain *d, int vcpuid, vcpu_guest_context_u ctxt)
|
||||
return arch_set_info_guest(v, ctxt);
|
||||
}
|
||||
|
||||
int vcpu_reset(struct vcpu *v)
|
||||
{
|
||||
struct domain *d = v->domain;
|
||||
int rc;
|
||||
|
||||
domain_pause(d);
|
||||
LOCK_BIGLOCK(d);
|
||||
|
||||
rc = arch_vcpu_reset(v);
|
||||
if ( rc != 0 )
|
||||
goto out;
|
||||
|
||||
set_bit(_VCPUF_down, &v->vcpu_flags);
|
||||
|
||||
clear_bit(_VCPUF_fpu_initialised, &v->vcpu_flags);
|
||||
clear_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags);
|
||||
clear_bit(_VCPUF_blocked, &v->vcpu_flags);
|
||||
clear_bit(_VCPUF_initialised, &v->vcpu_flags);
|
||||
clear_bit(_VCPUF_nmi_pending, &v->vcpu_flags);
|
||||
clear_bit(_VCPUF_nmi_masked, &v->vcpu_flags);
|
||||
clear_bit(_VCPUF_polling, &v->vcpu_flags);
|
||||
|
||||
out:
|
||||
UNLOCK_BIGLOCK(v->domain);
|
||||
domain_unpause(d);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
|
||||
{
|
||||
struct domain *d = current->domain;
|
||||
|
||||
@@ -173,6 +173,8 @@ int switch_native(struct domain *);
|
||||
|
||||
#else
|
||||
|
||||
#define compat_handle_is_null(hnd) 0
|
||||
|
||||
#define BITS_PER_GUEST_LONG(d) BITS_PER_LONG
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,6 +12,7 @@ struct vcpu *alloc_vcpu(
|
||||
int boot_vcpu(
|
||||
struct domain *d, int vcpuid, vcpu_guest_context_u ctxt);
|
||||
struct vcpu *alloc_idle_vcpu(unsigned int cpu_id);
|
||||
int vcpu_reset(struct vcpu *v);
|
||||
|
||||
struct domain *alloc_domain(domid_t domid);
|
||||
void free_domain(struct domain *d);
|
||||
@@ -56,4 +57,6 @@ void arch_dump_vcpu_info(struct vcpu *v);
|
||||
|
||||
void arch_dump_domain_info(struct domain *d);
|
||||
|
||||
int arch_vcpu_reset(struct vcpu *v);
|
||||
|
||||
#endif /* __XEN_DOMAIN_H__ */
|
||||