diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-01-12 11:13:57 +0000 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-01-12 11:13:57 +0000 |
commit | bc6c5510dbaa5b3be862d28ee62e3acf6c35f0bb (patch) | |
tree | 7ebd131f56422eaf67302fcad0dfe2e46f843883 /xen/arch/x86/hvm/intercept.c | |
parent | 3790d2ab9b967c9c3dfdedb56c22bc01b07ffbc2 (diff) | |
download | xen-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.c | 71 |
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; |