aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/intercept.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-01-12 11:13:57 +0000
committerKeir Fraser <keir.fraser@citrix.com>2008-01-12 11:13:57 +0000
commitbc6c5510dbaa5b3be862d28ee62e3acf6c35f0bb (patch)
tree7ebd131f56422eaf67302fcad0dfe2e46f843883 /xen/arch/x86/hvm/intercept.c
parent3790d2ab9b967c9c3dfdedb56c22bc01b07ffbc2 (diff)
downloadxen-bc6c5510dbaa5b3be862d28ee62e3acf6c35f0bb.tar.gz
xen-bc6c5510dbaa5b3be862d28ee62e3acf6c35f0bb.tar.bz2
xen-bc6c5510dbaa5b3be862d28ee62e3acf6c35f0bb.zip
hvm: Improve in-Xen PIO emulation to better handle string PIO
instructions. Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/arch/x86/hvm/intercept.c')
-rw-r--r--xen/arch/x86/hvm/intercept.c71
1 files changed, 62 insertions, 9 deletions
diff --git a/xen/arch/x86/hvm/intercept.c b/xen/arch/x86/hvm/intercept.c
index 27d0cbc6ab..76a6dc11a1 100644
--- a/xen/arch/x86/hvm/intercept.c
+++ b/xen/arch/x86/hvm/intercept.c
@@ -247,6 +247,50 @@ int hvm_mmio_intercept(ioreq_t *p)
return 0;
}
+static int process_portio_intercept(portio_action_t action, ioreq_t *p)
+{
+ int rc = 1, i, sign = p->df ? -1 : 1;
+ uint32_t data;
+
+ if ( p->dir == IOREQ_READ )
+ {
+ if ( !p->data_is_ptr )
+ {
+ rc = action(IOREQ_READ, p->addr, p->size, &data);
+ p->data = data;
+ }
+ else
+ {
+ for ( i = 0; i < p->count; i++ )
+ {
+ rc = action(IOREQ_READ, p->addr, p->size, &data);
+ (void)hvm_copy_to_guest_phys(p->data + sign*i*p->size,
+ &data, p->size);
+ }
+ }
+ }
+ else /* p->dir == IOREQ_WRITE */
+ {
+ if ( !p->data_is_ptr )
+ {
+ data = p->data;
+ rc = action(IOREQ_WRITE, p->addr, p->size, &data);
+ }
+ else
+ {
+ for ( i = 0; i < p->count; i++ )
+ {
+ data = 0;
+ (void)hvm_copy_from_guest_phys(&data, p->data + sign*i*p->size,
+ p->size);
+ rc = action(IOREQ_WRITE, p->addr, p->size, &data);
+ }
+ }
+ }
+
+ return rc;
+}
+
/*
* Check if the request is handled inside xen
* return value: 0 --not handled; 1 --handled
@@ -255,28 +299,35 @@ int hvm_io_intercept(ioreq_t *p, int type)
{
struct vcpu *v = current;
struct hvm_io_handler *handler =
- &(v->domain->arch.hvm_domain.io_handler);
+ &v->domain->arch.hvm_domain.io_handler;
int i;
unsigned long addr, size;
if ( (type == HVM_PORTIO) && (dpci_ioport_intercept(p)) )
return 1;
- for (i = 0; i < handler->num_slot; i++) {
- if( type != handler->hdl_list[i].type)
+ for ( i = 0; i < handler->num_slot; i++ )
+ {
+ if ( type != handler->hdl_list[i].type )
continue;
addr = handler->hdl_list[i].addr;
size = handler->hdl_list[i].size;
- if (p->addr >= addr &&
- p->addr + p->size <= addr + size)
- return handler->hdl_list[i].action(p);
+ if ( (p->addr >= addr) &&
+ ((p->addr + p->size) <= (addr + size)) )
+ {
+ if ( type == HVM_PORTIO )
+ return process_portio_intercept(
+ handler->hdl_list[i].action.portio, p);
+ return handler->hdl_list[i].action.mmio(p);
+ }
}
+
return 0;
}
int register_io_handler(
struct domain *d, unsigned long addr, unsigned long size,
- intercept_action_t action, int type)
+ void *action, int type)
{
struct hvm_io_handler *handler = &d->arch.hvm_domain.io_handler;
int num = handler->num_slot;
@@ -285,8 +336,10 @@ int register_io_handler(
handler->hdl_list[num].addr = addr;
handler->hdl_list[num].size = size;
- handler->hdl_list[num].action = action;
- handler->hdl_list[num].type = type;
+ if ( (handler->hdl_list[num].type = type) == HVM_PORTIO )
+ handler->hdl_list[num].action.portio = action;
+ else
+ handler->hdl_list[num].action.mmio = action;
handler->num_slot++;
return 1;