[RFC 25/26] rust/memory: Add binding to check target endian

Zhao Liu posted 26 patches 4 months, 1 week ago
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, Peter Xu <peterx@redhat.com>, David Hildenbrand <david@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Manos Pitsidianakis <manos.pitsidianakis@linaro.org>, "Alex Bennée" <alex.bennee@linaro.org>, Thomas Huth <thuth@redhat.com>
[RFC 25/26] rust/memory: Add binding to check target endian
Posted by Zhao Liu 4 months, 1 week ago
Add a binding (target_is_big_endian()) to check whether target is big
endian or not. This could help user to adjust endian before calling
AddresssSpace::store() or after calling AddressSpace::load().

Add the example in the documentation of AddresssSpace::store() to help
explain how to use it.

Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
 rust/qemu-api/src/memory.rs | 28 +++++++++++++++++++++++++---
 rust/qemu-api/wrapper.h     |  1 +
 2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/rust/qemu-api/src/memory.rs b/rust/qemu-api/src/memory.rs
index 42bba23cf3f8..a8eb83c95ead 100644
--- a/rust/qemu-api/src/memory.rs
+++ b/rust/qemu-api/src/memory.rs
@@ -31,7 +31,7 @@
         memory_region_init_io, section_access_allowed, section_covers_region_addr,
         section_fuzz_dma_read, section_get_host_addr, section_rust_load,
         section_rust_read_continue_step, section_rust_store, section_rust_write_continue_step,
-        MEMTX_OK,
+        target_big_endian, MEMTX_OK,
     },
     callbacks::FnCall,
     cell::Opaque,
@@ -1107,9 +1107,25 @@ pub fn read(&self, buf: &mut [u8], addr: GuestAddress) -> Result<usize> {
     /// This function is similar to `address_space_st{size}` in C side.
     ///
     /// But it only assumes @val follows target-endian by default. So ensure
-    /// the endian of `val` aligned with target, before using this method.
+    /// the endian of `val` aligned with target, before using this method.  The
+    /// taget-endian can be checked with [`target_is_big_endian`].
     ///
     /// And it assumes the memory attributes is MEMTXATTRS_UNSPECIFIED.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use qemu_api::memory::{ADDRESS_SPACE_MEMORY, target_is_big_endian};
+    ///
+    /// let addr = GuestAddress(0x123438000);
+    /// let val: u32 = 5;
+    /// let val_end = if target_is_big_endian() {
+    ///     val.to_be()
+    /// } else {
+    ///     val.to_le()
+    /// }
+    ///
+    /// assert!(ADDRESS_SPACE_MEMORY.store(addr, val_end).is_ok());
     pub fn store<T: AtomicAccess>(&self, addr: GuestAddress, val: T) -> Result<()> {
         rcu_read_lock();
         let r = self.memory().deref().store(val, addr, Ordering::Relaxed);
@@ -1122,7 +1138,8 @@ pub fn store<T: AtomicAccess>(&self, addr: GuestAddress, val: T) -> Result<()> {
     /// This function is similar to `address_space_ld{size}` in C side.
     ///
     /// But it only support target-endian by default.  The returned value is
-    /// with target-endian.
+    /// with target-endian.  The taget-endian can be checked with
+    /// [`target_is_big_endian`].
     ///
     /// And it assumes the memory attributes is MEMTXATTRS_UNSPECIFIED.
     pub fn load<T: AtomicAccess>(&self, addr: GuestAddress) -> Result<T> {
@@ -1147,3 +1164,8 @@ pub fn load<T: AtomicAccess>(&self, addr: GuestAddress) -> Result<T> {
     // the whole QEMU life.
     &*wrapper_ptr
 };
+
+pub fn target_is_big_endian() -> bool {
+    // SAFETY: the return value is boolean, so it is always valid.
+    unsafe { target_big_endian() }
+}
diff --git a/rust/qemu-api/wrapper.h b/rust/qemu-api/wrapper.h
index ce0ac8d3f550..c466b93054aa 100644
--- a/rust/qemu-api/wrapper.h
+++ b/rust/qemu-api/wrapper.h
@@ -70,3 +70,4 @@ typedef enum memory_order {
 #include "system/address-spaces.h"
 #include "hw/char/pl011.h"
 #include "qemu/rcu.h"
+#include "qemu/target-info.h"
-- 
2.34.1
Re: [RFC 25/26] rust/memory: Add binding to check target endian
Posted by Manos Pitsidianakis 4 months, 1 week ago
On Thu, Aug 7, 2025 at 3:10 PM Zhao Liu <zhao1.liu@intel.com> wrote:
>
> Add a binding (target_is_big_endian()) to check whether target is big
> endian or not. This could help user to adjust endian before calling

s/adjust endian/adjust endianness/

> AddresssSpace::store() or after calling AddressSpace::load().

No strong preference, but maybe we can keep the same name as C,
target_big_endian()? Just for consistency.

Either way:

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

>
> Add the example in the documentation of AddresssSpace::store() to help
> explain how to use it.
>
> Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
> ---
>  rust/qemu-api/src/memory.rs | 28 +++++++++++++++++++++++++---
>  rust/qemu-api/wrapper.h     |  1 +
>  2 files changed, 26 insertions(+), 3 deletions(-)
>
> diff --git a/rust/qemu-api/src/memory.rs b/rust/qemu-api/src/memory.rs
> index 42bba23cf3f8..a8eb83c95ead 100644
> --- a/rust/qemu-api/src/memory.rs
> +++ b/rust/qemu-api/src/memory.rs
> @@ -31,7 +31,7 @@
>          memory_region_init_io, section_access_allowed, section_covers_region_addr,
>          section_fuzz_dma_read, section_get_host_addr, section_rust_load,
>          section_rust_read_continue_step, section_rust_store, section_rust_write_continue_step,
> -        MEMTX_OK,
> +        target_big_endian, MEMTX_OK,
>      },
>      callbacks::FnCall,
>      cell::Opaque,
> @@ -1107,9 +1107,25 @@ pub fn read(&self, buf: &mut [u8], addr: GuestAddress) -> Result<usize> {
>      /// This function is similar to `address_space_st{size}` in C side.
>      ///
>      /// But it only assumes @val follows target-endian by default. So ensure
> -    /// the endian of `val` aligned with target, before using this method.
> +    /// the endian of `val` aligned with target, before using this method.  The
> +    /// taget-endian can be checked with [`target_is_big_endian`].
>      ///
>      /// And it assumes the memory attributes is MEMTXATTRS_UNSPECIFIED.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// use qemu_api::memory::{ADDRESS_SPACE_MEMORY, target_is_big_endian};
> +    ///
> +    /// let addr = GuestAddress(0x123438000);
> +    /// let val: u32 = 5;
> +    /// let val_end = if target_is_big_endian() {
> +    ///     val.to_be()
> +    /// } else {
> +    ///     val.to_le()
> +    /// }
> +    ///
> +    /// assert!(ADDRESS_SPACE_MEMORY.store(addr, val_end).is_ok());
>      pub fn store<T: AtomicAccess>(&self, addr: GuestAddress, val: T) -> Result<()> {
>          rcu_read_lock();
>          let r = self.memory().deref().store(val, addr, Ordering::Relaxed);
> @@ -1122,7 +1138,8 @@ pub fn store<T: AtomicAccess>(&self, addr: GuestAddress, val: T) -> Result<()> {
>      /// This function is similar to `address_space_ld{size}` in C side.
>      ///
>      /// But it only support target-endian by default.  The returned value is
> -    /// with target-endian.
> +    /// with target-endian.  The taget-endian can be checked with
> +    /// [`target_is_big_endian`].
>      ///
>      /// And it assumes the memory attributes is MEMTXATTRS_UNSPECIFIED.
>      pub fn load<T: AtomicAccess>(&self, addr: GuestAddress) -> Result<T> {
> @@ -1147,3 +1164,8 @@ pub fn load<T: AtomicAccess>(&self, addr: GuestAddress) -> Result<T> {
>      // the whole QEMU life.
>      &*wrapper_ptr
>  };
> +
> +pub fn target_is_big_endian() -> bool {
> +    // SAFETY: the return value is boolean, so it is always valid.
> +    unsafe { target_big_endian() }
> +}
> diff --git a/rust/qemu-api/wrapper.h b/rust/qemu-api/wrapper.h
> index ce0ac8d3f550..c466b93054aa 100644
> --- a/rust/qemu-api/wrapper.h
> +++ b/rust/qemu-api/wrapper.h
> @@ -70,3 +70,4 @@ typedef enum memory_order {
>  #include "system/address-spaces.h"
>  #include "hw/char/pl011.h"
>  #include "qemu/rcu.h"
> +#include "qemu/target-info.h"
> --
> 2.34.1
>
Re: [RFC 25/26] rust/memory: Add binding to check target endian
Posted by Zhao Liu 4 months ago
On Thu, Aug 07, 2025 at 03:44:57PM +0300, Manos Pitsidianakis wrote:
> Date: Thu, 7 Aug 2025 15:44:57 +0300
> From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
> Subject: Re: [RFC 25/26] rust/memory: Add binding to check target endian
> 
> On Thu, Aug 7, 2025 at 3:10 PM Zhao Liu <zhao1.liu@intel.com> wrote:
> >
> > Add a binding (target_is_big_endian()) to check whether target is big
> > endian or not. This could help user to adjust endian before calling
> 
> s/adjust endian/adjust endianness/
> 
> > AddresssSpace::store() or after calling AddressSpace::load().
> 
> No strong preference, but maybe we can keep the same name as C,
> target_big_endian()? Just for consistency.
> 
> Either way:
> 
> Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

Thanks! If the next version still supports target-endian, I'll keep
the same name.

Regards,
Zhao