Patchwork commit 08521e2 breaks SLOF usb boot

login
register
mail settings
Submitter Paolo Bonzini
Date July 19, 2013, 12:50 p.m.
Message ID <51E93624.5040702@redhat.com>
Download mbox | patch
Permalink /patch/260255/
State New
Headers show

Comments

Paolo Bonzini - July 19, 2013, 12:50 p.m.
Il 14/06/2013 12:32, Nikunj A Dadhania ha scritto:
> Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> writes:
>> commit 08521e28c7e6e8cc1f53424a0f845f58d2ed9546
>> Author: Paolo Bonzini <pbonzini@redhat.com>
>> Date:   Fri May 24 12:54:01 2013 +0200
>>
>>     memory: add big endian support to access_with_adjusted_size
>>     
>>     This will be used to split 8-byte access down to two four-byte accesses.
>>     
>>     Reviewed-by: Richard Henderson <rth@twiddle.net>
>>     Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>>
>>
>> If I hack the above funniness in my USB EHCI driver, somewhere down the
>> qemu crashes at code introduced by this patch:
>>
>> Program received signal SIGSEGV, Segmentation fault.
>> 0x0000000000000000 in ?? ()
>> (gdb) bt
>> #0 0x0000000000000000 in ?? ()
>> #1 0x00005555557a0ea4 in access_with_adjusted_size (addr=addr@entry=12, value=value@entry=0x7fffd5a86680, size=size@entry=1, access_size_min=<optimized out>, access_size_max=<optimized out>,
>> access=0x5555557a1f80 <memory_region_oldmmio_write_accessor>, opaque=0x5555567f8ab8) at /home/nikunj/work/power/code/qemu/memory.c:396
>> #2 0x00005555557a5ebb in memory_region_dispatch_write (size=1, data=0, addr=12, mr=0x5555567f8ab8) at /home/nikunj/work/power/code/qemu/memory.c:998
>>
>> Reverting this, I can safely boot using a usb-storage device put on ehci controller.
> 
> Just reverting this patch does not help though, i will need to figure
> which all commits are bad.

Hi Nikunj,

can you try the attached patch?

Alexey, with some luck it may even fix virtio-blk too.

Paolo
Alexey Kardashevskiy - July 19, 2013, 12:58 p.m.
On 07/19/2013 10:50 PM, Paolo Bonzini wrote:
> Il 14/06/2013 12:32, Nikunj A Dadhania ha scritto:
>> Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> writes:
>>> commit 08521e28c7e6e8cc1f53424a0f845f58d2ed9546
>>> Author: Paolo Bonzini <pbonzini@redhat.com>
>>> Date:   Fri May 24 12:54:01 2013 +0200
>>>
>>>     memory: add big endian support to access_with_adjusted_size
>>>     
>>>     This will be used to split 8-byte access down to two four-byte accesses.
>>>     
>>>     Reviewed-by: Richard Henderson <rth@twiddle.net>
>>>     Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>>>
>>>
>>> If I hack the above funniness in my USB EHCI driver, somewhere down the
>>> qemu crashes at code introduced by this patch:
>>>
>>> Program received signal SIGSEGV, Segmentation fault.
>>> 0x0000000000000000 in ?? ()
>>> (gdb) bt
>>> #0 0x0000000000000000 in ?? ()
>>> #1 0x00005555557a0ea4 in access_with_adjusted_size (addr=addr@entry=12, value=value@entry=0x7fffd5a86680, size=size@entry=1, access_size_min=<optimized out>, access_size_max=<optimized out>,
>>> access=0x5555557a1f80 <memory_region_oldmmio_write_accessor>, opaque=0x5555567f8ab8) at /home/nikunj/work/power/code/qemu/memory.c:396
>>> #2 0x00005555557a5ebb in memory_region_dispatch_write (size=1, data=0, addr=12, mr=0x5555567f8ab8) at /home/nikunj/work/power/code/qemu/memory.c:998
>>>
>>> Reverting this, I can safely boot using a usb-storage device put on ehci controller.
>>
>> Just reverting this patch does not help though, i will need to figure
>> which all commits are bad.
> 
> Hi Nikunj,
> 
> can you try the attached patch?
> 
> Alexey, with some luck it may even fix virtio-blk too.


Heh. Bad luck. The behaviour has changed slightly but it still does not work.
Paolo Bonzini - July 19, 2013, 1:03 p.m.
Il 19/07/2013 14:58, Alexey Kardashevskiy ha scritto:
> On 07/19/2013 10:50 PM, Paolo Bonzini wrote:
>> Il 14/06/2013 12:32, Nikunj A Dadhania ha scritto:
>>> Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> writes:
>>>> commit 08521e28c7e6e8cc1f53424a0f845f58d2ed9546
>>>> Author: Paolo Bonzini <pbonzini@redhat.com>
>>>> Date:   Fri May 24 12:54:01 2013 +0200
>>>>
>>>>     memory: add big endian support to access_with_adjusted_size
>>>>     
>>>>     This will be used to split 8-byte access down to two four-byte accesses.
>>>>     
>>>>     Reviewed-by: Richard Henderson <rth@twiddle.net>
>>>>     Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>>>>
>>>>
>>>> If I hack the above funniness in my USB EHCI driver, somewhere down the
>>>> qemu crashes at code introduced by this patch:
>>>>
>>>> Program received signal SIGSEGV, Segmentation fault.
>>>> 0x0000000000000000 in ?? ()
>>>> (gdb) bt
>>>> #0 0x0000000000000000 in ?? ()
>>>> #1 0x00005555557a0ea4 in access_with_adjusted_size (addr=addr@entry=12, value=value@entry=0x7fffd5a86680, size=size@entry=1, access_size_min=<optimized out>, access_size_max=<optimized out>,
>>>> access=0x5555557a1f80 <memory_region_oldmmio_write_accessor>, opaque=0x5555567f8ab8) at /home/nikunj/work/power/code/qemu/memory.c:396
>>>> #2 0x00005555557a5ebb in memory_region_dispatch_write (size=1, data=0, addr=12, mr=0x5555567f8ab8) at /home/nikunj/work/power/code/qemu/memory.c:998
>>>>
>>>> Reverting this, I can safely boot using a usb-storage device put on ehci controller.
>>>
>>> Just reverting this patch does not help though, i will need to figure
>>> which all commits are bad.
>>
>> Hi Nikunj,
>>
>> can you try the attached patch?
>>
>> Alexey, with some luck it may even fix virtio-blk too.
> 
> 
> Heh. Bad luck. The behaviour has changed slightly but it still does not work.

How changed?

Paolo
Alexey Kardashevskiy - July 19, 2013, 1:05 p.m.
On 07/19/2013 11:03 PM, Paolo Bonzini wrote:
> Il 19/07/2013 14:58, Alexey Kardashevskiy ha scritto:
>> On 07/19/2013 10:50 PM, Paolo Bonzini wrote:
>>> Il 14/06/2013 12:32, Nikunj A Dadhania ha scritto:
>>>> Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> writes:
>>>>> commit 08521e28c7e6e8cc1f53424a0f845f58d2ed9546
>>>>> Author: Paolo Bonzini <pbonzini@redhat.com>
>>>>> Date:   Fri May 24 12:54:01 2013 +0200
>>>>>
>>>>>     memory: add big endian support to access_with_adjusted_size
>>>>>     
>>>>>     This will be used to split 8-byte access down to two four-byte accesses.
>>>>>     
>>>>>     Reviewed-by: Richard Henderson <rth@twiddle.net>
>>>>>     Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>>>>>
>>>>>
>>>>> If I hack the above funniness in my USB EHCI driver, somewhere down the
>>>>> qemu crashes at code introduced by this patch:
>>>>>
>>>>> Program received signal SIGSEGV, Segmentation fault.
>>>>> 0x0000000000000000 in ?? ()
>>>>> (gdb) bt
>>>>> #0 0x0000000000000000 in ?? ()
>>>>> #1 0x00005555557a0ea4 in access_with_adjusted_size (addr=addr@entry=12, value=value@entry=0x7fffd5a86680, size=size@entry=1, access_size_min=<optimized out>, access_size_max=<optimized out>,
>>>>> access=0x5555557a1f80 <memory_region_oldmmio_write_accessor>, opaque=0x5555567f8ab8) at /home/nikunj/work/power/code/qemu/memory.c:396
>>>>> #2 0x00005555557a5ebb in memory_region_dispatch_write (size=1, data=0, addr=12, mr=0x5555567f8ab8) at /home/nikunj/work/power/code/qemu/memory.c:998
>>>>>
>>>>> Reverting this, I can safely boot using a usb-storage device put on ehci controller.
>>>>
>>>> Just reverting this patch does not help though, i will need to figure
>>>> which all commits are bad.
>>>
>>> Hi Nikunj,
>>>
>>> can you try the attached patch?
>>>
>>> Alexey, with some luck it may even fix virtio-blk too.
>>
>>
>> Heh. Bad luck. The behaviour has changed slightly but it still does not work.
> 
> How changed?


See below. I am trying to debug :)


SLOF **********************************************************************
QEMU Starting
 Build Date = Apr 30 2013 14:04:00
 FW Version = git-8cfdfc43f4c4c8c8
 Press "s" to enter Open Firmware.

Populating /vdevice methods
Populating /vdevice/nvram@71000000

NVRAM: size=65536, fetch=200E, store=200F
Populating /vdevice/vty@71000001
Populating /pci@800000020000000
 Adapters on 0800000020000000
                     00 0000 (D) : 1af4 1001    virtio [ block ]
No NVRAM common partition, re-initializing...
claim failed!
Using default console: /vdevice/vty@71000001

  Welcome to Open Firmware

  Copyright (c) 2004, 2011 IBM Corporation All rights reserved.
  This program and the accompanying materials are made available
  under the terms of the BSD License available at
  http://www.opensource.org/licenses/bsd-license.php


Trying to load:  from: disk ... qemu-system-ppc64: Guest moved used index
from 0 to 65535
Alexey Kardashevskiy - July 19, 2013, 1:23 p.m.
On 07/19/2013 11:05 PM, Alexey Kardashevskiy wrote:
> On 07/19/2013 11:03 PM, Paolo Bonzini wrote:
>> Il 19/07/2013 14:58, Alexey Kardashevskiy ha scritto:
>>> On 07/19/2013 10:50 PM, Paolo Bonzini wrote:
>>>> Il 14/06/2013 12:32, Nikunj A Dadhania ha scritto:
>>>>> Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> writes:
>>>>>> commit 08521e28c7e6e8cc1f53424a0f845f58d2ed9546
>>>>>> Author: Paolo Bonzini <pbonzini@redhat.com>
>>>>>> Date:   Fri May 24 12:54:01 2013 +0200
>>>>>>
>>>>>>     memory: add big endian support to access_with_adjusted_size
>>>>>>     
>>>>>>     This will be used to split 8-byte access down to two four-byte accesses.
>>>>>>     
>>>>>>     Reviewed-by: Richard Henderson <rth@twiddle.net>
>>>>>>     Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>>>>>>
>>>>>>
>>>>>> If I hack the above funniness in my USB EHCI driver, somewhere down the
>>>>>> qemu crashes at code introduced by this patch:
>>>>>>
>>>>>> Program received signal SIGSEGV, Segmentation fault.
>>>>>> 0x0000000000000000 in ?? ()
>>>>>> (gdb) bt
>>>>>> #0 0x0000000000000000 in ?? ()
>>>>>> #1 0x00005555557a0ea4 in access_with_adjusted_size (addr=addr@entry=12, value=value@entry=0x7fffd5a86680, size=size@entry=1, access_size_min=<optimized out>, access_size_max=<optimized out>,
>>>>>> access=0x5555557a1f80 <memory_region_oldmmio_write_accessor>, opaque=0x5555567f8ab8) at /home/nikunj/work/power/code/qemu/memory.c:396
>>>>>> #2 0x00005555557a5ebb in memory_region_dispatch_write (size=1, data=0, addr=12, mr=0x5555567f8ab8) at /home/nikunj/work/power/code/qemu/memory.c:998
>>>>>>
>>>>>> Reverting this, I can safely boot using a usb-storage device put on ehci controller.
>>>>>
>>>>> Just reverting this patch does not help though, i will need to figure
>>>>> which all commits are bad.
>>>>
>>>> Hi Nikunj,
>>>>
>>>> can you try the attached patch?
>>>>
>>>> Alexey, with some luck it may even fix virtio-blk too.
>>>
>>>
>>> Heh. Bad luck. The behaviour has changed slightly but it still does not work.
>>
>> How changed?
> 
> 
> See below. I am trying to debug :)


Fails here. io_mem_unassigned. Are you on any IRC?


(gdb) bt
#0  memory_region_access_valid (mr=0x10aee190 <io_mem_unassigned>,
addr=0xd0fb0000802, size=0x2,
    is_write=0x0) at /home/alexey/pcipassthru/qemu-impreza/memory.c:931
#1  0x00000000103838c0 in memory_region_dispatch_read (mr=0x10aee190
<io_mem_unassigned>,
    addr=0xd0fb0000802, pval=0x3fffffffdd30, size=0x2) at
/home/alexey/pcipassthru/qemu-impreza/memory.c:962
#2  0x0000000010387038 in io_mem_read (mr=0x10aee190 <io_mem_unassigned>,
addr=0xd0fb0000802,
    pval=0x3fffffffdd30, size=0x2) at
/home/alexey/pcipassthru/qemu-impreza/memory.c:1740
#3  0x00000000102ebde0 in lduw_phys_internal (addr=0xd0fb0000802,
endian=DEVICE_NATIVE_ENDIAN)
    at /home/alexey/pcipassthru/qemu-impreza/exec.c:2390
#4  0x00000000102ebed8 in lduw_phys (addr=0xd0fb0000802)
    at /home/alexey/pcipassthru/qemu-impreza/exec.c:2422
#5  0x000000001037387c in vring_avail_idx (vq=0x10c16e30)
    at /home/alexey/pcipassthru/qemu-impreza/hw/virtio/virtio.c:138
#6  0x000000001037429c in virtqueue_num_heads (vq=0x10c16e30, idx=0x0)
    at /home/alexey/pcipassthru/qemu-impreza/hw/virtio/virtio.c:285
#7  0x0000000010374a74 in virtqueue_pop (vq=0x10c16e30, elem=0x10c34c08)
    at /home/alexey/pcipassthru/qemu-impreza/hw/virtio/virtio.c:441
#8  0x000000001030c1bc in virtio_blk_get_request (s=0x10c1c2f8)
    at /home/alexey/pcipassthru/qemu-impreza/hw/block/virtio-blk.c:118
#9  0x000000001030cfb8 in virtio_blk_handle_output (vdev=0x10c1c2f8,
vq=0x10c16e30)
    at /home/alexey/pcipassthru/qemu-impreza/hw/block/virtio-blk.c:411
#10 0x0000000010375c48 in virtio_queue_notify_vq (vq=0x10c16e30)
    at /home/alexey/pcipassthru/qemu-impreza/hw/virtio/virtio.c:687
#11 0x000000001037776c in virtio_queue_host_notifier_read (n=0x10c16e80)
    at /home/alexey/pcipassthru/qemu-impreza/hw/virtio/virtio.c:1071
#12 0x000000001020fe74 in qemu_iohandler_poll (pollfds=0x10bb1a00, ret=0x2)
    at /home/alexey/pcipassthru/qemu-impreza/iohandler.c:143
#13 0x0000000010210c4c in main_loop_wait (nonblocking=0x0)
    at /home/alexey/pcipassthru/qemu-impreza/main-loop.c:466
#14 0x00000000102c97d4 in main_loop () at
/home/alexey/pcipassthru/qemu-impreza/vl.c:2090
#15 0x00000000102d2c80 in main (argc=0x16, argv=0x3ffffffff1b8,
envp=0x3ffffffff270)
    at /home/alexey/pcipassthru/qemu-impreza/vl.c:4432



> 
> SLOF **********************************************************************
> QEMU Starting
>  Build Date = Apr 30 2013 14:04:00
>  FW Version = git-8cfdfc43f4c4c8c8
>  Press "s" to enter Open Firmware.
> 
> Populating /vdevice methods
> Populating /vdevice/nvram@71000000
> 
> NVRAM: size=65536, fetch=200E, store=200F
> Populating /vdevice/vty@71000001
> Populating /pci@800000020000000
>  Adapters on 0800000020000000
>                      00 0000 (D) : 1af4 1001    virtio [ block ]
> No NVRAM common partition, re-initializing...
> claim failed!
> Using default console: /vdevice/vty@71000001
> 
>   Welcome to Open Firmware
> 
>   Copyright (c) 2004, 2011 IBM Corporation All rights reserved.
>   This program and the accompanying materials are made available
>   under the terms of the BSD License available at
>   http://www.opensource.org/licenses/bsd-license.php
> 
> 
> Trying to load:  from: disk ... qemu-system-ppc64: Guest moved used index
> from 0 to 65535
> 
> 
>
Nikunj A Dadhania - July 25, 2013, 6:04 a.m.
Paolo Bonzini <pbonzini@redhat.com> writes:

> Il 14/06/2013 12:32, Nikunj A Dadhania ha scritto:
>> Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> writes:
>>> commit 08521e28c7e6e8cc1f53424a0f845f58d2ed9546
>>> Author: Paolo Bonzini <pbonzini@redhat.com>
>>> Date:   Fri May 24 12:54:01 2013 +0200
>>>
>>>     memory: add big endian support to access_with_adjusted_size
>>>     
>>>     This will be used to split 8-byte access down to two four-byte accesses.
>>>     
>>>     Reviewed-by: Richard Henderson <rth@twiddle.net>
>>>     Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>>>
>>>
>>> If I hack the above funniness in my USB EHCI driver, somewhere down the
>>> qemu crashes at code introduced by this patch:
>>>
>>> Program received signal SIGSEGV, Segmentation fault.
>>> 0x0000000000000000 in ?? ()
>>> (gdb) bt
>>> #0 0x0000000000000000 in ?? ()
>>> #1 0x00005555557a0ea4 in access_with_adjusted_size (addr=addr@entry=12, value=value@entry=0x7fffd5a86680, size=size@entry=1, access_size_min=<optimized out>, access_size_max=<optimized out>,
>>> access=0x5555557a1f80 <memory_region_oldmmio_write_accessor>, opaque=0x5555567f8ab8) at /home/nikunj/work/power/code/qemu/memory.c:396
>>> #2 0x00005555557a5ebb in memory_region_dispatch_write (size=1, data=0, addr=12, mr=0x5555567f8ab8) at /home/nikunj/work/power/code/qemu/memory.c:998
>>>
>>> Reverting this, I can safely boot using a usb-storage device put on ehci controller.
>> 
>> Just reverting this patch does not help though, i will need to figure
>> which all commits are bad.
>
> Hi Nikunj,
>
> can you try the attached patch?
>
Sorry, for the late reply.

I tried your "iommu" branch at git://github.com/bonzini/qemu.git

Both ehci and ohci are working fine now in SLOF. I will do more testing and let
you know if there is any issues.

Thanks a lot.

Regards,
Nikunj

Patch

diff --git a/exec.c b/exec.c
index c99a883..c8658c6 100644
--- a/exec.c
+++ b/exec.c
@@ -1379,7 +1379,7 @@  static void *qemu_safe_ram_ptr(ram_addr_t addr)
 
 /* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr
  * but takes a size argument */
-static void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size)
+static void *qemu_ram_ptr_length(ram_addr_t addr, hwaddr *size)
 {
     if (*size == 0) {
         return NULL;
@@ -1898,14 +1898,10 @@  static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
 
 static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
 {
-    unsigned access_size_min = mr->ops->impl.min_access_size;
-    unsigned access_size_max = mr->ops->impl.max_access_size;
+    unsigned access_size_max = mr->ops->valid.max_access_size;
 
     /* Regions are assumed to support 1-4 byte accesses unless
        otherwise specified.  */
-    if (access_size_min == 0) {
-        access_size_min = 1;
-    }
     if (access_size_max == 0) {
         access_size_max = 4;
     }
@@ -1922,9 +1918,6 @@  static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
     if (l > access_size_max) {
         l = access_size_max;
     }
-    /* ??? The users of this function are wrong, not supporting minimums larger
-       than the remaining length.  C.f. memory.c:access_with_adjusted_size.  */
-    assert(l >= access_size_min);
 
     return l;
 }
diff --git a/memory.c b/memory.c
index c8f9a2b..a8db78c 100644
--- a/memory.c
+++ b/memory.c
@@ -339,65 +339,104 @@  static void flatview_simplify(FlatView *view)
     }
 }
 
-static void memory_region_oldmmio_read_accessor(void *opaque,
+static bool memory_region_big_endian(MemoryRegion *mr)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    return mr->ops->endianness != DEVICE_LITTLE_ENDIAN;
+#else
+    return mr->ops->endianness == DEVICE_BIG_ENDIAN;
+#endif
+}
+
+static bool memory_region_wrong_endianness(MemoryRegion *mr)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    return mr->ops->endianness == DEVICE_LITTLE_ENDIAN;
+#else
+    return mr->ops->endianness == DEVICE_BIG_ENDIAN;
+#endif
+}
+
+static void adjust_endianness(MemoryRegion *mr, uint64_t *data, unsigned size)
+{
+    if (memory_region_wrong_endianness(mr)) {
+        switch (size) {
+        case 1:
+            break;
+        case 2:
+            *data = bswap16(*data);
+            break;
+        case 4:
+            *data = bswap32(*data);
+            break;
+        case 8:
+            *data = bswap64(*data);
+            break;
+        default:
+            abort();
+        }
+    }
+}
+
+static void memory_region_oldmmio_read_accessor(MemoryRegion *mr,
                                                 hwaddr addr,
                                                 uint64_t *value,
                                                 unsigned size,
                                                 unsigned shift,
                                                 uint64_t mask)
 {
-    MemoryRegion *mr = opaque;
     uint64_t tmp;
 
     tmp = mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr);
+    adjust_endianness(mr, &tmp, size);
     *value |= (tmp & mask) << shift;
 }
 
-static void memory_region_read_accessor(void *opaque,
+static void memory_region_read_accessor(MemoryRegion *mr,
                                         hwaddr addr,
                                         uint64_t *value,
                                         unsigned size,
                                         unsigned shift,
                                         uint64_t mask)
 {
-    MemoryRegion *mr = opaque;
     uint64_t tmp;
 
     if (mr->flush_coalesced_mmio) {
         qemu_flush_coalesced_mmio_buffer();
     }
     tmp = mr->ops->read(mr->opaque, addr, size);
+    adjust_endianness(mr, &tmp, size);
     *value |= (tmp & mask) << shift;
 }
 
-static void memory_region_oldmmio_write_accessor(void *opaque,
+static void memory_region_oldmmio_write_accessor(MemoryRegion *mr,
                                                  hwaddr addr,
                                                  uint64_t *value,
                                                  unsigned size,
                                                  unsigned shift,
                                                  uint64_t mask)
 {
-    MemoryRegion *mr = opaque;
     uint64_t tmp;
 
     tmp = (*value >> shift) & mask;
+    adjust_endianness(mr, &tmp, size);
     mr->ops->old_mmio.write[ctz32(size)](mr->opaque, addr, tmp);
 }
 
-static void memory_region_write_accessor(void *opaque,
+static void memory_region_write_accessor(MemoryRegion *mr,
                                          hwaddr addr,
                                          uint64_t *value,
                                          unsigned size,
                                          unsigned shift,
                                          uint64_t mask)
 {
-    MemoryRegion *mr = opaque;
     uint64_t tmp;
 
     if (mr->flush_coalesced_mmio) {
         qemu_flush_coalesced_mmio_buffer();
     }
     tmp = (*value >> shift) & mask;
+    adjust_endianness(mr, &tmp, size);
     mr->ops->write(mr->opaque, addr, tmp, size);
 }
 
@@ -406,13 +445,13 @@  static void access_with_adjusted_size(hwaddr addr,
                                       unsigned size,
                                       unsigned access_size_min,
                                       unsigned access_size_max,
-                                      void (*access)(void *opaque,
+                                      void (*access)(MemoryRegion *mr,
                                                      hwaddr addr,
                                                      uint64_t *value,
                                                      unsigned size,
                                                      unsigned shift,
                                                      uint64_t mask),
-                                      void *opaque)
+                                      MemoryRegion *mr)
 {
     uint64_t access_mask;
     unsigned access_size;
@@ -428,13 +467,15 @@  static void access_with_adjusted_size(hwaddr addr,
     /* FIXME: support unaligned access? */
     access_size = MAX(MIN(size, access_size_max), access_size_min);
     access_mask = -1ULL >> (64 - access_size * 8);
-    for (i = 0; i < size; i += access_size) {
-#ifdef TARGET_WORDS_BIGENDIAN
-        access(opaque, addr + i, value, access_size,
-               (size - access_size - i) * 8, access_mask);
-#else
-        access(opaque, addr + i, value, access_size, i * 8, access_mask);
-#endif
+    if (memory_region_big_endian(mr)) {
+        for (i = 0; i < size; i += access_size) {
+            access(mr, addr + i, value, access_size,
+                   (size - access_size - i) * 8, access_mask);
+        }
+    } else {
+        for (i = 0; i < size; i += access_size) {
+            access(mr, addr + i, value, access_size, i * 8, access_mask);
+        }
     }
 }
 
@@ -786,15 +827,6 @@  static void memory_region_destructor_rom_device(MemoryRegion *mr)
     qemu_ram_free(mr->ram_addr & TARGET_PAGE_MASK);
 }
 
-static bool memory_region_wrong_endianness(MemoryRegion *mr)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
-    return mr->ops->endianness == DEVICE_LITTLE_ENDIAN;
-#else
-    return mr->ops->endianness == DEVICE_BIG_ENDIAN;
-#endif
-}
-
 void memory_region_init(MemoryRegion *mr,
                         Object *owner,
                         const char *name,
@@ -841,7 +872,7 @@  static uint64_t unassigned_mem_read(void *opaque, hwaddr addr,
     if (current_cpu != NULL) {
         cpu_unassigned_access(current_cpu, addr, false, false, 0, size);
     }
-    return 0;
+    return -1ULL;
 }
 
 static void unassigned_mem_write(void *opaque, hwaddr addr,
@@ -922,27 +953,6 @@  static uint64_t memory_region_dispatch_read1(MemoryRegion *mr,
     return data;
 }
 
-static void adjust_endianness(MemoryRegion *mr, uint64_t *data, unsigned size)
-{
-    if (memory_region_wrong_endianness(mr)) {
-        switch (size) {
-        case 1:
-            break;
-        case 2:
-            *data = bswap16(*data);
-            break;
-        case 4:
-            *data = bswap32(*data);
-            break;
-        case 8:
-            *data = bswap64(*data);
-            break;
-        default:
-            abort();
-        }
-    }
-}
-
 static bool memory_region_dispatch_read(MemoryRegion *mr,
                                         hwaddr addr,
                                         uint64_t *pval,
@@ -954,7 +964,6 @@  static bool memory_region_dispatch_read(MemoryRegion *mr,
     }
 
     *pval = memory_region_dispatch_read1(mr, addr, size);
-    adjust_endianness(mr, pval, size);
     return false;
 }
 
@@ -968,8 +977,6 @@  static bool memory_region_dispatch_write(MemoryRegion *mr,
         return true;
     }
 
-    adjust_endianness(mr, &data, size);
-
     if (mr->ops->write) {
         access_with_adjusted_size(addr, &data, size,
                                   mr->ops->impl.min_access_size,