Adds monitor support for I/O instructions.
Signed-off-by: Dmitry Isaykin <isaikin-dmitry@yandex.ru>
Signed-off-by: Anton Belousov <abelousov@ptsecurity.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Anthony PERARD <anthony.perard@citrix.com>
Acked-by: Tamas K Lengyel <tamas@tklengyel.com>
bool enable);
int xc_monitor_vmexit(xc_interface *xch, uint32_t domain_id, bool enable,
bool sync);
+int xc_monitor_io(xc_interface *xch, uint32_t domain_id, bool enable);
/**
* This function enables / disables emulation for each REP for a
* REP-compatible instruction.
return do_domctl(xch, &domctl);
}
+int xc_monitor_io(xc_interface *xch, uint32_t domain_id, bool enable)
+{
+ DECLARE_DOMCTL;
+
+ domctl.cmd = XEN_DOMCTL_monitor_op;
+ domctl.domain = domain_id;
+ domctl.u.monitor_op.op = enable ? XEN_DOMCTL_MONITOR_OP_ENABLE
+ : XEN_DOMCTL_MONITOR_OP_DISABLE;
+ domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_IO;
+
+ return do_domctl(xch, &domctl);
+}
+
/*
* Local variables:
* mode: C
return monitor_traps(curr, ad->monitor.vmexit_sync, &req);
}
+int hvm_monitor_io(unsigned int port, unsigned int bytes,
+ bool in, bool str)
+{
+ struct vcpu *curr = current;
+ struct arch_domain *ad = &curr->domain->arch;
+ vm_event_request_t req = {
+ .reason = VM_EVENT_REASON_IO_INSTRUCTION,
+ .u.io.bytes = bytes,
+ .u.io.port = port,
+ .u.io.in = in,
+ .u.io.str = str,
+ };
+
+ if ( !ad->monitor.io_enabled )
+ return 0;
+
+ set_npt_base(curr, &req);
+
+ return monitor_traps(curr, true, &req);
+}
+
/*
* Local variables:
* mode: C
break;
case VMEXIT_IOIO:
+ rc = hvm_monitor_io(vmcb->ei.io.port,
+ vmcb->ei.io.bytes,
+ vmcb->ei.io.in,
+ vmcb->ei.io.str);
+ if ( rc < 0 )
+ goto unexpected_exit_type;
+ if ( rc )
+ break;
+
if ( !vmcb->ei.io.str )
{
if ( handle_pio(vmcb->ei.io.port,
};
} io_qual;
unsigned int bytes;
+ int rc;
__vmread(EXIT_QUALIFICATION, &io_qual.raw);
bytes = io_qual.size + 1;
+ rc = hvm_monitor_io(io_qual.port, bytes, io_qual.in, io_qual.str);
+ if ( rc < 0 )
+ goto exit_and_crash;
+ if ( rc )
+ break;
+
if ( io_qual.str )
{
if ( !hvm_emulate_one_insn(x86_insn_is_portio, "port I/O") )
unsigned int descriptor_access_enabled : 1;
unsigned int guest_request_userspace_enabled : 1;
unsigned int emul_unimplemented_enabled : 1;
+ unsigned int io_enabled : 1;
/*
* By default all events are sent.
* This is used to filter out pagefaults.
int hvm_monitor_vmexit(unsigned long exit_reason,
unsigned long exit_qualification);
+int hvm_monitor_io(unsigned int port, unsigned int bytes,
+ bool in, bool str);
+
#endif /* __ASM_X86_HVM_MONITOR_H__ */
/*
(1U << XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG) |
(1U << XEN_DOMCTL_MONITOR_EVENT_EMUL_UNIMPLEMENTED) |
(1U << XEN_DOMCTL_MONITOR_EVENT_INGUEST_PAGEFAULT) |
- (1U << XEN_DOMCTL_MONITOR_EVENT_VMEXIT));
+ (1U << XEN_DOMCTL_MONITOR_EVENT_VMEXIT) |
+ (1U << XEN_DOMCTL_MONITOR_EVENT_IO));
if ( hvm_is_singlestep_supported() )
capabilities |= (1U << XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP);
break;
}
+ case XEN_DOMCTL_MONITOR_EVENT_IO:
+ {
+ bool old_status = ad->monitor.io_enabled;
+
+ if ( unlikely(old_status == requested_status) )
+ return -EEXIST;
+
+ domain_pause(d);
+ ad->monitor.io_enabled = requested_status;
+ domain_unpause(d);
+ break;
+ }
+
default:
/*
* Should not be reached unless arch_monitor_get_capabilities() is
/* Enabled by default */
#define XEN_DOMCTL_MONITOR_EVENT_INGUEST_PAGEFAULT 11
#define XEN_DOMCTL_MONITOR_EVENT_VMEXIT 12
+#define XEN_DOMCTL_MONITOR_EVENT_IO 13
struct xen_domctl_monitor_op {
uint32_t op; /* XEN_DOMCTL_MONITOR_OP_* */
#define VM_EVENT_REASON_EMUL_UNIMPLEMENTED 14
/* VMEXIT */
#define VM_EVENT_REASON_VMEXIT 15
+/* IN/OUT Instruction executed */
+#define VM_EVENT_REASON_IO_INSTRUCTION 16
/* Supported values for the vm_event_write_ctrlreg index. */
#define VM_EVENT_X86_CR0 0
} arch;
};
+struct vm_event_io {
+ uint32_t bytes; /* size of access */
+ uint16_t port; /* port number */
+ uint8_t in; /* direction (0 = OUT, 1 = IN) */
+ uint8_t str; /* string instruction (0 = not string, 1 = string) */
+};
+
typedef struct vm_event_st {
uint32_t version; /* VM_EVENT_INTERFACE_VERSION */
uint32_t flags; /* VM_EVENT_FLAG_* */
struct vm_event_debug debug_exception;
struct vm_event_cpuid cpuid;
struct vm_event_vmexit vmexit;
+ struct vm_event_io io;
union {
struct vm_event_interrupt_x86 x86;
} interrupt;