From: ddugger@redhat.com <ddugger@redhat.com> Date: Mon, 23 Mar 2009 10:23:01 -0600 Subject: [xen] x86: intercept I/O for assigned device Message-id: 200903231623.n2NGN14a022058@sobek.n0ano.com O-Subject: [RHEL5.4 PATCH 6/21 V2] Intercept I/O for assigned device Bugzilla: 484227 RH-Acked-by: Chris Lalancette <clalance@redhat.com> RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com> RH-Acked-by: Chris Lalancette <clalance@redhat.com> hook pio for assigned devices, thus improve pio performance. Upstream Status: Accepted (CS 15904, 17452) BZ: 484227 Signed-off-by: Weidong Han <weidong.han@intel.com> Signed-off-by: Gerd Hoffman <kraxel@redhat.com> Signed-off-by: Don Dugger <donald.d.dugger@intel.com> diff --git a/arch/x86/hvm/intercept.c b/arch/x86/hvm/intercept.c index e9712ce..e555f3c 100644 --- a/arch/x86/hvm/intercept.c +++ b/arch/x86/hvm/intercept.c @@ -243,6 +243,9 @@ int hvm_io_intercept(ioreq_t *p, int type) 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) continue; diff --git a/arch/x86/hvm/io.c b/arch/x86/hvm/io.c index 97e1215..b9b5f62 100644 --- a/arch/x86/hvm/io.c +++ b/arch/x86/hvm/io.c @@ -43,6 +43,7 @@ #include <public/sched.h> #include <public/hvm/ioreq.h> +#include <xen/iocap.h> #if defined (__i386__) static void set_reg_value (int size, int index, int seg, struct cpu_user_regs *regs, long value) @@ -873,6 +874,108 @@ void hvm_io_assist(void) vcpu_end_shutdown_deferral(v); } +void dpci_ioport_read(uint32_t mport, ioreq_t *p) +{ + int i, sign = p->df ? -1 : 1; + uint32_t data = 0; + + for ( i = 0; i < p->count; i++ ) + { + switch ( p->size ) + { + case 1: + data = inb(mport); + break; + case 2: + data = inw(mport); + break; + case 4: + data = inl(mport); + break; + default: + BUG(); + } + + if ( p->data_is_ptr ) + (void)hvm_copy_to_guest_phys( + p->data + (sign * i * p->size), &data, p->size); + else + p->data = data; + } +} + +void dpci_ioport_write(uint32_t mport, ioreq_t *p) +{ + int i, sign = p->df ? -1 : 1; + uint32_t data; + + for ( i = 0; i < p->count; i++ ) + { + data = p->data; + if ( p->data_is_ptr ) + (void)hvm_copy_from_guest_phys( + &data, p->data + (sign * i * p->size), p->size); + + switch ( p->size ) + { + case 1: + outb(data, mport); + break; + case 2: + outw(data, mport); + break; + case 4: + outl(data, mport); + break; + default: + BUG(); + } + } +} + +int dpci_ioport_intercept(ioreq_t *p) +{ + struct domain *d = current->domain; + struct hvm_iommu *hd = domain_hvm_iommu(d); + struct g2m_ioport *g2m_ioport; + unsigned int mport, gport = p->addr; + unsigned int s = 0, e = 0; + + list_for_each_entry( g2m_ioport, &hd->g2m_ioport_list, list ) + { + s = g2m_ioport->gport; + e = s + g2m_ioport->np; + if ( (gport >= s) && (gport < e) ) + goto found; + } + + return 0; + + found: + mport = (gport - s) + g2m_ioport->mport; + + if ( !ioports_access_permitted(d, mport, mport + p->size - 1) ) + { + gdprintk(XENLOG_ERR, "Error: access to gport=0x%x denied!\n", + (uint32_t)p->addr); + return 0; + } + + switch ( p->dir ) + { + case IOREQ_READ: + dpci_ioport_read(mport, p); + break; + case IOREQ_WRITE: + dpci_ioport_write(mport, p); + break; + default: + gdprintk(XENLOG_ERR, "Error: couldn't handle p->dir = %d", p->dir); + } + + return 1; +} + /* * Local variables: * mode: C