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 <[email protected]>
>From an ARM point of view: Reviewed-by: Stefano Stabellini <[email protected]> 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 >
