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

[PATCH v13 3/6] lib/arm: Add I/O memory copy helpers


  • To: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Oleksii Moisieiev <Oleksii_Moisieiev@xxxxxxxx>
  • Date: Tue, 22 Sep 2026 14:40:25 +0000
  • Accept-language: en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=epam.com; dmarc=pass action=none header.from=epam.com; dkim=pass header.d=epam.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=XV5f3tUGW+mzcug+M+p3lP5Jfj6Y79rIFmhgwSn1QeI=; b=mv5GQPFp/AoFRT4KSbZcwUz3Pe4LxHPQvRHiYjzlkvScNEs9AX3japXGsxG0geIGYYauEFdGq+lhC6wpg8q8IBpGMrgetKoNeynku1UGieq674tCCKKE3Rmj8c/IGneW7C2JmmeHx1+HrUzXHnbcGEMn3Cg8nzGRYTGvS+ImuE44GkLaoboxYZxFEJN6+8wE48utI224QzuNq7QWGcuTgOX5mt9Y96+1XE3fB4wHy6uFPgs2RKcj0iFla6dnWTz3k6dwvmmeJ63IpP+4a/AzVEv1OXslKIWPJLj12xYkggcVHSykwLRNmtVcewVV3Pz2yeShuLSsXKX9hFQ5qY5vxA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Bb5HSoGBKYf41+2fpiu2AOe+eAgoee3Tkdu3NpF10DSloMVtg497v1M4vkijxGVrfTuZto7/+f5oQHzp3ajPdoLF7SVPiGm5x26/xZFW+WEqsep2EifMBU24HmnHpuA7P95k75QfhK2LK+ebWjlW4EmPo4UtG+dM5toQEur76VU2hd2WfE+neGW0gs985mcsR+Wgub1VxNlZuiyQqgNM2GTNQCzrdVidOe9Fg2fwzRr7Oo4tPPKodZapB6hAftiJlCLKzNa1oPwGKuxTnZEGHxZk5q1OHTLg4oeZYAOynAtI/krkHMksorqp6BvSghC73AMKf5ykxW86R1Sg1U7jag==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=epam.com header.i="@epam.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:x-ms-exchange-senderadcheck"
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=epam.com;
  • Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Juergen Gross <jgross@xxxxxxxx>, Julien Grall <julien@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Oleksii Moisieiev <Oleksii_Moisieiev@xxxxxxxx>, Roger Pau Monné <roger.pau@xxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Grygorii Strashko <grygorii_strashko@xxxxxxxx>
  • Delivery-date: Tue, 22 Sep 2026 14:40:31 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHdSqBNWHTiy8oSrE+yfsv9Eam6pw==
  • Thread-topic: [PATCH v13 3/6] lib/arm: Add I/O memory copy helpers

Introduce memcpy_fromio() and memcpy_toio() helpers to copy between
regular memory and a memory-like I/O region on Arm. The generic
prototypes live in io.h so other architectures can provide their own
implementations.

The helpers copy a byte sequence: byte accesses are used until the I/O
pointer is 32-bit aligned and for the trailing count % 4 bytes, the
aligned bulk uses 32-bit accesses. Only the I/O pointer is aligned, the
regular memory side is accessed through get_unaligned_le32() /
put_unaligned_le32(), so the access widths issued on the I/O side do not
depend on the alignment of the memory buffer. These _le32 helpers pair
with readl()/writel(), which are little endian accessors, hence the byte
sequence is preserved on either CPU endianness.

The constraints on the I/O region are documented next to the
declarations in xen/io.h, the arch-specific access pattern next to the
implementation.

Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@xxxxxxxx>
Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>
---

Changes in v13:
- memcpy_{from,to}io(): align only the I/O pointer and access the
  regular memory side through get_unaligned_le32()/put_unaligned_le32().
- document the contract of the helpers in xen/io.h
- reword the Arm implementation notes to state the concrete access
  pattern
- drop the incorrect claim about avoiding endianness conversion from the
  commit message; note instead that the _le32 helpers pair with
  readl()/writel() so the byte sequence is preserved on either endianness

Changes in v12:
- Add missed R-B
- correct the Emacs footer of both files, which asked for 8 column
tab indentation while the code is in 4 column Xen style

Changes in v10:
- removed extra include in memcpy-{to/from}io.c files

Changes in v9:
- reword commit description to refer to memcpy_fromio and memcpy_toio
- ordering obj-y in Makefile
- rename ALL_LIBS to ARCH_LIBS
- drop io.h and move definitions to the common header, fix comments to
be arch neutral
- update comments for memcpy_{from/to}io implementation

Changes in v8:
- switched to ordered accessors to address the ordering and barrier
concerns.
- updated the documentation to match the implementation and explicitly
state the supported access sizes and granularity.
- rename memcpy_* implementation files to memcpu-* to follow naming
convension
- fix indentation to match Xen style
- fix intendation to match Xen style
- move memcpy-{from/to}io to more convenient library place

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/arch/arm/Makefile            |  1 +
 xen/arch/arm/arch.mk             |  1 +
 xen/arch/arm/lib/Makefile        |  2 ++
 xen/arch/arm/lib/memcpy-fromio.c | 56 ++++++++++++++++++++++++++++++++
 xen/arch/arm/lib/memcpy-toio.c   | 56 ++++++++++++++++++++++++++++++++
 xen/include/xen/io.h             | 25 ++++++++++++++
 6 files changed, 141 insertions(+)
 create mode 100644 xen/arch/arm/lib/Makefile
 create mode 100644 xen/arch/arm/lib/memcpy-fromio.c
 create mode 100644 xen/arch/arm/lib/memcpy-toio.c

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index b7afd3e58c..e448e69014 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -8,6 +8,7 @@ ifneq ($(CONFIG_NO_PLAT),y)
 obj-y += platforms/
 endif
 obj-y += firmware/
+obj-y += lib/
 obj-$(CONFIG_TEE) += tee/
 obj-$(CONFIG_HAS_VPCI) += vpci.o
 
diff --git a/xen/arch/arm/arch.mk b/xen/arch/arm/arch.mk
index dea8dbd18a..009bb22c45 100644
--- a/xen/arch/arm/arch.mk
+++ b/xen/arch/arm/arch.mk
@@ -2,6 +2,7 @@
 # arm-specific definitions
 
 ARCH_LIBS-y += arch/arm/$(ARCH)/lib/lib.a
+ARCH_LIBS-y += arch/arm/lib/lib.a
 
 $(call cc-options-add,CFLAGS,CC,$(EMBEDDED_EXTRA_CFLAGS))
 $(call cc-option-add,CFLAGS,CC,-Wnested-externs)
diff --git a/xen/arch/arm/lib/Makefile b/xen/arch/arm/lib/Makefile
new file mode 100644
index 0000000000..07a0d9186c
--- /dev/null
+++ b/xen/arch/arm/lib/Makefile
@@ -0,0 +1,2 @@
+lib-y += memcpy-fromio.o
+lib-y += memcpy-toio.o
diff --git a/xen/arch/arm/lib/memcpy-fromio.c b/xen/arch/arm/lib/memcpy-fromio.c
new file mode 100644
index 0000000000..98339a5cfa
--- /dev/null
+++ b/xen/arch/arm/lib/memcpy-fromio.c
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/io.h>
+#include <xen/unaligned.h>
+
+/*
+ * Arm implementation notes:
+ * - Byte accesses are issued until the I/O pointer is 32-bit aligned and
+ *   for the trailing count % 4 bytes; the aligned bulk uses 32-bit
+ *   accesses. No wider accesses are issued.
+ * - The access widths on the I/O side depend only on the alignment of the
+ *   I/O pointer and on count. The regular memory side is accessed through
+ *   put_unaligned_le32(), so its alignment has no influence on them.
+ * - put_unaligned_le32() pairs with readl(), which is a little endian
+ *   accessor, so the byte sequence is preserved on either CPU endianness.
+ * - The I/O region must be mapped with device attributes; ordering is
+ *   provided by the accessors themselves, no extra barriers are added.
+ */
+
+void memcpy_fromio(void *to, const volatile void __iomem *from,
+                   size_t count)
+{
+    while ( count && !IS_ALIGNED((unsigned long)from, 4) )
+    {
+        *(uint8_t *)to = readb(from);
+        from++;
+        to++;
+        count--;
+    }
+
+    while ( count >= 4 )
+    {
+        put_unaligned_le32(readl(from), to);
+        from += 4;
+        to += 4;
+        count -= 4;
+    }
+
+    while ( count )
+    {
+        *(uint8_t *)to = readb(from);
+        from++;
+        to++;
+        count--;
+    }
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/lib/memcpy-toio.c b/xen/arch/arm/lib/memcpy-toio.c
new file mode 100644
index 0000000000..c0be79586d
--- /dev/null
+++ b/xen/arch/arm/lib/memcpy-toio.c
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/io.h>
+#include <xen/unaligned.h>
+
+/*
+ * Arm implementation notes:
+ * - Byte accesses are issued until the I/O pointer is 32-bit aligned and
+ *   for the trailing count % 4 bytes; the aligned bulk uses 32-bit
+ *   accesses. No wider accesses are issued.
+ * - The access widths on the I/O side depend only on the alignment of the
+ *   I/O pointer and on count. The regular memory side is accessed through
+ *   get_unaligned_le32(), so its alignment has no influence on them.
+ * - get_unaligned_le32() pairs with writel(), which is a little endian
+ *   accessor, so the byte sequence is preserved on either CPU endianness.
+ * - The I/O region must be mapped with device attributes; ordering is
+ *   provided by the accessors themselves, no extra barriers are added.
+ */
+
+void memcpy_toio(volatile void __iomem *to, const void *from,
+                 size_t count)
+{
+    while ( count && !IS_ALIGNED((unsigned long)to, 4) )
+    {
+        writeb(*(const uint8_t *)from, to);
+        from++;
+        to++;
+        count--;
+    }
+
+    while ( count >= 4 )
+    {
+        writel(get_unaligned_le32(from), to);
+        from += 4;
+        to += 4;
+        count -= 4;
+    }
+
+    while ( count )
+    {
+        writeb(*(const uint8_t *)from, to);
+        from++;
+        to++;
+        count--;
+    }
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/xen/io.h b/xen/include/xen/io.h
index 164a20c5d7..0b60be27c1 100644
--- a/xen/include/xen/io.h
+++ b/xen/include/xen/io.h
@@ -67,4 +67,29 @@ static inline bool write_mmio(volatile void __iomem *mem, 
unsigned long data,
     return true;
 }
 
+/*
+ * Copy a sequence of bytes between regular memory and a memory-like I/O
+ * region, e.g. shared memory placed in RAM or SRAM mapped with device
+ * attributes.
+ *
+ * The I/O region must behave like byte-addressable storage: it has to
+ * accept 8-bit accesses at any byte address and naturally aligned 32-bit
+ * accesses, with plain byte-storage semantics in both cases (no side
+ * effects, no dependency on the access width). An implementation may use
+ * any of these widths, but never wider ones. The helpers are therefore
+ * not suitable for device registers with access-width requirements.
+ *
+ * Neither pointer needs to be aligned. The access widths issued on the
+ * I/O side depend only on the alignment of the I/O pointer and on count,
+ * never on the alignment of the regular memory pointer.
+ *
+ * Implementations are architecture-specific and may impose further
+ * constraints; see the respective arch/<arch>/lib/memcpy-{from,to}io.c
+ * for the exact access pattern.
+ */
+void memcpy_fromio(void *to, const volatile void __iomem *from,
+                   size_t count);
+void memcpy_toio(volatile void __iomem *to, const void *from,
+                 size_t count);
+
 #endif /* XEN_IO_H */
-- 
2.43.0



 


Rackspace

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