Commit 6c2934db949aa259ed47b126b5c6838ac57a3f6f
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
exec.c
| ... | ... | @@ -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 | } | ... | ... |