On 2018-09-26 10:17, David Hildenbrand wrote: > On 26/09/2018 10:09, Thomas Huth wrote: >> On 2018-09-26 10:07, David Hildenbrand wrote: >>> On 26/09/2018 10:04, David Hildenbrand wrote: >>>> On 26/09/2018 09:38, Thomas Huth wrote: >>>>> The uint16_t member cu_type of struct SenseId is not naturally aligned, >>>>> and since the struct is marked with QEMU_PACKED, this can lead to >>>>> unaligned memory accesses - which does not work on architectures like >>>>> Sparc. Thus remove the QEMU_PACKED here and rather copy the struct >>>>> byte by byte when we do copy_sense_id_to_guest(). >>>>> >>>>> Signed-off-by: Thomas Huth <th...@redhat.com> >>>>> --- >>>>> hw/s390x/css.c | 33 +++++++++++++++++---------------- >>>>> include/hw/s390x/css.h | 2 +- >>>>> 2 files changed, 18 insertions(+), 17 deletions(-) >>>>> >>>>> diff --git a/hw/s390x/css.c b/hw/s390x/css.c >>>>> index 5a9fe45..0e51b85 100644 >>>>> --- a/hw/s390x/css.c >>>>> +++ b/hw/s390x/css.c >>>>> @@ -750,20 +750,20 @@ static void sch_handle_halt_func(SubchDev *sch) >>>>> >>>>> } >>>>> >>>>> -static void copy_sense_id_to_guest(SenseId *dest, SenseId *src) >>>>> +static void copy_sense_id_to_guest(uint8_t *dest, SenseId *src) >>>>> { >>>>> int i; >>>>> >>>>> - dest->reserved = src->reserved; >>>>> - dest->cu_type = cpu_to_be16(src->cu_type); >>>>> - dest->cu_model = src->cu_model; >>>>> - dest->dev_type = cpu_to_be16(src->dev_type); >>>>> - dest->dev_model = src->dev_model; >>>>> - dest->unused = src->unused; >>>>> - for (i = 0; i < ARRAY_SIZE(dest->ciw); i++) { >>>>> - dest->ciw[i].type = src->ciw[i].type; >>>>> - dest->ciw[i].command = src->ciw[i].command; >>>>> - dest->ciw[i].count = cpu_to_be16(src->ciw[i].count); >>>>> + dest[0] = src->reserved; >>>>> + stw_be_p(dest + 1, src->cu_type); >>>>> + dest[3] = src->cu_model; >>>>> + stw_be_p(dest + 4, src->dev_type); >>>>> + dest[6] = src->dev_model; >>>>> + dest[7] = src->unused; >>>>> + for (i = 0; i < ARRAY_SIZE(src->ciw); i++) { >>>>> + dest[8 + i * 4] = src->ciw[i].type; >>>>> + dest[9 + i * 4] = src->ciw[i].command; >>>>> + stw_be_p(dest + 10 + i * 4, src->ciw[i].count); >>>> >>>> >>>> Not really a fan of this, as we sacrifice readability due to one >>>> unaligned member. What about only converting the unaligned members (e.g. >>>> cu_type) from uint16_t to uint8_t[2] and adding a comment why this is >>>> split. Then the structure is naturally packed. >>>> >>>> We only have to fixup the places that check cu_type. >>>> >>> >>> Just realized this was basically suggested by Peter. If it would be as >>> simple as splitting VMSTATE_UINT16 into two VMSTATE_UINT8 or similar, I >>> would prefer that. >> >> It's not that simple, it would break migration from older versions of >> QEMU due to endianness issues then. > > Migration between different QEMUs (e.g. big to little) is not supported > as far as I remember. But my head always hurts when thinking about > endianness conversions, so I am pretty sure I am missing something here.
I was not talking about migration between hosts with different endianess, but e.g. migration from a x86 host to a x86 host. If you want to send 0x1234, that would be 0x34 0x12 when using a 16-bit value, but if you break it up into hi- and low, then it's 0x12 0x34 instead. Hmm, actually the migration code seems to properly convert 16-bit values to network byte order, so maybe this could even work. But honestly, I still think we should avoid QEMU_PACKED as much as possible and better fill in the memory in copy_sense_id_to_guest() via a byte array here. As we've seen now, QEMU_PACKED can easily result in non-portable code, so even if copy_sense_id_to_guest() looks a little bit uglier now than before, it's certainly the better and more portable way to do this. Thomas