According to comment for full->xlat_section for non-RAM:
 Otherwise, iotlb contains
  - a physical section number in the lower TARGET_PAGE_BITS
  - the offset within section->mr of the page base (I/O, ROMD) with the
    TARGET_PAGE_BITS masked off.

This 'physical section number in the lower TARGET_PAGE_BITS' is true only
if memory region is aligned to TARGET_PAGE_BITS.

For example for memory region with address 0x1000c220 and size of
2 x 4k pages following sections will be created by flatview_add_to_dispatch():

flatview_add_to_dispatch section 1: addr: 0x1000c220 
offset_within_address_space 0x1000c220 offset_within_region 0x0
flatview_add_to_dispatch section 2: addr: 0x1000c220 
offset_within_address_space 0x1000d000 offset_within_region 0xde0
flatview_add_to_dispatch section 3: addr: 0x1000c220 
offset_within_address_space 0x1000e000 offset_within_region 0x1de0

So offset_within_region is not aligned to TARGET_PAGE_SIZE.

This leads to full->xlat_section & ~TARGET_PAGE_BITS to contain information not 
only about
section number, but also about offset in the memory region.

Fix it by clearing TARGET_PAGE_BITS bits in xlat before adding section and 
reapply them in io_prepare().

Signed-off-by: Vladimir Isaev <[email protected]>
---
 accel/tcg/cputlb.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index c30073326a..4c0b01b606 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1090,7 +1090,7 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx,
         }
     } else {
         /* I/O or ROMD */
-        iotlb = memory_region_section_get_iotlb(cpu, section) + xlat;
+        iotlb = memory_region_section_get_iotlb(cpu, section) + (xlat & 
TARGET_PAGE_MASK);
         /*
          * Writes to romd devices must go through MMIO to enable write.
          * Reads to romd devices go through the ram_ptr found above,
@@ -1277,7 +1277,8 @@ io_prepare(hwaddr *out_offset, CPUState *cpu, hwaddr xlat,
     hwaddr mr_offset;
 
     section = iotlb_to_section(cpu, xlat, attrs);
-    mr_offset = (xlat & TARGET_PAGE_MASK) + addr;
+    mr_offset = (xlat & TARGET_PAGE_MASK) + addr +
+                (section->offset_within_region & ~TARGET_PAGE_MASK);
     cpu->mem_io_pc = retaddr;
     if (!cpu->neg.can_do_io) {
         cpu_io_recompile(cpu, retaddr);
-- 
2.51.0


Reply via email to