[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v7 3/5] lib/arm: Add I/O memory copy helpers



On Wed, 14 Jan 2026, Oleksii Moisieiev wrote:
> This commit introduces two helper functions, `memcpy_fromio` and
> `memcpy_toio`, to provide a robust mechanism for copying data between
> standard memory and memory-mapped I/O (MMIO) space for the ARM
> architecture.
> 
> These helpers handle alignment safely by using byte accesses for any
> leading/trailing unaligned bytes and 32-bit raw accesses for the aligned
> bulk transfer. Using `__raw_readb/__raw_readl` and
> `__raw_writeb/__raw_writel` avoids unintended endianness conversion while
> remaining safe across ARM32/ARM64 devices that only support 32-bit
> accesses.
> 
> The interface lives in the generic header so other architectures can
> provide their own implementations (as macros or functions). The ARM
> implementation is split into separate compilation units and added to the
> architecture-specific lib Makefile.
> 
> Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@xxxxxxxx>

>From an ARM point of view:

Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>


Thanks Jan for the good feedback on the previous version which has now
been addressed


> ---
> 
> Changes in v7:
> - x86 guidance: removed the speculative note; header now just says
>   each arch supplies its own implementation or macro.
> - name spacing: dropped the double-underscore; the helpers are now
>   memcpy_fromio / memcpy_toio. The header also explicitly allows an
>   arch to define these as macros before including it.
> - updated io.c to keep 32-bit transfers safe on arm32
> - moved to __raw_read*/__raw_write* accessors to avoid endianness conversion.
> - split the helpers into separate compilation units
> 
> Changes in v6:
> - sorted objs in Makefile alhabetically
> - added newline at the end of Makefile
> - used uint{N}_t intead of u{N}
> - add comment about why 32 bit IO operations were used
> - updated cast opertaions to avoid dropping constness which is wrong
> - move function definitions to generic place so the could be reused by
> other arch
> - add SPDX tag to io.c
> 
> Changes in v5:
> - move memcpy_toio/fromio to the generic place
> 
>  xen/include/xen/lib/io.h    | 65 +++++++++++++++++++++++++++++++++++++
>  xen/lib/Makefile            |  1 +
>  xen/lib/arm/Makefile        |  1 +
>  xen/lib/arm/memcpy_fromio.c | 48 +++++++++++++++++++++++++++
>  xen/lib/arm/memcpy_toio.c   | 48 +++++++++++++++++++++++++++
>  5 files changed, 163 insertions(+)
>  create mode 100644 xen/include/xen/lib/io.h
>  create mode 100644 xen/lib/arm/Makefile
>  create mode 100644 xen/lib/arm/memcpy_fromio.c
>  create mode 100644 xen/lib/arm/memcpy_toio.c
> 
> diff --git a/xen/include/xen/lib/io.h b/xen/include/xen/lib/io.h
> new file mode 100644
> index 0000000000..cd2b6680d5
> --- /dev/null
> +++ b/xen/include/xen/lib/io.h
> @@ -0,0 +1,65 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Generic I/O memory copy function prototypes.
> + *
> + * These functions provide low-level implementation for copying data between
> + * regular memory and I/O memory regions. Each architecture must provide its
> + * own implementation based on the specific requirements of the 
> architecture's
> + * memory model and I/O access patterns. An architecture may supply these as
> + * functions or as macros in its own headers before including this file.
> + *
> + * Architecture-specific implementations:
> + * =====================================
> + * Each architecture should implement these functions in xen/lib/<arch>/io.c
> + * (or define them as macros) based on their hardware requirements. See
> + * xen/lib/arm/io.c for an example using explicit I/O accessors.
> + */
> +
> +#ifndef _XEN_LIB_IO_H
> +#define _XEN_LIB_IO_H
> +
> +#include <xen/types.h>
> +
> +/*
> + * memcpy_fromio - Copy data from I/O memory space to regular memory
> + * @to: Destination buffer in regular memory
> + * @from: Source address in I/O memory space (must be marked __iomem)
> + * @count: Number of bytes to copy
> + *
> + * This function handles copying from memory-mapped I/O regions using
> + * architecture-appropriate I/O accessor functions. It ensures proper:
> + * - Memory ordering and barriers
> + * - Alignment requirements
> + * - Hardware-specific access semantics
> + *
> + * Each architecture provides its own implementation that may:
> + * - Use special I/O accessor functions (ARM: readl_relaxed, readb_relaxed)
> + * - Implement alignment handling for devices requiring specific access sizes
> + * - Add memory barriers to ensure ordering with other I/O operations
> + * - Or simply map to memcpy() if the architecture allows direct I/O access
> + */
> +extern void memcpy_fromio(void *to, const volatile void __iomem *from,
> +                          size_t count);
> +
> +/*
> + * memcpy_toio - Copy data from regular memory to I/O memory space
> + * @to: Destination address in I/O memory space (must be marked __iomem)
> + * @from: Source buffer in regular memory
> + * @count: Number of bytes to copy
> + *
> + * This function handles copying to memory-mapped I/O regions using
> + * architecture-appropriate I/O accessor functions. It ensures proper:
> + * - Memory ordering and barriers
> + * - Alignment requirements
> + * - Hardware-specific access semantics
> + *
> + * Each architecture provides its own implementation that may:
> + * - Use special I/O accessor functions (ARM: writel_relaxed, writeb_relaxed)
> + * - Implement alignment handling for devices requiring specific access sizes
> + * - Add memory barriers to ensure ordering with other I/O operations
> + * - Or simply map to memcpy() if the architecture allows direct I/O access
> + */
> +extern void memcpy_toio(volatile void __iomem *to, const void *from,
> +                        size_t count);
> +
> +#endif /* _XEN_LIB_IO_H */
> diff --git a/xen/lib/Makefile b/xen/lib/Makefile
> index 5ccb1e5241..6bb0491d89 100644
> --- a/xen/lib/Makefile
> +++ b/xen/lib/Makefile
> @@ -1,3 +1,4 @@
> +obj-$(CONFIG_ARM) += arm/
>  obj-$(CONFIG_X86) += x86/
>  
>  lib-y += bsearch.o
> diff --git a/xen/lib/arm/Makefile b/xen/lib/arm/Makefile
> new file mode 100644
> index 0000000000..0bb1a825ce
> --- /dev/null
> +++ b/xen/lib/arm/Makefile
> @@ -0,0 +1 @@
> +obj-y += memcpy_fromio.o memcpy_toio.o
> diff --git a/xen/lib/arm/memcpy_fromio.c b/xen/lib/arm/memcpy_fromio.c
> new file mode 100644
> index 0000000000..342a28cb49
> --- /dev/null
> +++ b/xen/lib/arm/memcpy_fromio.c
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#include <asm/io.h>
> +#include <xen/lib/io.h>
> +
> +/*
> + * Use 32-bit raw IO operations for portability across ARM32/ARM64 where
> + * 64-bit accessors may not be atomic and some devices only support 32-bit
> + * aligned accesses.
> + */
> +
> +void memcpy_fromio(void *to, const volatile void __iomem *from,
> +                size_t count)
> +{
> +     while ( count && (!IS_ALIGNED((unsigned long)from, 4) ||
> +                       !IS_ALIGNED((unsigned long)to, 4)) )
> +     {
> +             *(uint8_t *)to = __raw_readb(from);
> +             from++;
> +             to++;
> +             count--;
> +     }
> +
> +     while ( count >= 4 )
> +     {
> +             *(uint32_t *)to = __raw_readl(from);
> +             from += 4;
> +             to += 4;
> +             count -= 4;
> +     }
> +
> +     while ( count )
> +     {
> +             *(uint8_t *)to = __raw_readb(from);
> +             from++;
> +             to++;
> +             count--;
> +     }
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 8
> + * tab-width: 8
> + * indent-tabs-mode: t
> + * End:
> + */
> diff --git a/xen/lib/arm/memcpy_toio.c b/xen/lib/arm/memcpy_toio.c
> new file mode 100644
> index 0000000000..e543c49124
> --- /dev/null
> +++ b/xen/lib/arm/memcpy_toio.c
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#include <asm/io.h>
> +#include <xen/lib/io.h>
> +
> +/*
> + * Use 32-bit raw IO operations for portability across ARM32/ARM64 where
> + * 64-bit accessors may not be atomic and some devices only support 32-bit
> + * aligned accesses.
> + */
> +
> +void memcpy_toio(volatile void __iomem *to, const void *from,
> +            size_t count)
> +{
> +     while ( count && (!IS_ALIGNED((unsigned long)to, 4) ||
> +                       !IS_ALIGNED((unsigned long)from, 4)) )
> +     {
> +             __raw_writeb(*(const uint8_t *)from, to);
> +             from++;
> +             to++;
> +             count--;
> +     }
> +
> +     while ( count >= 4 )
> +     {
> +             __raw_writel(*(const uint32_t *)from, to);
> +             from += 4;
> +             to += 4;
> +             count -= 4;
> +     }
> +
> +     while ( count )
> +     {
> +             __raw_writeb(*(const uint8_t *)from, to);
> +             from++;
> +             to++;
> +             count--;
> +     }
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 8
> + * tab-width: 8
> + * indent-tabs-mode: t
> + * End:
> + */
> -- 
> 2.34.1
> 



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.