Commit 6c2934db949aa259ed47b126b5c6838ac57a3f6f

Authored by aurel32
1 parent 978dd635

Fix cpu_physical_memory_rw() for 64-bit I/O accesses

KVM uses cpu_physical_memory_rw() to access the I/O devices. When a
read or write with a length of 8-byte is requested, it is split into 2
4-byte accesses.

This has been broken in revision 5849. After this revision, only the
first 4 bytes are actually read/write to the device, as the target
address is changed, so on the next iteration of the loop the next 4
bytes are actually read/written elsewhere (in the RAM for the graphic
card).

This patch fixes screen corruption (and most probably data corruption)
with FreeBSD/amd64. Bug #2556746 in KVM bugzilla.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6628 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 14 additions and 12 deletions
... ... @@ -2955,25 +2955,26 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
2955 2955  
2956 2956 if (is_write) {
2957 2957 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
  2958 + target_phys_addr_t addr1 = addr;
2958 2959 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2959 2960 if (p)
2960   - addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
  2961 + addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
2961 2962 /* XXX: could force cpu_single_env to NULL to avoid
2962 2963 potential bugs */
2963   - if (l >= 4 && ((addr & 3) == 0)) {
  2964 + if (l >= 4 && ((addr1 & 3) == 0)) {
2964 2965 /* 32 bit write access */
2965 2966 val = ldl_p(buf);
2966   - io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
  2967 + io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
2967 2968 l = 4;
2968   - } else if (l >= 2 && ((addr & 1) == 0)) {
  2969 + } else if (l >= 2 && ((addr1 & 1) == 0)) {
2969 2970 /* 16 bit write access */
2970 2971 val = lduw_p(buf);
2971   - io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
  2972 + io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
2972 2973 l = 2;
2973 2974 } else {
2974 2975 /* 8 bit write access */
2975 2976 val = ldub_p(buf);
2976   - io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
  2977 + io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
2977 2978 l = 1;
2978 2979 }
2979 2980 } else {
... ... @@ -2993,23 +2994,24 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
2993 2994 } else {
2994 2995 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2995 2996 !(pd & IO_MEM_ROMD)) {
  2997 + target_phys_addr_t addr1 = addr;
2996 2998 /* I/O case */
2997 2999 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2998 3000 if (p)
2999   - addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
3000   - if (l >= 4 && ((addr & 3) == 0)) {
  3001 + addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
  3002 + if (l >= 4 && ((addr1 & 3) == 0)) {
3001 3003 /* 32 bit read access */
3002   - val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
  3004 + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
3003 3005 stl_p(buf, val);
3004 3006 l = 4;
3005   - } else if (l >= 2 && ((addr & 1) == 0)) {
  3007 + } else if (l >= 2 && ((addr1 & 1) == 0)) {
3006 3008 /* 16 bit read access */
3007   - val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
  3009 + val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
3008 3010 stw_p(buf, val);
3009 3011 l = 2;
3010 3012 } else {
3011 3013 /* 8 bit read access */
3012   - val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
  3014 + val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
3013 3015 stb_p(buf, val);
3014 3016 l = 1;
3015 3017 }
... ...