diff mbox series

[Qemu-devel,v7,36/42] memory: Access MemoryRegion with endianness

Message ID 1565941083234.39909@bt.com (mailing list archive)
State New, archived
Headers show
Series Invert Endian bit in SPARCv9 MMU TTE | expand

Commit Message

Tony Nguyen Aug. 16, 2019, 7:38 a.m. UTC
Preparation for collapsing the two byte swaps adjust_endianness and
handle_bswap into the former.

Call memory_region_dispatch_{read|write} with endianness encoded into
the "MemOp op" operand.

This patch does not change any behaviour as
memory_region_dispatch_{read|write} is yet to handle the endianness.

Once it does handle endianness, callers with byte swaps can collapse
them into adjust_endianness.

Signed-off-by: Tony Nguyen <tony.nguyen@bt.com>
---
 accel/tcg/cputlb.c       |  6 ++++--
 exec.c                   |  5 +++--
 hw/intc/armv7m_nvic.c    | 15 ++++++++-------
 hw/s390x/s390-pci-inst.c |  6 ++++--
 hw/vfio/pci-quirks.c     |  5 +++--
 hw/virtio/virtio-pci.c   |  6 ++++--
 memory_ldst.inc.c        | 18 ++++++++++++------
 7 files changed, 38 insertions(+), 23 deletions(-)

--
1.8.3.1

?

Comments

Richard Henderson Aug. 18, 2019, 12:22 p.m. UTC | #1
On 8/16/19 8:38 AM, tony.nguyen@bt.com wrote:
> Preparation for collapsing the two byte swaps adjust_endianness and
> handle_bswap into the former.
> 
> Call memory_region_dispatch_{read|write} with endianness encoded into
> the "MemOp op" operand.
> 
> This patch does not change any behaviour as
> memory_region_dispatch_{read|write} is yet to handle the endianness.
> 
> Once it does handle endianness, callers with byte swaps can collapse
> them into adjust_endianness.
> 
> Signed-off-by: Tony Nguyen <tony.nguyen@bt.com>
> ---
>  accel/tcg/cputlb.c       |  6 ++++--
>  exec.c                   |  5 +++--
>  hw/intc/armv7m_nvic.c    | 15 ++++++++-------
>  hw/s390x/s390-pci-inst.c |  6 ++++--
>  hw/vfio/pci-quirks.c     |  5 +++--
>  hw/virtio/virtio-pci.c   |  6 ++++--
>  memory_ldst.inc.c        | 18 ++++++++++++------
>  7 files changed, 38 insertions(+), 23 deletions(-)
> 
> diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
> index 6c83878..0aff6a3 100644
> --- a/accel/tcg/cputlb.c
> +++ b/accel/tcg/cputlb.c
> @@ -906,7 +906,8 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
>          qemu_mutex_lock_iothread();
>          locked = true;
>      }
> -    r = memory_region_dispatch_read(mr, mr_offset, &val, size_memop(size),
> +    r = memory_region_dispatch_read(mr, mr_offset, &val,
> +                                    size_memop(size) | MO_TE,
>                                      iotlbentry->attrs);
>      if (r != MEMTX_OK) {
>          hwaddr physaddr = mr_offset +
> @@ -947,7 +948,8 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
>          qemu_mutex_lock_iothread();
>          locked = true;
>      }
> -    r = memory_region_dispatch_write(mr, mr_offset, val, size_memop(size),
> +    r = memory_region_dispatch_write(mr, mr_offset, val,
> +                                     size_memop(size) | MO_TE,
>                                       iotlbentry->attrs);

Ok.  Conversion to target-endian via handle_bswap() in the callers.

> diff --git a/exec.c b/exec.c
> index 303f9a7..562fb5b 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -3335,7 +3335,8 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
>                 potential bugs */
>              val = ldn_p(buf, l);
>              result |= memory_region_dispatch_write(mr, addr1, val,
> -                                                   size_memop(l), attrs);
> +                                                   size_memop(l) | MO_TE,
> +                                                   attrs);
>          } else {
>              /* RAM case */
>              ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
> @@ -3397,7 +3398,7 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
>              release_lock |= prepare_mmio_access(mr);
>              l = memory_access_size(mr, l, addr1);
>              result |= memory_region_dispatch_read(mr, addr1, &val,
> -                                                  size_memop(l), attrs);
> +                                                  size_memop(l) | MO_TE, attrs);
>              stn_p(buf, l, val);

Ok.  Please add comments:

    /*
     * TODO: Merge bswap from ldn_p into memory_region_dispatch_write
     * by using ldn_he_p and dropping MO_TE to get a host-endian value.
     */

and similar for the store.

This must be delayed until after patch 38, when the MO_BSWAP component of the
MemOp is operated on by memory_region_dispatch_*.

> --- a/hw/intc/armv7m_nvic.c
> +++ b/hw/intc/armv7m_nvic.c
> @@ -2346,8 +2346,8 @@ static MemTxResult nvic_sysreg_ns_write(void *opaque, hwaddr addr,
>      if (attrs.secure) {
>          /* S accesses to the alias act like NS accesses to the real region */
>          attrs.secure = 0;
> -        return memory_region_dispatch_write(mr, addr, value, size_memop(size),
> -                                            attrs);
> +        return memory_region_dispatch_write(mr, addr, value,
> +                                            size_memop(size) | MO_TE, attrs);
>      } else {
>          /* NS attrs are RAZ/WI for privileged, and BusFault for user */
>          if (attrs.user) {
> @@ -2366,8 +2366,8 @@ static MemTxResult nvic_sysreg_ns_read(void *opaque, hwaddr addr,
>      if (attrs.secure) {
>          /* S accesses to the alias act like NS accesses to the real region */
>          attrs.secure = 0;
> -        return memory_region_dispatch_read(mr, addr, data, size_memop(size),
> -                                           attrs);
> +        return memory_region_dispatch_read(mr, addr, data,
> +                                           size_memop(size) | MO_TE, attrs);
>      } else {
>          /* NS attrs are RAZ/WI for privileged, and BusFault for user */
>          if (attrs.user) {
> @@ -2393,8 +2393,8 @@ static MemTxResult nvic_systick_write(void *opaque, hwaddr addr,
> 
>      /* Direct the access to the correct systick */
>      mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
> -    return memory_region_dispatch_write(mr, addr, value, size_memop(size),
> -                                        attrs);
> +    return memory_region_dispatch_write(mr, addr, value,
> +                                        size_memop(size) | MO_TE, attrs);
>  }
> 
>  static MemTxResult nvic_systick_read(void *opaque, hwaddr addr,
> @@ -2406,7 +2406,8 @@ static MemTxResult nvic_systick_read(void *opaque, hwaddr addr,
> 
>      /* Direct the access to the correct systick */
>      mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
> -    return memory_region_dispatch_read(mr, addr, data, size_memop(size), attrs);
> +    return memory_region_dispatch_read(mr, addr, data, size_memop(size) | MO_TE,
> +                                       attrs);
>  }

Ok.

> 
>  static const MemoryRegionOps nvic_systick_ops = {
> diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
> index 0e92a37..272cb28 100644
> --- a/hw/s390x/s390-pci-inst.c
> +++ b/hw/s390x/s390-pci-inst.c
> @@ -373,7 +373,8 @@ static MemTxResult zpci_read_bar(S390PCIBusDevice *pbdev, uint8_t pcias,
>      mr = pbdev->pdev->io_regions[pcias].memory;
>      mr = s390_get_subregion(mr, offset, len);
>      offset -= mr->addr;
> -    return memory_region_dispatch_read(mr, offset, data, size_memop(len),
> +    return memory_region_dispatch_read(mr, offset, data,
> +                                       size_memop(len) | MO_LE,
>                                         MEMTXATTRS_UNSPECIFIED);
>  }
> 
> @@ -472,7 +473,8 @@ static MemTxResult zpci_write_bar(S390PCIBusDevice *pbdev, uint8_t pcias,
>      mr = pbdev->pdev->io_regions[pcias].memory;
>      mr = s390_get_subregion(mr, offset, len);
>      offset -= mr->addr;
> -    return memory_region_dispatch_write(mr, offset, data, size_memop(len),
> +    return memory_region_dispatch_write(mr, offset, data,
> +                                        size_memop(len) | MO_LE,
>                                          MEMTXATTRS_UNSPECIFIED);
>  }

How did you derive MO_LE here?

I realize that pci tends to imply LE, but this is called from
pcilg_service_call, which is an s390 instruction, Which normally implies BE.


> 
> diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
> index d5c0268..53db1c3 100644
> --- a/hw/vfio/pci-quirks.c
> +++ b/hw/vfio/pci-quirks.c
> @@ -1072,7 +1072,8 @@ static void vfio_rtl8168_quirk_address_write(void *opaque, hwaddr addr,
> 
>                  /* Write to the proper guest MSI-X table instead */
>                  memory_region_dispatch_write(&vdev->pdev.msix_table_mmio,
> -                                             offset, val, size_memop(size),
> +                                             offset, val,
> +                                             size_memop(size) | MO_LE,
>                                               MEMTXATTRS_UNSPECIFIED);
>              }
>              return; /* Do not write guest MSI-X data to hardware */
> @@ -1103,7 +1104,7 @@ static uint64_t vfio_rtl8168_quirk_data_read(void *opaque,
>      if (rtl->enabled && (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) {
>          hwaddr offset = rtl->addr & 0xfff;
>          memory_region_dispatch_read(&vdev->pdev.msix_table_mmio, offset,
> -                                    &data, size_memop(size),
> +                                    &data, size_memop(size) | MO_LE,
>                                      MEMTXATTRS_UNSPECIFIED);
>          trace_vfio_quirk_rtl8168_msix_read(vdev->vbasedev.name, offset, data);
>      }


Hmm.  We have .endianness = DEVICE_LITTLE_ENDIAN, so we probably already did
any bswap on input to this function.  Surely any further swapping should be
suppressed.  I assume MSI-X rtl8168 is only used by x86 guests, and we would
not notice a problem testing this on an x86 host.


> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index b929e44..ad06c12 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -551,7 +551,8 @@ void virtio_address_space_write(VirtIOPCIProxy *proxy, hwaddr addr,
>          /* As length is under guest control, handle illegal values. */
>          return;
>      }
> -    memory_region_dispatch_write(mr, addr, val, size_memop(len),
> +    /* FIXME: memory_region_dispatch_write ignores MO_BSWAP.  */
> +    memory_region_dispatch_write(mr, addr, val, size_memop(len) | MO_LE,
>                                   MEMTXATTRS_UNSPECIFIED);
>  }
> 
> @@ -575,7 +576,8 @@ virtio_address_space_read(VirtIOPCIProxy *proxy, hwaddr addr,
>      /* Make sure caller aligned buf properly */
>      assert(!(((uintptr_t)buf) & (len - 1)));
> 
> -    memory_region_dispatch_read(mr, addr, &val, size_memop(len),
> +    /* FIXME: memory_region_dispatch_read ignores MO_BSWAP.  */
> +    memory_region_dispatch_read(mr, addr, &val, size_memop(len) | MO_LE,
>                                  MEMTXATTRS_UNSPECIFIED);
>      switch (len) {
>      case 1:

Ok, cpu_to_le32 etc above.

> diff --git a/memory_ldst.inc.c b/memory_ldst.inc.c
> index d08fc79..482e4b3 100644
> --- a/memory_ldst.inc.c
> +++ b/memory_ldst.inc.c
> @@ -37,7 +37,8 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL,
>          release_lock |= prepare_mmio_access(mr);
> 
>          /* I/O case */
> -        r = memory_region_dispatch_read(mr, addr1, &val, MO_32, attrs);
> +        /* FIXME: memory_region_dispatch_read ignores MO_BSWAP.  */
> +        r = memory_region_dispatch_read(mr, addr1, &val, MO_32 | endian, attrs);
>  #if defined(TARGET_WORDS_BIGENDIAN)
>          if (endian == MO_LE) {
>              val = bswap32(val);
> @@ -112,7 +113,8 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL,
>          release_lock |= prepare_mmio_access(mr);
> 
>          /* I/O case */
> -        r = memory_region_dispatch_read(mr, addr1, &val, MO_64, attrs);
> +        /* FIXME: memory_region_dispatch_read ignores MO_BSWAP.  */
> +        r = memory_region_dispatch_read(mr, addr1, &val, MO_64 | endian, attrs);
>  #if defined(TARGET_WORDS_BIGENDIAN)
>          if (endian == MO_LE) {
>              val = bswap64(val);
> @@ -221,7 +223,8 @@ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL,
>          release_lock |= prepare_mmio_access(mr);
> 
>          /* I/O case */
> -        r = memory_region_dispatch_read(mr, addr1, &val, MO_16, attrs);
> +        /* FIXME: memory_region_dispatch_read ignores MO_BSWAP.  */
> +        r = memory_region_dispatch_read(mr, addr1, &val, MO_16 | endian, attrs);
>  #if defined(TARGET_WORDS_BIGENDIAN)
>          if (endian == MO_LE) {
>              val = bswap16(val);
> @@ -342,7 +345,8 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL,
>              val = bswap32(val);
>          }
>  #endif
> -        r = memory_region_dispatch_write(mr, addr1, val, MO_32, attrs);
> +        /* FIXME: memory_region_dispatch_write ignores MO_BSWAP.  */
> +        r = memory_region_dispatch_write(mr, addr1, val, MO_32 | endian, attrs);
>      } else {
>          /* RAM case */
>          ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
> @@ -447,7 +451,8 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL,
>              val = bswap16(val);
>          }
>  #endif
> -        r = memory_region_dispatch_write(mr, addr1, val, MO_16, attrs);
> +        /* FIXME: memory_region_dispatch_write ignores MO_BSWAP.  */
> +        r = memory_region_dispatch_write(mr, addr1, val, MO_16 | endian, attrs);
>      } else {
>          /* RAM case */
>          ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
> @@ -520,7 +525,8 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL,
>              val = bswap64(val);
>          }
>  #endif
> -        r = memory_region_dispatch_write(mr, addr1, val, MO_64, attrs);
> +        /* FIXME: memory_region_dispatch_write ignores MO_BSWAP.  */
> +        r = memory_region_dispatch_write(mr, addr1, val, MO_64 | endian, attrs);

Ok.  Since you're splitting out the device changes, you'll need a conversion
function for now:

MemOp devend_memop(enum device_endian end)
{
    static MemOp conv[] = {
        [DEVICE_LITTLE_ENDIAN] = MO_LE,
        [DEVICE_BIG_ENDIAN] = MO_BE,
        [DEVICE_NATIVE_ENDIAN] = MO_TE,
        [DEVICE_HOST_ENDIAN] = 0,
    };
    switch (end) {
    case DEVICE_LITTLE_ENDIAN:
    case DEVICE_BIG_ENDIAN:
    case DEVICE_NATIVE_ENDIAN:
    case DEVICE_HOST_ENDIAN:
        return conv[end];
    default:
        g_assert_not_reached();
    }
}

Probably declared in include/exec/memory.h and implemented in memory.c.


r~
diff mbox series

Patch

diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 6c83878..0aff6a3 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -906,7 +906,8 @@  static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
         qemu_mutex_lock_iothread();
         locked = true;
     }
-    r = memory_region_dispatch_read(mr, mr_offset, &val, size_memop(size),
+    r = memory_region_dispatch_read(mr, mr_offset, &val,
+                                    size_memop(size) | MO_TE,
                                     iotlbentry->attrs);
     if (r != MEMTX_OK) {
         hwaddr physaddr = mr_offset +
@@ -947,7 +948,8 @@  static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
         qemu_mutex_lock_iothread();
         locked = true;
     }
-    r = memory_region_dispatch_write(mr, mr_offset, val, size_memop(size),
+    r = memory_region_dispatch_write(mr, mr_offset, val,
+                                     size_memop(size) | MO_TE,
                                      iotlbentry->attrs);
     if (r != MEMTX_OK) {
         hwaddr physaddr = mr_offset +
diff --git a/exec.c b/exec.c
index 303f9a7..562fb5b 100644
--- a/exec.c
+++ b/exec.c
@@ -3335,7 +3335,8 @@  static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
                potential bugs */
             val = ldn_p(buf, l);
             result |= memory_region_dispatch_write(mr, addr1, val,
-                                                   size_memop(l), attrs);
+                                                   size_memop(l) | MO_TE,
+                                                   attrs);
         } else {
             /* RAM case */
             ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
@@ -3397,7 +3398,7 @@  MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
             release_lock |= prepare_mmio_access(mr);
             l = memory_access_size(mr, l, addr1);
             result |= memory_region_dispatch_read(mr, addr1, &val,
-                                                  size_memop(l), attrs);
+                                                  size_memop(l) | MO_TE, attrs);
             stn_p(buf, l, val);
         } else {
             /* RAM case */
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 975d7cc..e150f9a 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -2346,8 +2346,8 @@  static MemTxResult nvic_sysreg_ns_write(void *opaque, hwaddr addr,
     if (attrs.secure) {
         /* S accesses to the alias act like NS accesses to the real region */
         attrs.secure = 0;
-        return memory_region_dispatch_write(mr, addr, value, size_memop(size),
-                                            attrs);
+        return memory_region_dispatch_write(mr, addr, value,
+                                            size_memop(size) | MO_TE, attrs);
     } else {
         /* NS attrs are RAZ/WI for privileged, and BusFault for user */
         if (attrs.user) {
@@ -2366,8 +2366,8 @@  static MemTxResult nvic_sysreg_ns_read(void *opaque, hwaddr addr,
     if (attrs.secure) {
         /* S accesses to the alias act like NS accesses to the real region */
         attrs.secure = 0;
-        return memory_region_dispatch_read(mr, addr, data, size_memop(size),
-                                           attrs);
+        return memory_region_dispatch_read(mr, addr, data,
+                                           size_memop(size) | MO_TE, attrs);
     } else {
         /* NS attrs are RAZ/WI for privileged, and BusFault for user */
         if (attrs.user) {
@@ -2393,8 +2393,8 @@  static MemTxResult nvic_systick_write(void *opaque, hwaddr addr,

     /* Direct the access to the correct systick */
     mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
-    return memory_region_dispatch_write(mr, addr, value, size_memop(size),
-                                        attrs);
+    return memory_region_dispatch_write(mr, addr, value,
+                                        size_memop(size) | MO_TE, attrs);
 }

 static MemTxResult nvic_systick_read(void *opaque, hwaddr addr,
@@ -2406,7 +2406,8 @@  static MemTxResult nvic_systick_read(void *opaque, hwaddr addr,

     /* Direct the access to the correct systick */
     mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
-    return memory_region_dispatch_read(mr, addr, data, size_memop(size), attrs);
+    return memory_region_dispatch_read(mr, addr, data, size_memop(size) | MO_TE,
+                                       attrs);
 }

 static const MemoryRegionOps nvic_systick_ops = {
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 0e92a37..272cb28 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -373,7 +373,8 @@  static MemTxResult zpci_read_bar(S390PCIBusDevice *pbdev, uint8_t pcias,
     mr = pbdev->pdev->io_regions[pcias].memory;
     mr = s390_get_subregion(mr, offset, len);
     offset -= mr->addr;
-    return memory_region_dispatch_read(mr, offset, data, size_memop(len),
+    return memory_region_dispatch_read(mr, offset, data,
+                                       size_memop(len) | MO_LE,
                                        MEMTXATTRS_UNSPECIFIED);
 }

@@ -472,7 +473,8 @@  static MemTxResult zpci_write_bar(S390PCIBusDevice *pbdev, uint8_t pcias,
     mr = pbdev->pdev->io_regions[pcias].memory;
     mr = s390_get_subregion(mr, offset, len);
     offset -= mr->addr;
-    return memory_region_dispatch_write(mr, offset, data, size_memop(len),
+    return memory_region_dispatch_write(mr, offset, data,
+                                        size_memop(len) | MO_LE,
                                         MEMTXATTRS_UNSPECIFIED);
 }

diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index d5c0268..53db1c3 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -1072,7 +1072,8 @@  static void vfio_rtl8168_quirk_address_write(void *opaque, hwaddr addr,

                 /* Write to the proper guest MSI-X table instead */
                 memory_region_dispatch_write(&vdev->pdev.msix_table_mmio,
-                                             offset, val, size_memop(size),
+                                             offset, val,
+                                             size_memop(size) | MO_LE,
                                              MEMTXATTRS_UNSPECIFIED);
             }
             return; /* Do not write guest MSI-X data to hardware */
@@ -1103,7 +1104,7 @@  static uint64_t vfio_rtl8168_quirk_data_read(void *opaque,
     if (rtl->enabled && (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) {
         hwaddr offset = rtl->addr & 0xfff;
         memory_region_dispatch_read(&vdev->pdev.msix_table_mmio, offset,
-                                    &data, size_memop(size),
+                                    &data, size_memop(size) | MO_LE,
                                     MEMTXATTRS_UNSPECIFIED);
         trace_vfio_quirk_rtl8168_msix_read(vdev->vbasedev.name, offset, data);
     }
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index b929e44..ad06c12 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -551,7 +551,8 @@  void virtio_address_space_write(VirtIOPCIProxy *proxy, hwaddr addr,
         /* As length is under guest control, handle illegal values. */
         return;
     }
-    memory_region_dispatch_write(mr, addr, val, size_memop(len),
+    /* FIXME: memory_region_dispatch_write ignores MO_BSWAP.  */
+    memory_region_dispatch_write(mr, addr, val, size_memop(len) | MO_LE,
                                  MEMTXATTRS_UNSPECIFIED);
 }

@@ -575,7 +576,8 @@  virtio_address_space_read(VirtIOPCIProxy *proxy, hwaddr addr,
     /* Make sure caller aligned buf properly */
     assert(!(((uintptr_t)buf) & (len - 1)));

-    memory_region_dispatch_read(mr, addr, &val, size_memop(len),
+    /* FIXME: memory_region_dispatch_read ignores MO_BSWAP.  */
+    memory_region_dispatch_read(mr, addr, &val, size_memop(len) | MO_LE,
                                 MEMTXATTRS_UNSPECIFIED);
     switch (len) {
     case 1:
diff --git a/memory_ldst.inc.c b/memory_ldst.inc.c
index d08fc79..482e4b3 100644
--- a/memory_ldst.inc.c
+++ b/memory_ldst.inc.c
@@ -37,7 +37,8 @@  static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL,
         release_lock |= prepare_mmio_access(mr);

         /* I/O case */
-        r = memory_region_dispatch_read(mr, addr1, &val, MO_32, attrs);
+        /* FIXME: memory_region_dispatch_read ignores MO_BSWAP.  */
+        r = memory_region_dispatch_read(mr, addr1, &val, MO_32 | endian, attrs);
 #if defined(TARGET_WORDS_BIGENDIAN)
         if (endian == MO_LE) {
             val = bswap32(val);
@@ -112,7 +113,8 @@  static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL,
         release_lock |= prepare_mmio_access(mr);

         /* I/O case */
-        r = memory_region_dispatch_read(mr, addr1, &val, MO_64, attrs);
+        /* FIXME: memory_region_dispatch_read ignores MO_BSWAP.  */
+        r = memory_region_dispatch_read(mr, addr1, &val, MO_64 | endian, attrs);
 #if defined(TARGET_WORDS_BIGENDIAN)
         if (endian == MO_LE) {
             val = bswap64(val);
@@ -221,7 +223,8 @@  static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL,
         release_lock |= prepare_mmio_access(mr);

         /* I/O case */
-        r = memory_region_dispatch_read(mr, addr1, &val, MO_16, attrs);
+        /* FIXME: memory_region_dispatch_read ignores MO_BSWAP.  */
+        r = memory_region_dispatch_read(mr, addr1, &val, MO_16 | endian, attrs);
 #if defined(TARGET_WORDS_BIGENDIAN)
         if (endian == MO_LE) {
             val = bswap16(val);
@@ -342,7 +345,8 @@  static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL,
             val = bswap32(val);
         }
 #endif
-        r = memory_region_dispatch_write(mr, addr1, val, MO_32, attrs);
+        /* FIXME: memory_region_dispatch_write ignores MO_BSWAP.  */
+        r = memory_region_dispatch_write(mr, addr1, val, MO_32 | endian, attrs);
     } else {
         /* RAM case */
         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
@@ -447,7 +451,8 @@  static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL,
             val = bswap16(val);
         }
 #endif
-        r = memory_region_dispatch_write(mr, addr1, val, MO_16, attrs);
+        /* FIXME: memory_region_dispatch_write ignores MO_BSWAP.  */
+        r = memory_region_dispatch_write(mr, addr1, val, MO_16 | endian, attrs);
     } else {
         /* RAM case */
         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
@@ -520,7 +525,8 @@  static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL,
             val = bswap64(val);
         }
 #endif
-        r = memory_region_dispatch_write(mr, addr1, val, MO_64, attrs);
+        /* FIXME: memory_region_dispatch_write ignores MO_BSWAP.  */
+        r = memory_region_dispatch_write(mr, addr1, val, MO_64 | endian, attrs);
     } else {
         /* RAM case */
         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);