aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xen/arch/x86/hvm/io.c6
-rw-r--r--xen/arch/x86/hvm/vmx/realmode.c62
-rw-r--r--xen/arch/x86/hvm/vmx/vmx.c1
-rw-r--r--xen/arch/x86/x86_emulate.c34
-rw-r--r--xen/include/asm-x86/hvm/vcpu.h3
-rw-r--r--xen/include/asm-x86/hvm/vmx/vmcs.h4
-rw-r--r--xen/include/asm-x86/hvm/vmx/vmx.h1
7 files changed, 102 insertions, 9 deletions
diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c
index fe54017012..f522d60378 100644
--- a/xen/arch/x86/hvm/io.c
+++ b/xen/arch/x86/hvm/io.c
@@ -841,13 +841,17 @@ void hvm_io_assist(void)
if ( p->state != STATE_IORESP_READY )
{
gdprintk(XENLOG_ERR, "Unexpected HVM iorequest state %d.\n", p->state);
- domain_crash_synchronous();
+ domain_crash(v->domain);
+ goto out;
}
rmb(); /* see IORESP_READY /then/ read contents of ioreq */
p->state = STATE_IOREQ_NONE;
+ if ( v->arch.hvm_vcpu.io_complete && v->arch.hvm_vcpu.io_complete() )
+ goto out;
+
switch ( p->type )
{
case IOREQ_TYPE_INVALIDATE:
diff --git a/xen/arch/x86/hvm/vmx/realmode.c b/xen/arch/x86/hvm/vmx/realmode.c
index 53ec8e64a2..49dac88840 100644
--- a/xen/arch/x86/hvm/vmx/realmode.c
+++ b/xen/arch/x86/hvm/vmx/realmode.c
@@ -178,7 +178,24 @@ realmode_read_io(
unsigned long *val,
struct x86_emulate_ctxt *ctxt)
{
- return X86EMUL_UNHANDLEABLE;
+ struct vcpu *curr = current;
+
+ if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
+ return X86EMUL_UNHANDLEABLE;
+
+ if ( !curr->arch.hvm_vmx.real_mode_io_completed )
+ {
+ curr->arch.hvm_vmx.real_mode_io_in_progress = 1;
+ send_pio_req(port, 1, bytes, 0, IOREQ_READ, 0, 0);
+ }
+
+ if ( !curr->arch.hvm_vmx.real_mode_io_completed )
+ return X86EMUL_UNHANDLEABLE;
+
+ *val = curr->arch.hvm_vmx.real_mode_io_data;
+ curr->arch.hvm_vmx.real_mode_io_completed = 0;
+
+ return X86EMUL_OKAY;
}
static int realmode_write_io(
@@ -187,7 +204,15 @@ static int realmode_write_io(
unsigned long val,
struct x86_emulate_ctxt *ctxt)
{
- return X86EMUL_UNHANDLEABLE;
+ struct vcpu *curr = current;
+
+ if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
+ return X86EMUL_UNHANDLEABLE;
+
+ curr->arch.hvm_vmx.real_mode_io_in_progress = 1;
+ send_pio_req(port, 1, bytes, val, IOREQ_WRITE, 0, 0);
+
+ return X86EMUL_OKAY;
}
static int
@@ -259,8 +284,19 @@ int vmx_realmode(struct cpu_user_regs *regs)
rm_ctxt.insn_buf[2], rm_ctxt.insn_buf[3],
rm_ctxt.insn_buf[4], rm_ctxt.insn_buf[5]);
- if ( x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops) )
- {
+ rc = x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops);
+
+ if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
+ {
+ ioreq_t *p = &get_ioreq(curr)->vp_ioreq;
+ gdprintk(XENLOG_DEBUG, "RM I/O %d %c addr=%lx data=%lx\n",
+ p->type, p->dir ? 'R' : 'W', p->addr, p->data);
+ rc = 0;
+ break;
+ }
+
+ if ( rc )
+ {
gdprintk(XENLOG_ERR, "Emulation failed\n");
rc = -EINVAL;
break;
@@ -272,3 +308,21 @@ int vmx_realmode(struct cpu_user_regs *regs)
return rc;
}
+
+int vmx_realmode_io_complete(void)
+{
+ struct vcpu *curr = current;
+ ioreq_t *p = &get_ioreq(curr)->vp_ioreq;
+
+ if ( !curr->arch.hvm_vmx.real_mode_io_in_progress )
+ return 0;
+
+ curr->arch.hvm_vmx.real_mode_io_in_progress = 0;
+ if ( p->dir == IOREQ_READ )
+ {
+ curr->arch.hvm_vmx.real_mode_io_completed = 1;
+ curr->arch.hvm_vmx.real_mode_io_data = p->data;
+ }
+
+ return 1;
+}
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index da266fffc1..b23e205f88 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -95,6 +95,7 @@ static int vmx_vcpu_initialise(struct vcpu *v)
#ifndef VMXASSIST
if ( v->vcpu_id == 0 )
v->arch.guest_context.user_regs.eax = 1;
+ v->arch.hvm_vcpu.io_complete = vmx_realmode_io_complete;
#endif
return 0;
diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c
index 48325f92fc..3ff12f8112 100644
--- a/xen/arch/x86/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate.c
@@ -264,6 +264,7 @@ struct operand {
};
/* EFLAGS bit definitions. */
+#define EFLG_VM (1<<17)
#define EFLG_RF (1<<16)
#define EFLG_OF (1<<11)
#define EFLG_DF (1<<10)
@@ -478,10 +479,6 @@ do { \
/* In future we will be able to generate arbitrary exceptions. */
#define generate_exception_if(p, e) fail_if(p)
-/* To be done... */
-#define mode_ring0() (0)
-#define mode_iopl() (0)
-
/* Given byte has even parity (even number of 1s)? */
static int even_parity(uint8_t v)
{
@@ -680,6 +677,35 @@ test_cc(
}
static int
+get_cpl(
+ struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
+{
+ struct segment_register reg;
+
+ if ( ctxt->regs->eflags & EFLG_VM )
+ return 3;
+
+ if ( (ops->read_segment == NULL) ||
+ ops->read_segment(x86_seg_ss, &reg, ctxt) )
+ return -1;
+
+ return reg.attr.fields.dpl;
+}
+
+static int
+_mode_iopl(
+ struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
+{
+ int cpl = get_cpl(ctxt, ops);
+ return ((cpl >= 0) && (cpl <= ((ctxt->regs->eflags >> 12) & 3)));
+}
+
+#define mode_ring0() (get_cpl(ctxt, ops) == 0)
+#define mode_iopl() _mode_iopl(ctxt, ops)
+
+static int
in_realmode(
struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops)
diff --git a/xen/include/asm-x86/hvm/vcpu.h b/xen/include/asm-x86/hvm/vcpu.h
index 5d653f0ff9..f6c55dba12 100644
--- a/xen/include/asm-x86/hvm/vcpu.h
+++ b/xen/include/asm-x86/hvm/vcpu.h
@@ -59,6 +59,9 @@ struct hvm_vcpu {
bool_t flag_dr_dirty;
bool_t debug_state_latch;
+ /* Callback function for I/O completion. */
+ int (*io_complete)(void);
+
union {
struct arch_vmx_struct vmx;
struct arch_svm_struct svm;
diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h
index 0654264b46..68d1819d32 100644
--- a/xen/include/asm-x86/hvm/vmx/vmcs.h
+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h
@@ -92,6 +92,10 @@ struct arch_vmx_struct {
unsigned long vmxassist_enabled:1;
unsigned long irqbase_mode:1;
unsigned char pm_irqbase[2];
+#else
+ bool_t real_mode_io_in_progress;
+ bool_t real_mode_io_completed;
+ unsigned long real_mode_io_data;
#endif
};
diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h
index f6846a1d30..4787226cd3 100644
--- a/xen/include/asm-x86/hvm/vmx/vmx.h
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h
@@ -34,6 +34,7 @@ void vmx_do_resume(struct vcpu *);
void set_guest_time(struct vcpu *v, u64 gtime);
void vmx_vlapic_msr_changed(struct vcpu *v);
int vmx_realmode(struct cpu_user_regs *regs);
+int vmx_realmode_io_complete(void);
/*
* Exit Reasons