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,25 +2955,26 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
2955 2955
2956 if (is_write) { 2956 if (is_write) {
2957 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { 2957 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
  2958 + target_phys_addr_t addr1 = addr;
2958 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); 2959 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2959 if (p) 2960 if (p)
2960 - addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; 2961 + addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
2961 /* XXX: could force cpu_single_env to NULL to avoid 2962 /* XXX: could force cpu_single_env to NULL to avoid
2962 potential bugs */ 2963 potential bugs */
2963 - if (l >= 4 && ((addr & 3) == 0)) { 2964 + if (l >= 4 && ((addr1 & 3) == 0)) {
2964 /* 32 bit write access */ 2965 /* 32 bit write access */
2965 val = ldl_p(buf); 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 l = 4; 2968 l = 4;
2968 - } else if (l >= 2 && ((addr & 1) == 0)) { 2969 + } else if (l >= 2 && ((addr1 & 1) == 0)) {
2969 /* 16 bit write access */ 2970 /* 16 bit write access */
2970 val = lduw_p(buf); 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 l = 2; 2973 l = 2;
2973 } else { 2974 } else {
2974 /* 8 bit write access */ 2975 /* 8 bit write access */
2975 val = ldub_p(buf); 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 l = 1; 2978 l = 1;
2978 } 2979 }
2979 } else { 2980 } else {
@@ -2993,23 +2994,24 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, @@ -2993,23 +2994,24 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
2993 } else { 2994 } else {
2994 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && 2995 if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2995 !(pd & IO_MEM_ROMD)) { 2996 !(pd & IO_MEM_ROMD)) {
  2997 + target_phys_addr_t addr1 = addr;
2996 /* I/O case */ 2998 /* I/O case */
2997 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); 2999 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2998 if (p) 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 /* 32 bit read access */ 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 stl_p(buf, val); 3005 stl_p(buf, val);
3004 l = 4; 3006 l = 4;
3005 - } else if (l >= 2 && ((addr & 1) == 0)) { 3007 + } else if (l >= 2 && ((addr1 & 1) == 0)) {
3006 /* 16 bit read access */ 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 stw_p(buf, val); 3010 stw_p(buf, val);
3009 l = 2; 3011 l = 2;
3010 } else { 3012 } else {
3011 /* 8 bit read access */ 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 stb_p(buf, val); 3015 stb_p(buf, val);
3014 l = 1; 3016 l = 1;
3015 } 3017 }