diff --git a/xen/arch/x86/hvm/intercept.c b/xen/arch/x86/hvm/intercept.c index 5bb1c17190..21fd33fb31 100644 --- a/xen/arch/x86/hvm/intercept.c +++ b/xen/arch/x86/hvm/intercept.c @@ -131,11 +131,24 @@ int hvm_mmio_intercept(ioreq_t *p) int i; for ( i = 0; i < HVM_MMIO_HANDLER_NR; i++ ) - if ( hvm_mmio_handlers[i]->check_handler(v, p->addr) ) + { + hvm_mmio_check_t check_handler = + hvm_mmio_handlers[i]->check_handler; + + if ( check_handler(v, p->addr) ) + { + if ( unlikely(p->count > 1) && + !check_handler(v, unlikely(p->df) + ? p->addr - (p->count - 1L) * p->size + : p->addr + (p->count - 1L) * p->size) ) + p->count = 1; + return hvm_mmio_access( v, p, hvm_mmio_handlers[i]->read_handler, hvm_mmio_handlers[i]->write_handler); + } + } return X86EMUL_UNHANDLEABLE; } @@ -243,6 +256,13 @@ int hvm_io_intercept(ioreq_t *p, int type) if ( type == HVM_PORTIO ) return process_portio_intercept( handler->hdl_list[i].action.portio, p); + + if ( unlikely(p->count > 1) && + (unlikely(p->df) + ? p->addr - (p->count - 1L) * p->size < addr + : p->addr + p->count * 1L * p->size - 1 >= addr + size) ) + p->count = 1; + return handler->hdl_list[i].action.mmio(p); } } diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c index 2bda25cd24..f158a2e0f5 100644 --- a/xen/arch/x86/hvm/vmsi.c +++ b/xen/arch/x86/hvm/vmsi.c @@ -235,6 +235,8 @@ static int msixtbl_read( rcu_read_lock(&msixtbl_rcu_lock); entry = msixtbl_find_entry(v, address); + if ( !entry ) + goto out; offset = address & (PCI_MSIX_ENTRY_SIZE - 1); if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET ) @@ -277,6 +279,8 @@ static int msixtbl_write(struct vcpu *v, unsigned long address, rcu_read_lock(&msixtbl_rcu_lock); entry = msixtbl_find_entry(v, address); + if ( !entry ) + goto out; nr_entry = (address - entry->gtable) / PCI_MSIX_ENTRY_SIZE; offset = address & (PCI_MSIX_ENTRY_SIZE - 1);