[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] hvm: Improve in-Xen PIO emulation to better handle string PIO
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1200136437 0 # Node ID 9862217f3c34a8f941cf0b3eaebd3c0b042815d9 # Parent a30aabe3c84a71404202f6b18d06cb313842ee23 hvm: Improve in-Xen PIO emulation to better handle string PIO instructions. Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx> --- xen/arch/x86/hvm/i8254.c | 37 ++++++++++-------- xen/arch/x86/hvm/intercept.c | 73 +++++++++++++++++++++++++++++++----- xen/arch/x86/hvm/pmtimer.c | 29 +++++++------- xen/arch/x86/hvm/rtc.c | 13 +++--- xen/arch/x86/hvm/stdvga.c | 37 ++++++++---------- xen/arch/x86/hvm/vpic.c | 85 ++++++++++++++++--------------------------- xen/include/asm-x86/hvm/io.h | 17 +++++--- 7 files changed, 164 insertions(+), 127 deletions(-) diff -r a30aabe3c84a -r 9862217f3c34 xen/arch/x86/hvm/i8254.c --- a/xen/arch/x86/hvm/i8254.c Sat Jan 12 09:29:38 2008 +0000 +++ b/xen/arch/x86/hvm/i8254.c Sat Jan 12 11:13:57 2008 +0000 @@ -48,8 +48,10 @@ #define RW_STATE_WORD0 3 #define RW_STATE_WORD1 4 -static int handle_pit_io(ioreq_t *p); -static int handle_speaker_io(ioreq_t *p); +static int handle_pit_io( + int dir, uint32_t port, uint32_t bytes, uint32_t *val); +static int handle_speaker_io( + int dir, uint32_t port, uint32_t bytes, uint32_t *val); /* Compute with 96 bit intermediate result: (a*b)/c */ static uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) @@ -525,24 +527,25 @@ void pit_deinit(struct domain *d) } /* the intercept action for PIT DM retval:0--not handled; 1--handled */ -static int handle_pit_io(ioreq_t *p) +static int handle_pit_io( + int dir, uint32_t port, uint32_t bytes, uint32_t *val) { struct PITState *vpit = vcpu_vpit(current); - if ( (p->size != 1) || p->data_is_ptr || (p->type != IOREQ_TYPE_PIO) ) + if ( bytes != 1 ) { gdprintk(XENLOG_WARNING, "PIT bad access\n"); return 1; } - if ( p->dir == IOREQ_WRITE ) - { - pit_ioport_write(vpit, p->addr, p->data); + if ( dir == IOREQ_WRITE ) + { + pit_ioport_write(vpit, port, *val); } else { - if ( (p->addr & 3) != 3 ) - p->data = pit_ioport_read(vpit, p->addr); + if ( (port & 3) != 3 ) + *val = pit_ioport_read(vpit, port); else gdprintk(XENLOG_WARNING, "PIT: read A1:A0=3!\n"); } @@ -566,11 +569,12 @@ static uint32_t speaker_ioport_read( (pit_get_out(pit, 2) << 5) | (refresh_clock << 4)); } -static int handle_speaker_io(ioreq_t *p) +static int handle_speaker_io( + int dir, uint32_t port, uint32_t bytes, uint32_t *val) { struct PITState *vpit = vcpu_vpit(current); - if ( (p->size != 1) || p->data_is_ptr || (p->type != IOREQ_TYPE_PIO) ) + if ( bytes != 1 ) { gdprintk(XENLOG_WARNING, "PIT_SPEAKER bad access\n"); return 1; @@ -578,10 +582,10 @@ static int handle_speaker_io(ioreq_t *p) spin_lock(&vpit->lock); - if ( p->dir == IOREQ_WRITE ) - speaker_ioport_write(vpit, p->addr, p->data); + if ( dir == IOREQ_WRITE ) + speaker_ioport_write(vpit, port, *val); else - p->data = speaker_ioport_read(vpit, p->addr); + *val = speaker_ioport_read(vpit, port); spin_unlock(&vpit->lock); @@ -597,13 +601,14 @@ int pv_pit_handler(int port, int data, i .dir = write ? IOREQ_WRITE : IOREQ_READ, .data = data }; + uint32_t val = data; if ( (current->domain->domain_id == 0) && dom0_pit_access(&ioreq) ) /* nothing to do */; else if ( port == 0x61 ) - handle_speaker_io(&ioreq); + handle_speaker_io(ioreq.dir, port, 1, &val); else - handle_pit_io(&ioreq); + handle_pit_io(ioreq.dir, port, 1, &val); return !write ? ioreq.data : 0; } diff -r a30aabe3c84a -r 9862217f3c34 xen/arch/x86/hvm/intercept.c --- a/xen/arch/x86/hvm/intercept.c Sat Jan 12 09:29:38 2008 +0000 +++ b/xen/arch/x86/hvm/intercept.c Sat Jan 12 11:13:57 2008 +0000 @@ -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 typ { 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; diff -r a30aabe3c84a -r 9862217f3c34 xen/arch/x86/hvm/pmtimer.c --- a/xen/arch/x86/hvm/pmtimer.c Sat Jan 12 09:29:38 2008 +0000 +++ b/xen/arch/x86/hvm/pmtimer.c Sat Jan 12 11:13:57 2008 +0000 @@ -114,7 +114,8 @@ static void pmt_timer_callback(void *opa } /* Handle port I/O to the PM1a_STS and PM1a_EN registers */ -static int handle_evt_io(ioreq_t *p) +static int handle_evt_io( + int dir, uint32_t port, uint32_t bytes, uint32_t *val) { struct vcpu *v = current; PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt; @@ -123,10 +124,10 @@ static int handle_evt_io(ioreq_t *p) spin_lock(&s->lock); - if ( p->dir == IOREQ_WRITE ) + if ( dir == IOREQ_WRITE ) { /* Handle this I/O one byte at a time */ - for ( i = p->size, addr = p->addr, data = p->data; + for ( i = bytes, addr = port, data = *val; i > 0; i--, addr++, data >>= 8 ) { @@ -150,9 +151,8 @@ static int handle_evt_io(ioreq_t *p) default: gdprintk(XENLOG_WARNING, - "Bad ACPI PM register write: %"PRIu64 - " bytes (%#"PRIx64") at %"PRIx64"\n", - p->size, p->data, p->addr); + "Bad ACPI PM register write: %x bytes (%x) at %x\n", + bytes, *val, port); } } /* Fix up the SCI state to match the new register state */ @@ -161,10 +161,10 @@ static int handle_evt_io(ioreq_t *p) else /* p->dir == IOREQ_READ */ { data = s->pm.pm1a_sts | (((uint32_t) s->pm.pm1a_en) << 16); - data >>= 8 * (p->addr - PM1a_STS_ADDR); - if ( p->size == 1 ) data &= 0xff; - else if ( p->size == 2 ) data &= 0xffff; - p->data = data; + data >>= 8 * (port - PM1a_STS_ADDR); + if ( bytes == 1 ) data &= 0xff; + else if ( bytes == 2 ) data &= 0xffff; + *val = data; } spin_unlock(&s->lock); @@ -174,22 +174,23 @@ static int handle_evt_io(ioreq_t *p) /* Handle port I/O to the TMR_VAL register */ -static int handle_pmt_io(ioreq_t *p) +static int handle_pmt_io( + int dir, uint32_t port, uint32_t bytes, uint32_t *val) { struct vcpu *v = current; PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt; - if ( (p->size != 4) || p->data_is_ptr || (p->type != IOREQ_TYPE_PIO) ) + if ( bytes != 4 ) { gdprintk(XENLOG_WARNING, "HVM_PMT bad access\n"); return 1; } - if ( p->dir == IOREQ_READ ) + if ( dir == IOREQ_READ ) { spin_lock(&s->lock); pmt_update_time(s); - p->data = s->pm.tmr_val; + *val = s->pm.tmr_val; spin_unlock(&s->lock); return 1; } diff -r a30aabe3c84a -r 9862217f3c34 xen/arch/x86/hvm/rtc.c --- a/xen/arch/x86/hvm/rtc.c Sat Jan 12 09:29:38 2008 +0000 +++ b/xen/arch/x86/hvm/rtc.c Sat Jan 12 11:13:57 2008 +0000 @@ -395,24 +395,25 @@ static uint32_t rtc_ioport_read(RTCState return ret; } -static int handle_rtc_io(ioreq_t *p) +static int handle_rtc_io( + int dir, uint32_t port, uint32_t bytes, uint32_t *val) { struct RTCState *vrtc = vcpu_vrtc(current); - if ( (p->size != 1) || p->data_is_ptr || (p->type != IOREQ_TYPE_PIO) ) + if ( bytes != 1 ) { gdprintk(XENLOG_WARNING, "HVM_RTC bas access\n"); return 1; } - if ( p->dir == IOREQ_WRITE ) - { - if ( rtc_ioport_write(vrtc, p->addr, p->data & 0xFF) ) + if ( dir == IOREQ_WRITE ) + { + if ( rtc_ioport_write(vrtc, port, (uint8_t)*val) ) return 1; } else if ( vrtc->hw.cmos_index < RTC_CMOS_SIZE ) { - p->data = rtc_ioport_read(vrtc, p->addr); + *val = rtc_ioport_read(vrtc, port); return 1; } diff -r a30aabe3c84a -r 9862217f3c34 xen/arch/x86/hvm/stdvga.c --- a/xen/arch/x86/hvm/stdvga.c Sat Jan 12 09:29:38 2008 +0000 +++ b/xen/arch/x86/hvm/stdvga.c Sat Jan 12 11:13:57 2008 +0000 @@ -148,42 +148,37 @@ static int stdvga_outb(uint64_t addr, ui return rc; } -static int stdvga_out(ioreq_t *p) -{ - int rc = 1; - - switch ( p->size ) +static void stdvga_out(uint32_t port, uint32_t bytes, uint32_t val) +{ + switch ( bytes ) { case 1: - rc &= stdvga_outb(p->addr, p->data); + stdvga_outb(port, val); break; case 2: - rc &= stdvga_outb(p->addr + 0, p->data >> 0); - rc &= stdvga_outb(p->addr + 1, p->data >> 8); + stdvga_outb(port + 0, val >> 0); + stdvga_outb(port + 1, val >> 8); break; default: - rc = 0; - break; - } - - return rc; -} - -int stdvga_intercept_pio(ioreq_t *p) + break; + } +} + +int stdvga_intercept_pio( + int dir, uint32_t port, uint32_t bytes, uint32_t *val) { struct hvm_hw_stdvga *s = ¤t->domain->arch.hvm_domain.stdvga; - int rc; - - if ( p->data_is_ptr || (p->dir == IOREQ_READ) ) + + if ( dir == IOREQ_READ ) return 0; spin_lock(&s->lock); - rc = (stdvga_out(p) && hvm_buffered_io_send(p)); + stdvga_out(port, bytes, *val); spin_unlock(&s->lock); - return rc; + return 0; /* propagate to external ioemu */ } #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff) diff -r a30aabe3c84a -r 9862217f3c34 xen/arch/x86/hvm/vpic.c --- a/xen/arch/x86/hvm/vpic.c Sat Jan 12 09:29:38 2008 +0000 +++ b/xen/arch/x86/hvm/vpic.c Sat Jan 12 11:13:57 2008 +0000 @@ -316,61 +316,45 @@ static uint32_t vpic_ioport_read(struct return vpic->imr; } -static int vpic_intercept_pic_io(ioreq_t *p) +static int vpic_intercept_pic_io( + int dir, uint32_t port, uint32_t bytes, uint32_t *val) +{ + struct hvm_hw_vpic *vpic; + + if ( bytes != 1 ) + { + gdprintk(XENLOG_WARNING, "PIC_IO bad access size %d\n", bytes); + return 1; + } + + vpic = ¤t->domain->arch.hvm_domain.vpic[port >> 7]; + + if ( dir == IOREQ_WRITE ) + vpic_ioport_write(vpic, port, (uint8_t)*val); + else + *val = (uint8_t)vpic_ioport_read(vpic, port); + + return 1; +} + +static int vpic_intercept_elcr_io( + int dir, uint32_t port, uint32_t bytes, uint32_t *val) { struct hvm_hw_vpic *vpic; uint32_t data; - if ( (p->size != 1) || (p->count != 1) ) - { - gdprintk(XENLOG_WARNING, "PIC_IO bad access size %d\n", (int)p->size); + if ( bytes != 1 ) + { + gdprintk(XENLOG_WARNING, "PIC_IO bad access size %d\n", bytes); return 1; } - vpic = ¤t->domain->arch.hvm_domain.vpic[p->addr >> 7]; - - if ( p->dir == IOREQ_WRITE ) - { - if ( p->data_is_ptr ) - (void)hvm_copy_from_guest_phys(&data, p->data, p->size); - else - data = p->data; - vpic_ioport_write(vpic, (uint32_t)p->addr, (uint8_t)data); - } - else - { - data = vpic_ioport_read(vpic, (uint32_t)p->addr); - if ( p->data_is_ptr ) - (void)hvm_copy_to_guest_phys(p->data, &data, p->size); - else - p->data = (u64)data; - } - - return 1; -} - -static int vpic_intercept_elcr_io(ioreq_t *p) -{ - struct hvm_hw_vpic *vpic; - uint32_t data; - - if ( (p->size != 1) || (p->count != 1) ) - { - gdprintk(XENLOG_WARNING, "PIC_IO bad access size %d\n", (int)p->size); - return 1; - } - - vpic = ¤t->domain->arch.hvm_domain.vpic[p->addr & 1]; - - if ( p->dir == IOREQ_WRITE ) - { - if ( p->data_is_ptr ) - (void)hvm_copy_from_guest_phys(&data, p->data, p->size); - else - data = p->data; - + vpic = ¤t->domain->arch.hvm_domain.vpic[port & 1]; + + if ( dir == IOREQ_WRITE ) + { /* Some IRs are always edge trig. Slave IR is always level trig. */ - data &= vpic_elcr_mask(vpic); + data = *val & vpic_elcr_mask(vpic); if ( vpic->is_master ) data |= 1 << 2; vpic->elcr = data; @@ -378,12 +362,7 @@ static int vpic_intercept_elcr_io(ioreq_ else { /* Reader should not see hardcoded level-triggered slave IR. */ - data = vpic->elcr & vpic_elcr_mask(vpic); - - if ( p->data_is_ptr ) - (void)hvm_copy_to_guest_phys(p->data, &data, p->size); - else - p->data = data; + *val = vpic->elcr & vpic_elcr_mask(vpic); } return 1; diff -r a30aabe3c84a -r 9862217f3c34 xen/include/asm-x86/hvm/io.h --- a/xen/include/asm-x86/hvm/io.h Sat Jan 12 09:29:38 2008 +0000 +++ b/xen/include/asm-x86/hvm/io.h Sat Jan 12 11:13:57 2008 +0000 @@ -86,23 +86,26 @@ struct hvm_io_op { #define HVM_MMIO 1 #define HVM_BUFFERED_IO 2 -typedef int (*intercept_action_t)(ioreq_t *); typedef unsigned long (*hvm_mmio_read_t)(struct vcpu *v, unsigned long addr, unsigned long length); - typedef void (*hvm_mmio_write_t)(struct vcpu *v, unsigned long addr, unsigned long length, unsigned long val); - typedef int (*hvm_mmio_check_t)(struct vcpu *v, unsigned long addr); +typedef int (*portio_action_t)( + int dir, uint32_t port, uint32_t bytes, uint32_t *val); +typedef int (*mmio_action_t)(ioreq_t *); struct io_handler { int type; unsigned long addr; unsigned long size; - intercept_action_t action; + union { + portio_action_t portio; + mmio_action_t mmio; + } action; }; struct hvm_io_handler { @@ -120,7 +123,7 @@ extern int hvm_io_intercept(ioreq_t *p, extern int hvm_io_intercept(ioreq_t *p, int type); extern int register_io_handler( struct domain *d, unsigned long addr, unsigned long size, - intercept_action_t action, int type); + void *action, int type); static inline int hvm_portio_intercept(ioreq_t *p) { @@ -137,14 +140,14 @@ extern int hvm_buffered_io_send(ioreq_t static inline int register_portio_handler( struct domain *d, unsigned long addr, - unsigned long size, intercept_action_t action) + unsigned long size, portio_action_t action) { return register_io_handler(d, addr, size, action, HVM_PORTIO); } static inline int register_buffered_io_handler( struct domain *d, unsigned long addr, - unsigned long size, intercept_action_t action) + unsigned long size, mmio_action_t action) { return register_io_handler(d, addr, size, action, HVM_BUFFERED_IO); } _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |