diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index ddc800791e..20b12d05f4 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -95,7 +95,7 @@ static const struct hvm_io_handler null_handler = { }; static int hvmemul_do_io( - bool_t is_mmio, paddr_t addr, unsigned long reps, unsigned int size, + bool_t is_mmio, paddr_t addr, unsigned long *reps, unsigned int size, uint8_t dir, bool_t df, bool_t data_is_addr, uintptr_t data) { struct vcpu *curr = current; @@ -104,7 +104,7 @@ static int hvmemul_do_io( .type = is_mmio ? IOREQ_TYPE_COPY : IOREQ_TYPE_PIO, .addr = addr, .size = size, - .count = reps, + .count = *reps, .dir = dir, .df = df, .data = data, @@ -136,7 +136,7 @@ static int hvmemul_do_io( if ( (p.type != is_mmio ? IOREQ_TYPE_COPY : IOREQ_TYPE_PIO) || (p.addr != addr) || (p.size != size) || - (p.count != reps) || + (p.count != *reps) || (p.dir != dir) || (p.df != df) || (p.data_is_ptr != data_is_addr) ) @@ -214,7 +214,7 @@ static int hvmemul_do_io_buffer( BUG_ON(buffer == NULL); - rc = hvmemul_do_io(is_mmio, addr, *reps, size, dir, df, 0, + rc = hvmemul_do_io(is_mmio, addr, reps, size, dir, df, 0, (uintptr_t)buffer); if ( rc == X86EMUL_UNHANDLEABLE && dir == IOREQ_READ ) memset(buffer, 0xff, size); @@ -305,13 +305,13 @@ static int hvmemul_do_io_addr( count = 1; } - rc = hvmemul_do_io(is_mmio, addr, count, size, dir, df, 1, + rc = hvmemul_do_io(is_mmio, addr, &count, size, dir, df, 1, ram_gpa); + if ( rc == X86EMUL_OKAY ) - { v->arch.hvm_vcpu.hvm_io.mmio_retry = (count < *reps); - *reps = count; - } + + *reps = count; out: while ( nr_pages ) diff --git a/xen/arch/x86/hvm/intercept.c b/xen/arch/x86/hvm/intercept.c index 7096d74c77..3a7a7dd33a 100644 --- a/xen/arch/x86/hvm/intercept.c +++ b/xen/arch/x86/hvm/intercept.c @@ -148,8 +148,8 @@ int hvm_process_io_intercept(const struct hvm_io_handler *handler, ASSERT_UNREACHABLE(); /* fall through */ default: - rc = X86EMUL_UNHANDLEABLE; - break; + domain_crash(current->domain); + return X86EMUL_UNHANDLEABLE; } if ( rc != X86EMUL_OKAY ) break; @@ -178,8 +178,8 @@ int hvm_process_io_intercept(const struct hvm_io_handler *handler, ASSERT_UNREACHABLE(); /* fall through */ default: - rc = X86EMUL_UNHANDLEABLE; - break; + domain_crash(current->domain); + return X86EMUL_UNHANDLEABLE; } if ( rc != X86EMUL_OKAY ) break; @@ -196,8 +196,20 @@ int hvm_process_io_intercept(const struct hvm_io_handler *handler, } } - if ( i != 0 && rc == X86EMUL_UNHANDLEABLE ) - domain_crash(current->domain); + if ( i ) + { + p->count = i; + rc = X86EMUL_OKAY; + } + else if ( rc == X86EMUL_UNHANDLEABLE ) + { + /* + * Don't forward entire batches to the device model: This would + * prevent the internal handlers to see subsequent iterations of + * the request. + */ + p->count = 1; + } return rc; }