diff options
author | Jan Beulich <jbeulich@suse.com> | 2013-10-14 09:50:16 +0200 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2013-10-14 09:50:16 +0200 |
commit | f21399e148386ecf3826ab81159eca58cfab2147 (patch) | |
tree | 658790e97a8ad57938021db95c551d61b2db9af2 /xen/arch/x86/hvm/stdvga.c | |
parent | 7ab6af234f9c140418e6aae177928d00abbb628b (diff) | |
download | xen-f21399e148386ecf3826ab81159eca58cfab2147.tar.gz xen-f21399e148386ecf3826ab81159eca58cfab2147.tar.bz2 xen-f21399e148386ecf3826ab81159eca58cfab2147.zip |
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 <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/arch/x86/hvm/stdvga.c')
-rw-r--r-- | xen/arch/x86/hvm/stdvga.c | 34 |
1 files changed, 11 insertions, 23 deletions
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; |