diff --git a/xen/arch/x86/x86_64/domain.c b/xen/arch/x86/x86_64/domain.c index a02d4f569e..533b0b21a0 100644 --- a/xen/arch/x86/x86_64/domain.c +++ b/xen/arch/x86/x86_64/domain.c @@ -58,6 +58,11 @@ compat_vcpu_op(int cmd, unsigned int vcpuid, XEN_GUEST_HANDLE_PARAM(void) arg) rc = 0; guest_from_compat_handle(v->runstate_guest.compat, area.addr.h); + /* NULL handle is deregistering the address. */ + if ( compat_handle_is_null(area.addr.h) ) + break; + + /* Update the newly-registered runstate area, best-effort. */ if ( v == current ) { XLAT_vcpu_runstate_info(&info, &v->runstate); diff --git a/xen/common/domain.c b/xen/common/domain.c index 6b52713518..b41be89cd0 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -2324,12 +2324,21 @@ long common_vcpu_op(int cmd, struct vcpu *v, XEN_GUEST_HANDLE_PARAM(void) arg) if ( copy_from_guest(&area, arg, 1) ) break; + /* NULL handle is deregistering the address. */ + if ( guest_handle_is_null(area.addr.h) ) + { + runstate_guest(v) = area.addr.h; + rc = 0; + break; + } + if ( !guest_handle_okay(area.addr.h, 1) ) break; rc = 0; runstate_guest(v) = area.addr.h; + /* Update the newly-registered runstate area, best-effort. */ if ( v == current ) { __copy_to_guest(runstate_guest(v), &v->runstate, 1); diff --git a/xen/include/public/vcpu.h b/xen/include/public/vcpu.h index 5aea6ca709..9a8003e3ec 100644 --- a/xen/include/public/vcpu.h +++ b/xen/include/public/vcpu.h @@ -112,6 +112,7 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_runstate_info_t); * VCPU was last scheduled to run. * 3. New code wants to prefer VCPUOP_register_runstate_phys_area, and only * fall back to the operation here for backwards compatibility. + * 4. Passing a NULL handle will deregister the region. * @extra_arg == pointer to vcpu_register_runstate_memory_area structure. */ #define VCPUOP_register_runstate_memory_area 5