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