* non-architectural indices.
*/
int xc_monitor_mov_to_msr(xc_interface *xch, uint32_t domain_id, uint32_t msr,
- bool enable);
+ bool enable, bool onchangeonly);
int xc_monitor_singlestep(xc_interface *xch, uint32_t domain_id, bool enable);
int xc_monitor_software_breakpoint(xc_interface *xch, uint32_t domain_id,
bool enable);
}
int xc_monitor_mov_to_msr(xc_interface *xch, uint32_t domain_id, uint32_t msr,
- bool enable)
+ bool enable, bool onchangeonly)
{
DECLARE_DOMCTL;
: XEN_DOMCTL_MONITOR_OP_DISABLE;
domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR;
domctl.u.monitor_op.u.mov_to_msr.msr = msr;
+ domctl.u.monitor_op.u.mov_to_msr.onchangeonly = onchangeonly;
return do_domctl(xch, &domctl);
}
}
int hvm_msr_write_intercept(unsigned int msr, uint64_t msr_content,
- bool_t may_defer)
+ bool may_defer)
{
struct vcpu *v = current;
struct domain *d = v->domain;
if ( may_defer && unlikely(monitored_msr(v->domain, msr)) )
{
+ uint64_t msr_old_content;
+
+ ret = hvm_msr_read_intercept(msr, &msr_old_content);
+ if ( ret != X86EMUL_OKAY )
+ return ret;
+
ASSERT(v->arch.vm_event);
/* The actual write will occur in hvm_do_resume() (if permitted). */
v->arch.vm_event->write_data.msr = msr;
v->arch.vm_event->write_data.value = msr_content;
- hvm_monitor_msr(msr, msr_content);
+ hvm_monitor_msr(msr, msr_content, msr_old_content);
return X86EMUL_OKAY;
}
monitor_traps(curr, true, &req) == 1;
}
-void hvm_monitor_msr(unsigned int msr, uint64_t value)
+void hvm_monitor_msr(unsigned int msr, uint64_t new_value, uint64_t old_value)
{
struct vcpu *curr = current;
- if ( monitored_msr(curr->domain, msr) )
+ if ( monitored_msr(curr->domain, msr) &&
+ (!monitored_msr_onchangeonly(curr->domain, msr) ||
+ new_value != old_value) )
{
vm_event_request_t req = {
.reason = VM_EVENT_REASON_MOV_TO_MSR,
.u.mov_to_msr.msr = msr,
- .u.mov_to_msr.value = value,
+ .u.mov_to_msr.new_value = new_value,
+ .u.mov_to_msr.old_value = old_value
};
monitor_traps(curr, 1, &req);
int arch_monitor_init_domain(struct domain *d)
{
if ( !d->arch.monitor.msr_bitmap )
- d->arch.monitor.msr_bitmap = xzalloc(struct monitor_msr_bitmap);
+ d->arch.monitor.msr_bitmap = xzalloc_array(struct monitor_msr_bitmap,
+ 2);
if ( !d->arch.monitor.msr_bitmap )
return -ENOMEM;
}
}
-static int monitor_enable_msr(struct domain *d, u32 msr)
+static int monitor_enable_msr(struct domain *d, u32 msr, bool onchangeonly)
{
unsigned long *bitmap;
u32 index = msr;
hvm_enable_msr_interception(d, msr);
+ if ( onchangeonly )
+ __set_bit(index + sizeof(struct monitor_msr_bitmap) * 8, bitmap);
+ else
+ __clear_bit(index + sizeof(struct monitor_msr_bitmap) * 8, bitmap);
+
return 0;
}
return test_bit(msr, bitmap);
}
+bool monitored_msr_onchangeonly(const struct domain *d, u32 msr)
+{
+ const unsigned long *bitmap;
+
+ if ( !d->arch.monitor.msr_bitmap )
+ return false;
+
+ bitmap = monitor_bitmap_for_msr(d, &msr);
+
+ if ( !bitmap )
+ return false;
+
+ return test_bit(msr + sizeof(struct monitor_msr_bitmap) * 8, bitmap);
+}
+
int arch_monitor_domctl_event(struct domain *d,
struct xen_domctl_monitor_op *mop)
{
}
if ( requested_status )
- rc = monitor_enable_msr(d, msr);
+ rc = monitor_enable_msr(d, msr, mop->u.mov_to_msr.onchangeonly);
else
rc = monitor_disable_msr(d, msr);
unsigned long old);
#define hvm_monitor_crX(cr, new, old) \
hvm_monitor_cr(VM_EVENT_X86_##cr, new, old)
-void hvm_monitor_msr(unsigned int msr, uint64_t value);
+void hvm_monitor_msr(unsigned int msr, uint64_t value, uint64_t old_value);
void hvm_monitor_descriptor_access(uint64_t exit_info,
uint64_t vmx_exit_qualification,
uint8_t descriptor, bool is_write);
int __must_check hvm_msr_read_intercept(
unsigned int msr, uint64_t *msr_content);
int __must_check hvm_msr_write_intercept(
- unsigned int msr, uint64_t msr_content, bool_t may_defer);
+ unsigned int msr, uint64_t msr_content, bool may_defer);
#endif /* __ASM_X86_HVM_SUPPORT_H__ */
void arch_monitor_cleanup_domain(struct domain *d);
bool monitored_msr(const struct domain *d, u32 msr);
+bool monitored_msr_onchangeonly(const struct domain *d, u32 msr);
#endif /* __ASM_X86_MONITOR_H__ */
struct {
uint32_t msr;
+ /* Send event only on a change of value */
+ uint8_t onchangeonly;
} mov_to_msr;
struct {
#include "xen.h"
-#define VM_EVENT_INTERFACE_VERSION 0x00000002
+#define VM_EVENT_INTERFACE_VERSION 0x00000003
#if defined(__XEN__) || defined(__XEN_TOOLS__)
struct vm_event_mov_to_msr {
uint64_t msr;
- uint64_t value;
+ uint64_t new_value;
+ uint64_t old_value;
};
#define VM_EVENT_DESC_IDTR 1