* [PATCH v3 0/3] semihosting/uaccess: Swap bytes based on runtime-configurable endianness
@ 2026-03-11 16:27 Martin Kröning via qemu development
2026-03-11 16:27 ` [PATCH v3 1/3] include/hw/core: Rename virtio_is_big_endian to internal_is_big_endian Martin Kröning via qemu development
` (3 more replies)
0 siblings, 4 replies; 15+ messages in thread
From: Martin Kröning via qemu development @ 2026-03-11 16:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Philippe Mathieu-Daudé, Peter Maydell,
Martin Kröning
The semihosting ABI [1] states:
> Multi-byte values in memory must be formatted as pure little-endian or pure
> big-endian to match the endianness mapping configuration of the processor.
This series ensures that semihosting data is properly byte-swapped if
the guest's CPU is currently in a different runtime-configurable
endianness than the host's CPU. This is done by adding cpu_internal_tswap()
functions and then using them in semihosting/uaccess.
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3258
Buglink: https://github.com/taiki-e/semihosting/issues/18
[1]: https://github.com/ARM-software/abi-aa/blob/2025Q1/semihosting/semihosting.rst#the-semihosting-interface
Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
---
Changes in v3:
- Remove target_needs_bswap() check from cpu_internal_tswap()
Now, only cpu_internal_needs_bswap() is checked.
This fixes the behavior on a big-endian host where the CPU currently
is in little-endian mode.
Thanks for pointing this out, Peter!
- Link to v2: https://lore.kernel.org/qemu-devel/20260227-semihosting-cpu-tswap-v2-0-cbdcdf39dd15@eonerc.rwth-aachen.de
Changes in v2:
- Rebase and resolve conflicts.
- Rename virtio_is_big_endian to internal_is_big_endian (fist commit).
- Rename new functios from cpu_tswap to cpu_internal_tswap.
- Document exceptions for using these internal functions (virtio and
semihosting).
- Link to v1: https://lore.kernel.org/qemu-devel/20260106-semihosting-cpu-tswap-v1-0-646576c25f56@eonerc.rwth-aachen.de
---
Martin Kröning (3):
include/hw/core: Rename virtio_is_big_endian to internal_is_big_endian
include/exec: Provide the cpu_internal_tswap() functions
semihosting/uaccess: Use the cpu_internal_tswap() functions
hw/core/cpu-system.c | 6 +++---
hw/virtio/virtio.c | 2 +-
include/exec/tswap.h | 36 ++++++++++++++++++++++++++++++++++++
include/hw/core/cpu.h | 4 ++--
include/hw/core/sysemu-cpu-ops.h | 6 +++---
include/semihosting/uaccess.h | 8 ++++----
target/arm/cpu.c | 4 ++--
target/ppc/cpu_init.c | 2 +-
8 files changed, 52 insertions(+), 16 deletions(-)
---
base-commit: 1fd5ff9d76d23ab23a68419cbc76d5ee33e8b455
change-id: 20260106-semihosting-cpu-tswap-b47debe274e2
Best regards,
--
Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3 1/3] include/hw/core: Rename virtio_is_big_endian to internal_is_big_endian
2026-03-11 16:27 [PATCH v3 0/3] semihosting/uaccess: Swap bytes based on runtime-configurable endianness Martin Kröning via qemu development
@ 2026-03-11 16:27 ` Martin Kröning via qemu development
2026-03-11 16:27 ` [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions Martin Kröning via qemu development
` (2 subsequent siblings)
3 siblings, 0 replies; 15+ messages in thread
From: Martin Kröning via qemu development @ 2026-03-11 16:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Philippe Mathieu-Daudé, Peter Maydell,
Martin Kröning
These functions are needed to do semihosting on CPUs that support
runtime-configurable endiannes. This commit renames them and allows
using them for semihosting, but makes sure to signal that these
functions should not be used in other circumstances.
Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/core/cpu-system.c | 6 +++---
hw/virtio/virtio.c | 2 +-
include/hw/core/cpu.h | 4 ++--
include/hw/core/sysemu-cpu-ops.h | 6 +++---
target/arm/cpu.c | 4 ++--
target/ppc/cpu_init.c | 2 +-
6 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c
index 4a91c3e8ec..273b9b7c22 100644
--- a/hw/core/cpu-system.c
+++ b/hw/core/cpu-system.c
@@ -127,10 +127,10 @@ int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
return (*cpu->cc->sysemu_ops->write_elf64_note)(f, cpu, cpuid, opaque);
}
-bool cpu_virtio_is_big_endian(CPUState *cpu)
+bool cpu_internal_is_big_endian(CPUState *cpu)
{
- if (cpu->cc->sysemu_ops->virtio_is_big_endian) {
- return cpu->cc->sysemu_ops->virtio_is_big_endian(cpu);
+ if (cpu->cc->sysemu_ops->internal_is_big_endian) {
+ return cpu->cc->sysemu_ops->internal_is_big_endian(cpu);
}
return target_big_endian();
}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 0ba734d0bc..8fcf6cfd0b 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2323,7 +2323,7 @@ static enum virtio_device_endian virtio_default_endian(void)
static enum virtio_device_endian virtio_current_cpu_endian(void)
{
- if (cpu_virtio_is_big_endian(current_cpu)) {
+ if (cpu_internal_is_big_endian(current_cpu)) {
return VIRTIO_DEVICE_ENDIAN_BIG;
} else {
return VIRTIO_DEVICE_ENDIAN_LITTLE;
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 7d2f4459d2..04e1f970ca 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -782,13 +782,13 @@ hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int cpu_asidx_from_attrs(CPUState *cpu, MemTxAttrs attrs);
/**
- * cpu_virtio_is_big_endian:
+ * cpu_internal_is_big_endian:
* @cpu: CPU
* Returns %true if a CPU which supports runtime configurable endianness
* is currently big-endian.
*/
-bool cpu_virtio_is_big_endian(CPUState *cpu);
+bool cpu_internal_is_big_endian(CPUState *cpu);
/**
* cpu_has_work:
diff --git a/include/hw/core/sysemu-cpu-ops.h b/include/hw/core/sysemu-cpu-ops.h
index 877892373f..7b2d2d2610 100644
--- a/include/hw/core/sysemu-cpu-ops.h
+++ b/include/hw/core/sysemu-cpu-ops.h
@@ -77,13 +77,13 @@ typedef struct SysemuCPUOps {
int (*write_elf64_qemunote)(WriteCoreDumpFunction f, CPUState *cpu,
DumpState *s);
/**
- * @virtio_is_big_endian: Callback to return %true if a CPU which supports
+ * @internal_is_big_endian: Callback to return %true if a CPU which supports
* runtime configurable endianness is currently big-endian.
* Non-configurable CPUs can use the default implementation of this method.
* This method should not be used by any callers other than the pre-1.0
- * virtio devices.
+ * virtio devices and the semihosting interface.
*/
- bool (*virtio_is_big_endian)(CPUState *cpu);
+ bool (*internal_is_big_endian)(CPUState *cpu);
/**
* @legacy_vmsd: Legacy state for migration.
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 7e3e84b4bb..98d09ac065 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -756,7 +756,7 @@ static void arm_cpu_set_irq(void *opaque, int irq, int level)
}
}
-static bool arm_cpu_virtio_is_big_endian(CPUState *cs)
+static bool arm_cpu_internal_is_big_endian(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
@@ -2299,7 +2299,7 @@ static const struct SysemuCPUOps arm_sysemu_ops = {
.asidx_from_attrs = arm_asidx_from_attrs,
.write_elf32_note = arm_cpu_write_elf32_note,
.write_elf64_note = arm_cpu_write_elf64_note,
- .virtio_is_big_endian = arm_cpu_virtio_is_big_endian,
+ .internal_is_big_endian = arm_cpu_internal_is_big_endian,
.legacy_vmsd = &vmstate_arm_cpu,
};
#endif
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 3d932a5642..191f5726f6 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7480,7 +7480,7 @@ static const struct SysemuCPUOps ppc_sysemu_ops = {
.get_phys_page_debug = ppc_cpu_get_phys_page_debug,
.write_elf32_note = ppc32_cpu_write_elf32_note,
.write_elf64_note = ppc64_cpu_write_elf64_note,
- .virtio_is_big_endian = ppc_cpu_is_big_endian,
+ .internal_is_big_endian = ppc_cpu_is_big_endian,
.legacy_vmsd = &vmstate_ppc_cpu,
};
#endif
--
Git-155)
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions
2026-03-11 16:27 [PATCH v3 0/3] semihosting/uaccess: Swap bytes based on runtime-configurable endianness Martin Kröning via qemu development
2026-03-11 16:27 ` [PATCH v3 1/3] include/hw/core: Rename virtio_is_big_endian to internal_is_big_endian Martin Kröning via qemu development
@ 2026-03-11 16:27 ` Martin Kröning via qemu development
2026-03-12 18:29 ` Peter Maydell
2026-03-12 19:29 ` Philippe Mathieu-Daudé
2026-03-11 16:27 ` [PATCH v3 3/3] semihosting/uaccess: Use " Martin Kröning via qemu development
2026-03-12 18:35 ` [PATCH v3 0/3] semihosting/uaccess: Swap bytes based on runtime-configurable endianness Peter Maydell
3 siblings, 2 replies; 15+ messages in thread
From: Martin Kröning via qemu development @ 2026-03-11 16:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Philippe Mathieu-Daudé, Peter Maydell,
Martin Kröning
These functions are needed to support semihosting on CPUs that support
runtime-configurable endianness. They should not be used in other contexts.
Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
---
include/exec/tswap.h | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/include/exec/tswap.h b/include/exec/tswap.h
index 9e94fa0021..17ac544454 100644
--- a/include/exec/tswap.h
+++ b/include/exec/tswap.h
@@ -10,6 +10,7 @@
#include "qemu/bswap.h"
#include "qemu/target-info.h"
+#include "hw/core/cpu.h"
/*
* If we're in target-specific code, we can hard-code the swapping
@@ -72,4 +73,39 @@ static inline void tswap64s(uint64_t *s)
}
#endif
+/*
+ * If we're in semihosting code, have to swap depending on the currently
+ * configured endianness of the CPU. These functions should not be used in
+ * other contexts.
+ */
+#define cpu_internal_needs_bswap(cpu) \
+ (HOST_BIG_ENDIAN != cpu_internal_is_big_endian(cpu))
+
+static inline uint16_t cpu_internal_tswap16(CPUState *cpu, uint16_t s)
+{
+ if (cpu_internal_needs_bswap(cpu)) {
+ return bswap16(s);
+ } else {
+ return s;
+ }
+}
+
+static inline uint32_t cpu_internal_tswap32(CPUState *cpu, uint32_t s)
+{
+ if (cpu_internal_needs_bswap(cpu)) {
+ return bswap32(s);
+ } else {
+ return s;
+ }
+}
+
+static inline uint64_t cpu_internal_tswap64(CPUState *cpu, uint64_t s)
+{
+ if (cpu_internal_needs_bswap(cpu)) {
+ return bswap64(s);
+ } else {
+ return s;
+ }
+}
+
#endif /* TSWAP_H */
--
Git-155)
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 3/3] semihosting/uaccess: Use the cpu_internal_tswap() functions
2026-03-11 16:27 [PATCH v3 0/3] semihosting/uaccess: Swap bytes based on runtime-configurable endianness Martin Kröning via qemu development
2026-03-11 16:27 ` [PATCH v3 1/3] include/hw/core: Rename virtio_is_big_endian to internal_is_big_endian Martin Kröning via qemu development
2026-03-11 16:27 ` [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions Martin Kröning via qemu development
@ 2026-03-11 16:27 ` Martin Kröning via qemu development
2026-03-12 19:30 ` Philippe Mathieu-Daudé
2026-03-12 18:35 ` [PATCH v3 0/3] semihosting/uaccess: Swap bytes based on runtime-configurable endianness Peter Maydell
3 siblings, 1 reply; 15+ messages in thread
From: Martin Kröning via qemu development @ 2026-03-11 16:27 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Philippe Mathieu-Daudé, Peter Maydell,
Martin Kröning
The semihosting ABI [1] states:
> Multi-byte values in memory must be formatted as pure little-endian or pure
> big-endian to match the endianness mapping configuration of the processor.
This commits ensures that semihosting data is properly byte-swapped if
the guest's CPU is currently in a different runtime-configurable
endianness than the host's CPU.
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3258
Buglink: https://github.com/taiki-e/semihosting/issues/18
[1]: https://github.com/ARM-software/abi-aa/blob/2025Q1/semihosting/semihosting.rst#the-semihosting-interface
Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
include/semihosting/uaccess.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/include/semihosting/uaccess.h b/include/semihosting/uaccess.h
index 2093a49827..0911e3b31d 100644
--- a/include/semihosting/uaccess.h
+++ b/include/semihosting/uaccess.h
@@ -28,7 +28,7 @@
({ uint64_t val_ = 0; \
int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \
&val_, sizeof(val_), 0); \
- (val) = tswap64(val_); ret_; })
+ (val) = cpu_internal_tswap64(cs, val_); ret_; })
/**
* get_user_u32:
@@ -39,7 +39,7 @@
({ uint32_t val_ = 0; \
int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \
&val_, sizeof(val_), 0); \
- (val) = tswap32(val_); ret_; })
+ (val) = cpu_internal_tswap32(cs, val_); ret_; })
/**
* get_user_u8:
@@ -65,7 +65,7 @@
* Returns: 0 on success, -1 on error.
*/
#define put_user_u64(val, addr) \
- ({ uint64_t val_ = tswap64(val); \
+ ({ uint64_t val_ = cpu_internal_tswap64(cs, val); \
cpu_memory_rw_debug(env_cpu(env), (addr), &val_, sizeof(val_), 1); })
/**
@@ -74,7 +74,7 @@
* Returns: 0 on success, -1 on error.
*/
#define put_user_u32(val, addr) \
- ({ uint32_t val_ = tswap32(val); \
+ ({ uint32_t val_ = cpu_internal_tswap32(cs, val); \
cpu_memory_rw_debug(env_cpu(env), (addr), &val_, sizeof(val_), 1); })
/**
--
Git-155)
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions
2026-03-11 16:27 ` [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions Martin Kröning via qemu development
@ 2026-03-12 18:29 ` Peter Maydell
2026-03-12 19:29 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 15+ messages in thread
From: Peter Maydell @ 2026-03-12 18:29 UTC (permalink / raw)
To: Martin Kröning
Cc: qemu-devel, Alex Bennée, Philippe Mathieu-Daudé
On Wed, 11 Mar 2026 at 16:28, Martin Kröning
<martin.kroening@eonerc.rwth-aachen.de> wrote:
>
> These functions are needed to support semihosting on CPUs that support
> runtime-configurable endianness. They should not be used in other contexts.
>
> Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
> ---
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
thanks
-- PMM
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 0/3] semihosting/uaccess: Swap bytes based on runtime-configurable endianness
2026-03-11 16:27 [PATCH v3 0/3] semihosting/uaccess: Swap bytes based on runtime-configurable endianness Martin Kröning via qemu development
` (2 preceding siblings ...)
2026-03-11 16:27 ` [PATCH v3 3/3] semihosting/uaccess: Use " Martin Kröning via qemu development
@ 2026-03-12 18:35 ` Peter Maydell
2026-03-12 19:17 ` Philippe Mathieu-Daudé
3 siblings, 1 reply; 15+ messages in thread
From: Peter Maydell @ 2026-03-12 18:35 UTC (permalink / raw)
To: Martin Kröning
Cc: qemu-devel, Alex Bennée, Philippe Mathieu-Daudé
On Wed, 11 Mar 2026 at 16:28, Martin Kröning
<martin.kroening@eonerc.rwth-aachen.de> wrote:
>
> The semihosting ABI [1] states:
> > Multi-byte values in memory must be formatted as pure little-endian or pure
> > big-endian to match the endianness mapping configuration of the processor.
>
> This series ensures that semihosting data is properly byte-swapped if
> the guest's CPU is currently in a different runtime-configurable
> endianness than the host's CPU. This is done by adding cpu_internal_tswap()
> functions and then using them in semihosting/uaccess.
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3258
> Buglink: https://github.com/taiki-e/semihosting/issues/18
>
> [1]: https://github.com/ARM-software/abi-aa/blob/2025Q1/semihosting/semihosting.rst#the-semihosting-interface
>
> Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
Applied to target-arm.next, thanks.
-- PMM
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 0/3] semihosting/uaccess: Swap bytes based on runtime-configurable endianness
2026-03-12 18:35 ` [PATCH v3 0/3] semihosting/uaccess: Swap bytes based on runtime-configurable endianness Peter Maydell
@ 2026-03-12 19:17 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 15+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-03-12 19:17 UTC (permalink / raw)
To: Peter Maydell, Martin Kröning; +Cc: qemu-devel, Alex Bennée
On 12/3/26 19:35, Peter Maydell wrote:
> On Wed, 11 Mar 2026 at 16:28, Martin Kröning
> <martin.kroening@eonerc.rwth-aachen.de> wrote:
>>
>> The semihosting ABI [1] states:
>>> Multi-byte values in memory must be formatted as pure little-endian or pure
>>> big-endian to match the endianness mapping configuration of the processor.
>>
>> This series ensures that semihosting data is properly byte-swapped if
>> the guest's CPU is currently in a different runtime-configurable
>> endianness than the host's CPU. This is done by adding cpu_internal_tswap()
>> functions and then using them in semihosting/uaccess.
>>
>> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3258
>> Buglink: https://github.com/taiki-e/semihosting/issues/18
>>
>> [1]: https://github.com/ARM-software/abi-aa/blob/2025Q1/semihosting/semihosting.rst#the-semihosting-interface
>>
>> Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
>
> Applied to target-arm.next, thanks.
FYI I was not ignoring this series, just postponed until freeze date,
and was looking at it earlier today. Interestingly this also fixes
my issues with m68k! So I'm glad to provide:
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions
2026-03-11 16:27 ` [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions Martin Kröning via qemu development
2026-03-12 18:29 ` Peter Maydell
@ 2026-03-12 19:29 ` Philippe Mathieu-Daudé
2026-03-12 19:30 ` Peter Maydell
1 sibling, 1 reply; 15+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-03-12 19:29 UTC (permalink / raw)
To: Martin Kröning, qemu-devel; +Cc: Alex Bennée, Peter Maydell
On 11/3/26 17:27, Martin Kröning wrote:
> These functions are needed to support semihosting on CPUs that support
> runtime-configurable endianness. They should not be used in other contexts.
Another note is these function are not target-specific, which is great!
These can also be used outside of semihosting.
Matter of taste I'd have named them using this shorter pattern:
cpu_internal_tswap16() -> tswap16_cpu()
>
> Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
> ---
> include/exec/tswap.h | 36 ++++++++++++++++++++++++++++++++++++
> 1 file changed, 36 insertions(+)
>
> diff --git a/include/exec/tswap.h b/include/exec/tswap.h
> index 9e94fa0021..17ac544454 100644
> --- a/include/exec/tswap.h
> +++ b/include/exec/tswap.h
> @@ -10,6 +10,7 @@
>
> #include "qemu/bswap.h"
> #include "qemu/target-info.h"
> +#include "hw/core/cpu.h"
>
> /*
> * If we're in target-specific code, we can hard-code the swapping
> @@ -72,4 +73,39 @@ static inline void tswap64s(uint64_t *s)
> }
> #endif
>
> +/*
> + * If we're in semihosting code, have to swap depending on the currently
> + * configured endianness of the CPU. These functions should not be used in
> + * other contexts.
> + */
> +#define cpu_internal_needs_bswap(cpu) \
> + (HOST_BIG_ENDIAN != cpu_internal_is_big_endian(cpu))
> +
> +static inline uint16_t cpu_internal_tswap16(CPUState *cpu, uint16_t s)
> +{
> + if (cpu_internal_needs_bswap(cpu)) {
> + return bswap16(s);
> + } else {
> + return s;
> + }
> +}
> +
> +static inline uint32_t cpu_internal_tswap32(CPUState *cpu, uint32_t s)
> +{
> + if (cpu_internal_needs_bswap(cpu)) {
> + return bswap32(s);
> + } else {
> + return s;
> + }
> +}
> +
> +static inline uint64_t cpu_internal_tswap64(CPUState *cpu, uint64_t s)
> +{
> + if (cpu_internal_needs_bswap(cpu)) {
> + return bswap64(s);
> + } else {
> + return s;
> + }
> +}
> +
> #endif /* TSWAP_H */
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 3/3] semihosting/uaccess: Use the cpu_internal_tswap() functions
2026-03-11 16:27 ` [PATCH v3 3/3] semihosting/uaccess: Use " Martin Kröning via qemu development
@ 2026-03-12 19:30 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 15+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-03-12 19:30 UTC (permalink / raw)
To: Martin Kröning, qemu-devel
Cc: Alex Bennée, Peter Maydell, Pierrick Bouvier
On 11/3/26 17:27, Martin Kröning wrote:
> The semihosting ABI [1] states:
>> Multi-byte values in memory must be formatted as pure little-endian or pure
>> big-endian to match the endianness mapping configuration of the processor.
>
> This commits ensures that semihosting data is properly byte-swapped if
> the guest's CPU is currently in a different runtime-configurable
> endianness than the host's CPU.
This patch also remove the target-specificity in semihosting,
which is an excellent news for me \o/
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3258
> Buglink: https://github.com/taiki-e/semihosting/issues/18
>
> [1]: https://github.com/ARM-software/abi-aa/blob/2025Q1/semihosting/semihosting.rst#the-semihosting-interface
>
> Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> include/semihosting/uaccess.h | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/include/semihosting/uaccess.h b/include/semihosting/uaccess.h
> index 2093a49827..0911e3b31d 100644
> --- a/include/semihosting/uaccess.h
> +++ b/include/semihosting/uaccess.h
> @@ -28,7 +28,7 @@
> ({ uint64_t val_ = 0; \
> int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \
> &val_, sizeof(val_), 0); \
> - (val) = tswap64(val_); ret_; })
> + (val) = cpu_internal_tswap64(cs, val_); ret_; })
>
> /**
> * get_user_u32:
> @@ -39,7 +39,7 @@
> ({ uint32_t val_ = 0; \
> int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \
> &val_, sizeof(val_), 0); \
> - (val) = tswap32(val_); ret_; })
> + (val) = cpu_internal_tswap32(cs, val_); ret_; })
>
> /**
> * get_user_u8:
> @@ -65,7 +65,7 @@
> * Returns: 0 on success, -1 on error.
> */
> #define put_user_u64(val, addr) \
> - ({ uint64_t val_ = tswap64(val); \
> + ({ uint64_t val_ = cpu_internal_tswap64(cs, val); \
> cpu_memory_rw_debug(env_cpu(env), (addr), &val_, sizeof(val_), 1); })
>
> /**
> @@ -74,7 +74,7 @@
> * Returns: 0 on success, -1 on error.
> */
> #define put_user_u32(val, addr) \
> - ({ uint32_t val_ = tswap32(val); \
> + ({ uint32_t val_ = cpu_internal_tswap32(cs, val); \
> cpu_memory_rw_debug(env_cpu(env), (addr), &val_, sizeof(val_), 1); })
>
> /**
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions
2026-03-12 19:29 ` Philippe Mathieu-Daudé
@ 2026-03-12 19:30 ` Peter Maydell
2026-03-12 19:37 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 15+ messages in thread
From: Peter Maydell @ 2026-03-12 19:30 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Martin Kröning, qemu-devel, Alex Bennée
On Thu, 12 Mar 2026 at 19:29, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>
> On 11/3/26 17:27, Martin Kröning wrote:
> > These functions are needed to support semihosting on CPUs that support
> > runtime-configurable endianness. They should not be used in other contexts.
>
> Another note is these function are not target-specific, which is great!
>
> These can also be used outside of semihosting.
>
> Matter of taste I'd have named them using this shorter pattern:
>
> cpu_internal_tswap16() -> tswap16_cpu()
We specifically didn't want to use a name that might tempt
people to use them -- these are only wanted for the very
few niche use cases that are outside the CPU but need to
know information about the CPU's internals, which is basically
legacy-virtio and semihosting.
-- PMM
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions
2026-03-12 19:30 ` Peter Maydell
@ 2026-03-12 19:37 ` Philippe Mathieu-Daudé
2026-03-12 19:38 ` Philippe Mathieu-Daudé
2026-03-13 8:51 ` Peter Maydell
0 siblings, 2 replies; 15+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-03-12 19:37 UTC (permalink / raw)
To: Peter Maydell
Cc: Martin Kröning, qemu-devel, Alex Bennée,
Pierrick Bouvier
On 12/3/26 20:30, Peter Maydell wrote:
> On Thu, 12 Mar 2026 at 19:29, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>>
>> On 11/3/26 17:27, Martin Kröning wrote:
>>> These functions are needed to support semihosting on CPUs that support
>>> runtime-configurable endianness. They should not be used in other contexts.
>>
>> Another note is these function are not target-specific, which is great!
>>
>> These can also be used outside of semihosting.
>>
>> Matter of taste I'd have named them using this shorter pattern:
>>
>> cpu_internal_tswap16() -> tswap16_cpu()
>
> We specifically didn't want to use a name that might tempt
> people to use them -- these are only wanted for the very
> few niche use cases that are outside the CPU but need to
> know information about the CPU's internals, which is basically
> legacy-virtio and semihosting.
This was the missing piece to make qtest target-agnostic:
-- >8 --
diff --git a/system/qtest.c b/system/qtest.c
index cf90cd53adb..392c1394656 100644
--- a/system/qtest.c
+++ b/system/qtest.c
@@ -523,18 +523,15 @@ static void qtest_process_command(CharFrontend
*chr, gchar **words)
address_space_write(first_cpu->as, addr,
MEMTXATTRS_UNSPECIFIED,
&data, 1);
} else if (words[0][5] == 'w') {
- uint16_t data = value;
- tswap16s(&data);
+ uint16_t data = cpu_internal_tswap16(first_cpu, value);
address_space_write(first_cpu->as, addr,
MEMTXATTRS_UNSPECIFIED,
&data, 2);
} else if (words[0][5] == 'l') {
- uint32_t data = value;
- tswap32s(&data);
+ uint32_t data = cpu_internal_tswap32(first_cpu, value);
address_space_write(first_cpu->as, addr,
MEMTXATTRS_UNSPECIFIED,
&data, 4);
} else if (words[0][5] == 'q') {
- uint64_t data = value;
- tswap64s(&data);
+ uint64_t data = cpu_internal_tswap64(first_cpu, value);
address_space_write(first_cpu->as, addr,
MEMTXATTRS_UNSPECIFIED,
&data, 8);
}
---
QTest is already dubious by always accessing the first CPU AS, so
using the first CPU endianness is good enough for me IMO. (Ideally
QTest would support multiple address-spaces).
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions
2026-03-12 19:37 ` Philippe Mathieu-Daudé
@ 2026-03-12 19:38 ` Philippe Mathieu-Daudé
2026-03-13 8:51 ` Peter Maydell
1 sibling, 0 replies; 15+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-03-12 19:38 UTC (permalink / raw)
To: Peter Maydell
Cc: Martin Kröning, qemu-devel, Alex Bennée,
Pierrick Bouvier
On Thu, 12 Mar 2026 at 20:37, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>
> On 12/3/26 20:30, Peter Maydell wrote:
> > On Thu, 12 Mar 2026 at 19:29, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
> >>
> >> On 11/3/26 17:27, Martin Kröning wrote:
> >>> These functions are needed to support semihosting on CPUs that support
> >>> runtime-configurable endianness. They should not be used in other contexts.
> >>
> >> Another note is these function are not target-specific, which is great!
> >>
> >> These can also be used outside of semihosting.
> >>
> >> Matter of taste I'd have named them using this shorter pattern:
> >>
> >> cpu_internal_tswap16() -> tswap16_cpu()
> >
> > We specifically didn't want to use a name that might tempt
> > people to use them -- these are only wanted for the very
> > few niche use cases that are outside the CPU but need to
> > know information about the CPU's internals, which is basically
> > legacy-virtio and semihosting.
>
> This was the missing piece to make qtest target-agnostic:
>
> -- >8 --
> diff --git a/system/qtest.c b/system/qtest.c
> index cf90cd53adb..392c1394656 100644
> --- a/system/qtest.c
> +++ b/system/qtest.c
> @@ -523,18 +523,15 @@ static void qtest_process_command(CharFrontend
> *chr, gchar **words)
> address_space_write(first_cpu->as, addr,
> MEMTXATTRS_UNSPECIFIED,
> &data, 1);
> } else if (words[0][5] == 'w') {
> - uint16_t data = value;
> - tswap16s(&data);
> + uint16_t data = cpu_internal_tswap16(first_cpu, value);
> address_space_write(first_cpu->as, addr,
> MEMTXATTRS_UNSPECIFIED,
> &data, 2);
> } else if (words[0][5] == 'l') {
> - uint32_t data = value;
> - tswap32s(&data);
> + uint32_t data = cpu_internal_tswap32(first_cpu, value);
> address_space_write(first_cpu->as, addr,
> MEMTXATTRS_UNSPECIFIED,
> &data, 4);
> } else if (words[0][5] == 'q') {
> - uint64_t data = value;
> - tswap64s(&data);
> + uint64_t data = cpu_internal_tswap64(first_cpu, value);
> address_space_write(first_cpu->as, addr,
> MEMTXATTRS_UNSPECIFIED,
> &data, 8);
> }
> ---
>
> QTest is already dubious by always accessing the first CPU AS, so
> using the first CPU endianness is good enough for me IMO. (Ideally
> QTest would support multiple address-spaces).
And these endianness checks in QTest framework are only there to test
legacy virtio, so we are good, this isn't even another niche use case.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions
2026-03-12 19:37 ` Philippe Mathieu-Daudé
2026-03-12 19:38 ` Philippe Mathieu-Daudé
@ 2026-03-13 8:51 ` Peter Maydell
2026-03-15 14:07 ` Philippe Mathieu-Daudé
1 sibling, 1 reply; 15+ messages in thread
From: Peter Maydell @ 2026-03-13 8:51 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Martin Kröning, qemu-devel, Alex Bennée,
Pierrick Bouvier
On Thu, 12 Mar 2026 at 19:37, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>
> On 12/3/26 20:30, Peter Maydell wrote:
> > On Thu, 12 Mar 2026 at 19:29, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
> >>
> >> On 11/3/26 17:27, Martin Kröning wrote:
> >>> These functions are needed to support semihosting on CPUs that support
> >>> runtime-configurable endianness. They should not be used in other contexts.
> >>
> >> Another note is these function are not target-specific, which is great!
> >>
> >> These can also be used outside of semihosting.
> >>
> >> Matter of taste I'd have named them using this shorter pattern:
> >>
> >> cpu_internal_tswap16() -> tswap16_cpu()
> >
> > We specifically didn't want to use a name that might tempt
> > people to use them -- these are only wanted for the very
> > few niche use cases that are outside the CPU but need to
> > know information about the CPU's internals, which is basically
> > legacy-virtio and semihosting.
>
> This was the missing piece to make qtest target-agnostic:
>
> -- >8 --
> diff --git a/system/qtest.c b/system/qtest.c
> index cf90cd53adb..392c1394656 100644
> --- a/system/qtest.c
> +++ b/system/qtest.c
> @@ -523,18 +523,15 @@ static void qtest_process_command(CharFrontend
> *chr, gchar **words)
> address_space_write(first_cpu->as, addr,
> MEMTXATTRS_UNSPECIFIED,
> &data, 1);
> } else if (words[0][5] == 'w') {
> - uint16_t data = value;
> - tswap16s(&data);
> + uint16_t data = cpu_internal_tswap16(first_cpu, value);
This is a behaviour change, and I don't think we want it.
tswap16s() swaps per the system endianness. cpu_internal_tswap16()
swaps based on the CPU's current configuration. With qtest
that's a bit of a weird thing, because we can never run the
CPU in a way that will make it switch endianness.
This is why we gave these functions the _internal_ bit in
the name -- they really are a very very specific piece
of functionality that you almost never want.
> And these endianness checks in QTest framework are only there to test
> legacy virtio, so we are good, this isn't even another niche use case.
No, these ones are here so that when when a test does a read
or write of non-byte width data (e.g. via "writel 0x8000 0x12345678")
we send it into the memory system in the endianness that it
expects, so that it arrives at the device as "write of width 4
with value 0x12345678". That is, we want to match it to the
system endianness, because that's what we want to cancel out
the swapping done in adjust_endianness() in system/memory.c.
thanks
-- PMM
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions
2026-03-13 8:51 ` Peter Maydell
@ 2026-03-15 14:07 ` Philippe Mathieu-Daudé
2026-03-16 10:03 ` Peter Maydell
0 siblings, 1 reply; 15+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-03-15 14:07 UTC (permalink / raw)
To: Peter Maydell
Cc: Martin Kröning, qemu-devel, Alex Bennée,
Pierrick Bouvier
On 13/3/26 09:51, Peter Maydell wrote:
> On Thu, 12 Mar 2026 at 19:37, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>>
>> On 12/3/26 20:30, Peter Maydell wrote:
>>> On Thu, 12 Mar 2026 at 19:29, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>>>>
>>>> On 11/3/26 17:27, Martin Kröning wrote:
>>>>> These functions are needed to support semihosting on CPUs that support
>>>>> runtime-configurable endianness. They should not be used in other contexts.
>>>>
>>>> Another note is these function are not target-specific, which is great!
>>>>
>>>> These can also be used outside of semihosting.
>>>>
>>>> Matter of taste I'd have named them using this shorter pattern:
>>>>
>>>> cpu_internal_tswap16() -> tswap16_cpu()
>>>
>>> We specifically didn't want to use a name that might tempt
>>> people to use them -- these are only wanted for the very
>>> few niche use cases that are outside the CPU but need to
>>> know information about the CPU's internals, which is basically
>>> legacy-virtio and semihosting.
>>
>> This was the missing piece to make qtest target-agnostic:
>>
>> -- >8 --
>> diff --git a/system/qtest.c b/system/qtest.c
>> index cf90cd53adb..392c1394656 100644
>> --- a/system/qtest.c
>> +++ b/system/qtest.c
>> @@ -523,18 +523,15 @@ static void qtest_process_command(CharFrontend
>> *chr, gchar **words)
>> address_space_write(first_cpu->as, addr,
>> MEMTXATTRS_UNSPECIFIED,
>> &data, 1);
>> } else if (words[0][5] == 'w') {
>> - uint16_t data = value;
>> - tswap16s(&data);
>> + uint16_t data = cpu_internal_tswap16(first_cpu, value);
>
> This is a behaviour change, and I don't think we want it.
> tswap16s() swaps per the system endianness. cpu_internal_tswap16()
> swaps based on the CPU's current configuration. With qtest
> that's a bit of a weird thing, because we can never run the
> CPU in a way that will make it switch endianness.
>
> This is why we gave these functions the _internal_ bit in
> the name -- they really are a very very specific piece
> of functionality that you almost never want.
>
>> And these endianness checks in QTest framework are only there to test
>> legacy virtio, so we are good, this isn't even another niche use case.
>
> No, these ones are here so that when when a test does a read
> or write of non-byte width data (e.g. via "writel 0x8000 0x12345678")
> we send it into the memory system in the endianness that it
> expects, so that it arrives at the device as "write of width 4
> with value 0x12345678". That is, we want to match it to the
> system endianness, because that's what we want to cancel out
> the swapping done in adjust_endianness() in system/memory.c.
What do you mean by "system endianness"? The default endianness picked
for a particular qemu-system-foo binary?
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions
2026-03-15 14:07 ` Philippe Mathieu-Daudé
@ 2026-03-16 10:03 ` Peter Maydell
0 siblings, 0 replies; 15+ messages in thread
From: Peter Maydell @ 2026-03-16 10:03 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Martin Kröning, qemu-devel, Alex Bennée,
Pierrick Bouvier
On Sun, 15 Mar 2026 at 14:07, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>
> On 13/3/26 09:51, Peter Maydell wrote:
> > No, these ones are here so that when when a test does a read
> > or write of non-byte width data (e.g. via "writel 0x8000 0x12345678")
> > we send it into the memory system in the endianness that it
> > expects, so that it arrives at the device as "write of width 4
> > with value 0x12345678". That is, we want to match it to the
> > system endianness, because that's what we want to cancel out
> > the swapping done in adjust_endianness() in system/memory.c.
>
> What do you mean by "system endianness"? The default endianness picked
> for a particular qemu-system-foo binary?
I mean whether TARGET_BIG_ENDIAN is set -- the effective
endianness of the whole system, which affects whether
the core memory system thinks it needs to byteswap data
that passes through it.
That's different from what the CPU does internally for things like
Arm CPSR.E. An Arm system is always little-endian at the
system level, regardless of CPSR.E. Setting CPSR.E just makes
the CPU byteswap data before sending it out of the CPU to the
system. (That's how it works in hardware as well as QEMU.)
thanks
-- PMM
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-03-16 10:04 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-11 16:27 [PATCH v3 0/3] semihosting/uaccess: Swap bytes based on runtime-configurable endianness Martin Kröning via qemu development
2026-03-11 16:27 ` [PATCH v3 1/3] include/hw/core: Rename virtio_is_big_endian to internal_is_big_endian Martin Kröning via qemu development
2026-03-11 16:27 ` [PATCH v3 2/3] include/exec: Provide the cpu_internal_tswap() functions Martin Kröning via qemu development
2026-03-12 18:29 ` Peter Maydell
2026-03-12 19:29 ` Philippe Mathieu-Daudé
2026-03-12 19:30 ` Peter Maydell
2026-03-12 19:37 ` Philippe Mathieu-Daudé
2026-03-12 19:38 ` Philippe Mathieu-Daudé
2026-03-13 8:51 ` Peter Maydell
2026-03-15 14:07 ` Philippe Mathieu-Daudé
2026-03-16 10:03 ` Peter Maydell
2026-03-11 16:27 ` [PATCH v3 3/3] semihosting/uaccess: Use " Martin Kröning via qemu development
2026-03-12 19:30 ` Philippe Mathieu-Daudé
2026-03-12 18:35 ` [PATCH v3 0/3] semihosting/uaccess: Swap bytes based on runtime-configurable endianness Peter Maydell
2026-03-12 19:17 ` Philippe Mathieu-Daudé
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox