Il 14/06/2013 12:32, Nikunj A Dadhania ha scritto: > Nikunj A Dadhania <nik...@linux.vnet.ibm.com> writes: >> commit 08521e28c7e6e8cc1f53424a0f845f58d2ed9546 >> Author: Paolo Bonzini <pbonz...@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 <r...@twiddle.net> >> Signed-off-by: Paolo Bonzini <pbonz...@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
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,