From f21399e148386ecf3826ab81159eca58cfab2147 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 14 Oct 2013 09:50:16 +0200 Subject: x86/HVM: properly handle backward string instruction emulation Multiplying a signed 32-bit quantity with an unsigned 32-bit quantity produces an unsigned 32-bit result, yet for emulation of backward string instructions we need the result sign extended before getting added to the base address. Signed-off-by: Jan Beulich Reviewed-by: Andrew Cooper Acked-by: Keir Fraser --- xen/arch/x86/hvm/intercept.c | 23 ++++++++--------------- xen/arch/x86/hvm/io.c | 10 ++++------ xen/arch/x86/hvm/stdvga.c | 34 +++++++++++----------------------- 3 files changed, 23 insertions(+), 44 deletions(-) diff --git a/xen/arch/x86/hvm/intercept.c b/xen/arch/x86/hvm/intercept.c index 5bb1c17190..5ac08937d7 100644 --- a/xen/arch/x86/hvm/intercept.c +++ b/xen/arch/x86/hvm/intercept.c @@ -48,7 +48,7 @@ static int hvm_mmio_access(struct vcpu *v, hvm_mmio_write_t write_handler) { unsigned long data; - int rc = X86EMUL_OKAY, i, sign = p->df ? -1 : 1; + int rc = X86EMUL_OKAY, i, step = p->df ? -p->size : p->size; if ( !p->data_is_ptr ) { @@ -68,13 +68,10 @@ static int hvm_mmio_access(struct vcpu *v, { int ret; - rc = read_handler(v, p->addr + (sign * i * p->size), p->size, - &data); + rc = read_handler(v, p->addr + step * i, p->size, &data); if ( rc != X86EMUL_OKAY ) break; - ret = hvm_copy_to_guest_phys(p->data + (sign * i * p->size), - &data, - p->size); + ret = hvm_copy_to_guest_phys(p->data + step * i, &data, p->size); if ( (ret == HVMCOPY_gfn_paged_out) || (ret == HVMCOPY_gfn_shared) ) { @@ -87,8 +84,7 @@ static int hvm_mmio_access(struct vcpu *v, { for ( i = 0; i < p->count; i++ ) { - switch ( hvm_copy_from_guest_phys(&data, - p->data + sign * i * p->size, + switch ( hvm_copy_from_guest_phys(&data, p->data + step * i, p->size) ) { case HVMCOPY_okay: @@ -109,8 +105,7 @@ static int hvm_mmio_access(struct vcpu *v, } if ( rc != X86EMUL_OKAY ) break; - rc = write_handler(v, p->addr + (sign * i * p->size), p->size, - data); + rc = write_handler(v, p->addr + step * i, p->size, data); if ( rc != X86EMUL_OKAY ) break; } @@ -142,7 +137,7 @@ int hvm_mmio_intercept(ioreq_t *p) static int process_portio_intercept(portio_action_t action, ioreq_t *p) { - int rc = X86EMUL_OKAY, i, sign = p->df ? -1 : 1; + int rc = X86EMUL_OKAY, i, step = p->df ? -p->size : p->size; uint32_t data; if ( !p->data_is_ptr ) @@ -167,8 +162,7 @@ static int process_portio_intercept(portio_action_t action, ioreq_t *p) rc = action(IOREQ_READ, p->addr, p->size, &data); if ( rc != X86EMUL_OKAY ) break; - (void)hvm_copy_to_guest_phys(p->data + sign*i*p->size, - &data, p->size); + (void)hvm_copy_to_guest_phys(p->data + step * i, &data, p->size); } } else /* p->dir == IOREQ_WRITE */ @@ -176,8 +170,7 @@ static int process_portio_intercept(portio_action_t action, ioreq_t *p) for ( i = 0; i < p->count; i++ ) { data = 0; - switch ( hvm_copy_from_guest_phys(&data, - p->data + sign * i * p->size, + switch ( hvm_copy_from_guest_phys(&data, p->data + step * i, p->size) ) { case HVMCOPY_okay: diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c index 5f5009a179..77698c4db2 100644 --- a/xen/arch/x86/hvm/io.c +++ b/xen/arch/x86/hvm/io.c @@ -294,7 +294,7 @@ void hvm_io_assist(void) static int dpci_ioport_read(uint32_t mport, ioreq_t *p) { - int i, sign = p->df ? -1 : 1; + int i, step = p->df ? -p->size : p->size; uint32_t data = 0; for ( i = 0; i < p->count; i++ ) @@ -317,8 +317,7 @@ static int dpci_ioport_read(uint32_t mport, ioreq_t *p) if ( p->data_is_ptr ) { int ret; - ret = hvm_copy_to_guest_phys(p->data + (sign * i * p->size), &data, - p->size); + ret = hvm_copy_to_guest_phys(p->data + step * i, &data, p->size); if ( (ret == HVMCOPY_gfn_paged_out) || (ret == HVMCOPY_gfn_shared) ) return X86EMUL_RETRY; @@ -332,7 +331,7 @@ static int dpci_ioport_read(uint32_t mport, ioreq_t *p) static int dpci_ioport_write(uint32_t mport, ioreq_t *p) { - int i, sign = p->df ? -1 : 1; + int i, step = p->df ? -p->size : p->size; uint32_t data; for ( i = 0; i < p->count; i++ ) @@ -340,8 +339,7 @@ static int dpci_ioport_write(uint32_t mport, ioreq_t *p) data = p->data; if ( p->data_is_ptr ) { - switch ( hvm_copy_from_guest_phys(&data, - p->data + sign * i * p->size, + switch ( hvm_copy_from_guest_phys(&data, p->data + step * i, p->size) ) { case HVMCOPY_okay: diff --git a/xen/arch/x86/hvm/stdvga.c b/xen/arch/x86/hvm/stdvga.c index 331fca0ff4..19e80ed607 100644 --- a/xen/arch/x86/hvm/stdvga.c +++ b/xen/arch/x86/hvm/stdvga.c @@ -467,15 +467,17 @@ static uint32_t read_data; static int mmio_move(struct hvm_hw_stdvga *s, ioreq_t *p) { int i; - int sign = p->df ? -1 : 1; + uint64_t addr = p->addr; p2m_type_t p2mt; struct domain *d = current->domain; if ( p->data_is_ptr ) { + uint64_t data = p->data, tmp; + int step = p->df ? -p->size : p->size; + if ( p->dir == IOREQ_READ ) { - uint64_t addr = p->addr, data = p->data, tmp; for ( i = 0; i < p->count; i++ ) { tmp = stdvga_mem_read(addr, p->size); @@ -498,13 +500,12 @@ static int mmio_move(struct hvm_hw_stdvga *s, ioreq_t *p) ASSERT(!dp); stdvga_mem_write(data, tmp, p->size); } - data += sign * p->size; - addr += sign * p->size; + data += step; + addr += step; } } else { - uint32_t addr = p->addr, data = p->data, tmp; for ( i = 0; i < p->count; i++ ) { if ( hvm_copy_from_guest_phys(&tmp, data, p->size) != @@ -523,31 +524,18 @@ static int mmio_move(struct hvm_hw_stdvga *s, ioreq_t *p) tmp = stdvga_mem_read(data, p->size); } stdvga_mem_write(addr, tmp, p->size); - data += sign * p->size; - addr += sign * p->size; + data += step; + addr += step; } } } else { + ASSERT(p->count == 1); if ( p->dir == IOREQ_READ ) - { - uint32_t addr = p->addr; - for ( i = 0; i < p->count; i++ ) - { - p->data = stdvga_mem_read(addr, p->size); - addr += sign * p->size; - } - } + p->data = stdvga_mem_read(addr, p->size); else - { - uint32_t addr = p->addr; - for ( i = 0; i < p->count; i++ ) - { - stdvga_mem_write(addr, p->data, p->size); - addr += sign * p->size; - } - } + stdvga_mem_write(addr, p->data, p->size); } read_data = p->data; -- cgit v1.2.3