[PATCH v3 8/9] system/memory: Fix subpage endianness for big-endian targets

Djordje Todorovic posted 9 patches 3 weeks, 6 days ago
There is a newer version of this series
[PATCH v3 8/9] system/memory: Fix subpage endianness for big-endian targets
Posted by Djordje Todorovic 3 weeks, 6 days ago
The subpage memory region wrapper dispatches MMIO accesses through
flatview_read/write, which re-enters memory_region_dispatch_read/write
on the underlying device MR. The inner dispatch uses size_memop() which
strips endianness bits (effectively MO_LE), causing adjust_endianness to
apply a byte-swap for DEVICE_NATIVE_ENDIAN devices on big-endian targets.
The outer dispatch's adjust_endianness then sees matching endianness
(MO_BE == devend_BE) and does nothing, leaving the data incorrectly swapped.

Fix by changing subpage_ops from DEVICE_NATIVE_ENDIAN to DEVICE_LITTLE_ENDIAN.
This matches the implicit LE semantics of size_memop() used in the inner
dispatch, so the outer adjust_endianness correctly compensates with a
second swap, yielding the correct net result.

For little-endian targets, DEVICE_NATIVE_ENDIAN already equals LE, so
this change has zero behavioral impact.
---
 system/physmem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/system/physmem.c b/system/physmem.c
index 2fb0c25c93..5d917482eb 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -2929,7 +2929,7 @@ static const MemoryRegionOps subpage_ops = {
     .valid.min_access_size = 1,
     .valid.max_access_size = 8,
     .valid.accepts = subpage_accepts,
-    .endianness = DEVICE_NATIVE_ENDIAN,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static int subpage_register(subpage_t *mmio, uint32_t start, uint32_t end,
-- 
2.34.1
Re: [PATCH v3 8/9] system/memory: Fix subpage endianness for big-endian targets
Posted by Philippe Mathieu-Daudé 3 weeks, 6 days ago
On 11/3/26 12:59, Djordje Todorovic wrote:
> The subpage memory region wrapper dispatches MMIO accesses through
> flatview_read/write, which re-enters memory_region_dispatch_read/write
> on the underlying device MR. The inner dispatch uses size_memop() which
> strips endianness bits (effectively MO_LE), causing adjust_endianness to
> apply a byte-swap for DEVICE_NATIVE_ENDIAN devices on big-endian targets.
> The outer dispatch's adjust_endianness then sees matching endianness
> (MO_BE == devend_BE) and does nothing, leaving the data incorrectly swapped.
> 
> Fix by changing subpage_ops from DEVICE_NATIVE_ENDIAN to DEVICE_LITTLE_ENDIAN.
> This matches the implicit LE semantics of size_memop() used in the inner
> dispatch, so the outer adjust_endianness correctly compensates with a
> second swap, yielding the correct net result.
> 
> For little-endian targets, DEVICE_NATIVE_ENDIAN already equals LE, so
> this change has zero behavioral impact.
> ---
>   system/physmem.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/system/physmem.c b/system/physmem.c
> index 2fb0c25c93..5d917482eb 100644
> --- a/system/physmem.c
> +++ b/system/physmem.c
> @@ -2929,7 +2929,7 @@ static const MemoryRegionOps subpage_ops = {
>       .valid.min_access_size = 1,
>       .valid.max_access_size = 8,
>       .valid.accepts = subpage_accepts,
> -    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .endianness = DEVICE_LITTLE_ENDIAN,

NAck, this likely break big-endian hosts.

>   };
Re: [PATCH v3 8/9] system/memory: Fix subpage endianness for big-endian targets
Posted by Philippe Mathieu-Daudé 2 weeks, 6 days ago
On 11/3/26 13:19, Philippe Mathieu-Daudé wrote:
> On 11/3/26 12:59, Djordje Todorovic wrote:
>> The subpage memory region wrapper dispatches MMIO accesses through
>> flatview_read/write, which re-enters memory_region_dispatch_read/write
>> on the underlying device MR. The inner dispatch uses size_memop() which
>> strips endianness bits (effectively MO_LE), causing adjust_endianness to
>> apply a byte-swap for DEVICE_NATIVE_ENDIAN devices on big-endian targets.
>> The outer dispatch's adjust_endianness then sees matching endianness
>> (MO_BE == devend_BE) and does nothing, leaving the data incorrectly 
>> swapped.
>>
>> Fix by changing subpage_ops from DEVICE_NATIVE_ENDIAN to 
>> DEVICE_LITTLE_ENDIAN.
>> This matches the implicit LE semantics of size_memop() used in the inner
>> dispatch, so the outer adjust_endianness correctly compensates with a
>> second swap, yielding the correct net result.
>>
>> For little-endian targets, DEVICE_NATIVE_ENDIAN already equals LE, so
>> this change has zero behavioral impact.
>> ---
>>   system/physmem.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/system/physmem.c b/system/physmem.c
>> index 2fb0c25c93..5d917482eb 100644
>> --- a/system/physmem.c
>> +++ b/system/physmem.c
>> @@ -2929,7 +2929,7 @@ static const MemoryRegionOps subpage_ops = {
>>       .valid.min_access_size = 1,
>>       .valid.max_access_size = 8,
>>       .valid.accepts = subpage_accepts,
>> -    .endianness = DEVICE_NATIVE_ENDIAN,
>> +    .endianness = DEVICE_LITTLE_ENDIAN,
> 
> NAck, this likely break big-endian hosts.

(see also 
https://lore.kernel.org/qemu-devel/20251224152210.87880-4-philmd@linaro.org/ 
and Paolo's response)

>>   };
>