# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1200137207 0
# Node ID d381e9278086085586b7afe20ecabe384be35876
# Parent 927fb0b1201ca9cb5436404abdd85bd215bc7ca5
hvm: Improve in-Xen PIO emulation to better handle string PIO
instructions.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
xen-unstable changeset: 16709:9862217f3c34
xen-unstable date: Sat Jan 12 11:13:57 2008 +0000
---
xen/arch/x86/hvm/i8254.c | 51 ++++++++++++-------------
xen/arch/x86/hvm/intercept.c | 70 ++++++++++++++++++++++++++++++-----
xen/arch/x86/hvm/pmtimer.c | 29 +++++++-------
xen/arch/x86/hvm/rtc.c | 13 +++---
xen/arch/x86/hvm/vpic.c | 85 ++++++++++++++++---------------------------
xen/include/asm-x86/hvm/io.h | 15 ++++---
6 files changed, 149 insertions(+), 114 deletions(-)
diff -r 927fb0b1201c -r d381e9278086 xen/arch/x86/hvm/i8254.c
--- a/xen/arch/x86/hvm/i8254.c Sat Jan 12 09:38:25 2008 +0000
+++ b/xen/arch/x86/hvm/i8254.c Sat Jan 12 11:26:47 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)
@@ -530,24 +532,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");
}
@@ -571,11 +574,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;
@@ -583,10 +587,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);
@@ -595,18 +599,13 @@ static int handle_speaker_io(ioreq_t *p)
int pv_pit_handler(int port, int data, int write)
{
- ioreq_t ioreq = {
- .size = 1,
- .type = IOREQ_TYPE_PIO,
- .addr = port,
- .dir = write ? 0 : 1,
- .data = write ? data : 0,
- };
+ int dir = write ? IOREQ_WRITE : IOREQ_READ;
+ uint32_t val = data;
if ( port == 0x61 )
- handle_speaker_io(&ioreq);
+ handle_speaker_io(dir, port, 1, &val);
else
- handle_pit_io(&ioreq);
-
- return !write ? ioreq.data : 0;
-}
+ handle_pit_io(dir, port, 1, &val);
+
+ return !write ? val : 0;
+}
diff -r 927fb0b1201c -r d381e9278086 xen/arch/x86/hvm/intercept.c
--- a/xen/arch/x86/hvm/intercept.c Sat Jan 12 09:38:25 2008 +0000
+++ b/xen/arch/x86/hvm/intercept.c Sat Jan 12 11:26:47 2008 +0000
@@ -231,6 +231,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
@@ -239,25 +283,31 @@ 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;
- 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 < 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;
@@ -266,8 +316,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 927fb0b1201c -r d381e9278086 xen/arch/x86/hvm/pmtimer.c
--- a/xen/arch/x86/hvm/pmtimer.c Sat Jan 12 09:38:25 2008 +0000
+++ b/xen/arch/x86/hvm/pmtimer.c Sat Jan 12 11:26:47 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 927fb0b1201c -r d381e9278086 xen/arch/x86/hvm/rtc.c
--- a/xen/arch/x86/hvm/rtc.c Sat Jan 12 09:38:25 2008 +0000
+++ b/xen/arch/x86/hvm/rtc.c Sat Jan 12 11:26:47 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 927fb0b1201c -r d381e9278086 xen/arch/x86/hvm/vpic.c
--- a/xen/arch/x86/hvm/vpic.c Sat Jan 12 09:38:25 2008 +0000
+++ b/xen/arch/x86/hvm/vpic.c Sat Jan 12 11:26:47 2008 +0000
@@ -311,61 +311,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;
@@ -373,12 +357,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 927fb0b1201c -r d381e9278086 xen/include/asm-x86/hvm/io.h
--- a/xen/include/asm-x86/hvm/io.h Sat Jan 12 09:38:25 2008 +0000
+++ b/xen/include/asm-x86/hvm/io.h Sat Jan 12 11:26:47 2008 +0000
@@ -85,23 +85,26 @@ struct hvm_io_op {
#define HVM_PORTIO 0
#define HVM_MMIO 1
-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 {
@@ -119,7 +122,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)
{
@@ -132,7 +135,7 @@ extern int hvm_buffered_io_intercept(ior
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);
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|