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 | } | ... | ... |