From nobody Sun Jul 26 13:29:02 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1781587608; cv=none; d=zohomail.com; s=zohoarc; b=BWEpMYf7p+t/EspQs2mDHmFA84D1cmDeoSz3bvseNbl/y8zNSrcDP3E3adv6Fo6SCoRkpw5Mhh86mQ6DBMe0Xj9NG3EZl4RhpUKZjcZvqnIDKcEcWn/2vHx7fN5Yji0mndcUaBrhEmJtdMI0VT8efncYCQIPePTVRqyAfWb6VJ8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1781587608; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=NStWUbsE6Tm5fos2QuYOYWDBvvnYvZHjRArlTMvyoTk=; b=Mkdn5wlZlJjQlCA35tWZWzh33NP9wScfbsOTlMQDmLiodbsLxQND7lvC4xScYkiE+xspMFeeEVJbMz+Dm/z5qg6pJdirhtt6UHVZNIR5ozqj91rlnZv5iBtJUY8HdwxaCYBM/mrUOhvOvQgqTIE6zKlH/8iRVgYhJ/kCWzAumiY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1781587608283199.72023438985298; Mon, 15 Jun 2026 22:26:48 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wZMJk-0006y5-1f; Tue, 16 Jun 2026 01:26:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wZMJi-0006xh-K3 for qemu-devel@nongnu.org; Tue, 16 Jun 2026 01:26:30 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wZMJg-0002QL-7a for qemu-devel@nongnu.org; Tue, 16 Jun 2026 01:26:30 -0400 Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-562-9R7wwIRkMMSTDOxvvwuQUg-1; Tue, 16 Jun 2026 01:26:23 -0400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 106BC195607A; Tue, 16 Jun 2026 05:26:21 +0000 (UTC) Received: from gshan-thinkpadx1nanogen2.rmtau.csb (unknown [10.64.136.2]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 91F191800586; Tue, 16 Jun 2026 05:26:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1781587587; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NStWUbsE6Tm5fos2QuYOYWDBvvnYvZHjRArlTMvyoTk=; b=fI05ul1SOq53vk3fitE8nnBMQ4GVAWvKbfH0cbYLfcTiQ68el6++WkyqYyfYTtLO/dLGGz xSwjoU9zlXD+5bHu/NGyEZvqbsklKAu+axAKT8fam5mADFh6SAT2l+0Cku4WcFa5CSNjcF z6KcrsuMZzqEruuEbX8taZEX8RM0fQ8= X-MC-Unique: 9R7wwIRkMMSTDOxvvwuQUg-1 X-Mimecast-MFC-AGG-ID: 9R7wwIRkMMSTDOxvvwuQUg_1781587581 From: Gavin Shan To: qemu-arm@nongnu.org Cc: qemu-devel@nongnu.org, mst@redhat.com, peterx@redhat.com, alex@shazbot.org, richard.henderson@linaro.org, peter.maydell@linaro.org, berrange@redhat.com, philmd@oss.qualcomm.com, philmd@mailo.com, david@kernel.org, clg@redhat.com, pbonzini@redhat.com, phrdina@redhat.com, jugraham@redhat.com, liugang24219@sangfor.com.cn, dinghui@sangfor.com.cn, shan.gavin@gmail.com Subject: [PATCH v3 1/2] system/memory: Use qemu_ram_{copy, move}() in ram device region accessors Date: Tue, 16 Jun 2026 15:25:51 +1000 Message-ID: <20260616052552.389021-2-gshan@redhat.com> In-Reply-To: <20260616052552.389021-1-gshan@redhat.com> References: <20260616052552.389021-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=gshan@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: 8 X-Spam_score: 0.8 X-Spam_bar: / X-Spam_report: (0.8 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1781587609952158500 Content-Type: text/plain; charset="utf-8" All ram device regions were turned to be indirectly accessible by commit 4a2e242bbb ("memory: Don't use memcpy for ram_device regions"). This leads to guest hang on attempt to build 'cuda-samples' as reported by Julia. The guest is started by the following command lines, with GH100 GPU card passed from the host. host$ lspci | grep GH100 0009:01:00.0 3D controller: NVIDIA Corporation GH100 [GH200 120GB / 480G= B] (rev a1) host$ /home/sandbox/gavin/qemu.main/build/qemu-system-aarch64 = \ -machine virt,gic-version=3Dhost,ras=3Don,highmem-mmio-size=3D4T = \ -accel kvm -cpu host -smp cpus=3D48 -m size=3D8G = \ -drive file=3D/home/gavin/sandbox/images/disk.qcow2,if=3Dnone,id= =3Dd0 \ -device virtio-blk-pci,id=3Dvb0,bus=3Dpcie.0,drive=3Dd0,num-queues= =3D4 \ -device vfio-pci-nohotplug,host=3D0009:01:00.0,bus=3Dpcie.1.0 : guest$ cd cuda-samples/build guest$ make -j 20 clean guest$ make -j 20 : [ 54%] Linking CUDA executable graphMemoryNodes [ 54%] Built target graphMemoryNodes guest$ qemu-system-aarch64: virtio: bogus descriptor or out of resources [ 555.814025] virtio_blk virtio0: [vda] new size: 268435456 512-byte lo= gical blocks (137 GB/128 GiB) When the GPU's driver (NVidia open driver) is loaded on guest bootup, the memory blocks residing in the PCI BAR#4 of the GH100 GPU card can be presented to the guest through memory hot-add. The page cache can then be allocated from the hot added memory blocks when cuda-samples is being built. Afterwards, the page cache is sent to QEMU's virtio-blk device as part of the DMA request, the bounce buffer has to be used to accomodate the request as the corresponding memory region (MemoryRegion) is an indirectly accessible ram device region in qemu. However, the max bounce bufer size is only 4096 bytes by default and that is exhausted quickly, leading to a reset on the virtio-blk device and frozen guest eventually. QEMU =3D=3D=3D=3D virtio_blk_handle_output virtio_blk_handle_vq virtio_blk_get_request virtqueue_pop virtqueue_split_pop virtqueue_map_desc address_space_map memory_access_is_direct # Return false memory_region_supports_direct_access (qemu) info mtree memory-region: pci_bridge_pci 0000000000000000-ffffffffffffffff (prio 0, container): pci_bridge_pci 0000042000000000-0000043fffffffff (prio 1, i/o): 0009:01:00.0 base BA= R 4 0000042000000000-0000043fffffffff (prio 0, i/o): 0009:01:00.0 BAR 4 0000042000000000-000004379fffffff (prio 0, ramd): 0009:01:00.0 BA= R 4 mmaps[0] This adds qemu_ram_{copy, move}() and replaces {memcpy, memmove}() with them in the ram device memory region accessors, similar to what's done in commit 4a2e242bbb so that the issue (MMIO access instructions were optimized to SSE instructions) covered by that commit is fixed. This makes 'ram_device_mem_ops' redundant, paving the way to revert that commit to make ram device region directly accessible again in the next patch. Reported-by: Julia Graham Suggested-by: Michael S. Tsirkin Suggested-by: Peter Xu Suggested-by: Richard Henderson Suggested-by: Peter Maydell Signed-off-by: Gavin Shan --- v3: Documentation for qemu_ram_{copy, move} (Peter/Michael) Support qemu_ram_move() for overlapped src/dest (Richard) Use {memcpy, memmove} if step is 16-bytes or more (Michael) Code improvements (Richard/Michael) --- hw/remote/vfio-user-obj.c | 4 +- include/system/memory.h | 32 ++++++- system/physmem.c | 178 +++++++++++++++++++++++++++++++++++++- 3 files changed, 207 insertions(+), 7 deletions(-) diff --git a/hw/remote/vfio-user-obj.c b/hw/remote/vfio-user-obj.c index 87fa7b6572..97a6c88780 100644 --- a/hw/remote/vfio-user-obj.c +++ b/hw/remote/vfio-user-obj.c @@ -375,9 +375,9 @@ static int vfu_object_mr_rw(MemoryRegion *mr, uint8_t *= buf, hwaddr offset, ram_ptr =3D memory_region_get_ram_ptr(mr); =20 if (is_write) { - memcpy((ram_ptr + offset), buf, size); + qemu_ram_copy(ram_ptr + offset, buf, size); } else { - memcpy(buf, (ram_ptr + offset), size); + qemu_ram_copy(buf, ram_ptr + offset, size); } =20 return 0; diff --git a/include/system/memory.h b/include/system/memory.h index 1417132f6d..84203c312d 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -2897,6 +2897,36 @@ void address_space_register_map_client(AddressSpace = *as, QEMUBH *bh); void address_space_unregister_map_client(AddressSpace *as, QEMUBH *bh); =20 /* Internal functions, part of the implementation of address_space_read. = */ + +/** + * qemu_ram_copy: copy data to ramblock + * + * @dst: destination where the data is copied to + * @src: source where the data is copied from + * @n: length of data to be copied + * + * + * Copy @n bytes from @src to @dst with the assumption that @src and @dst + * do not overlap. Handles special cases such as uncacheable ramblocks + * correctly. Use this for accessing ramblock in response to DMA/VCPU IO, + * in preference to memcpy(). + */ +void qemu_ram_copy(void *dest, const void *src, size_t n); + +/** + * qemu_ram_move: move data to ramblock + * + * @dst: destination where the data is moved to + * @src: source where the data is moved from + * @n: length of data to be moved + * + * Move @n bytes from @src to @dst with the assumption that @src and @dst + * can overlap. Handles special cases such as uncacheable ramblocks + * correctly. Use this for accessing ramblock in response to DMA/VCPU IO, + * in preference to memmove(). + */ +void qemu_ram_move(void *dest, const void *src, size_t n); + MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, void *buf, hwaddr le= n); MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr, @@ -2970,7 +3000,7 @@ MemTxResult address_space_read(AddressSpace *as, hwad= dr addr, mr =3D flatview_translate(fv, addr, &addr1, &l, false, attrs); if (len =3D=3D l && memory_access_is_direct(mr, false, attrs))= { ptr =3D qemu_map_ram_ptr(mr->ram_block, addr1); - memcpy(buf, ptr, len); + qemu_ram_copy(buf, ptr, len); } else { result =3D flatview_read_continue(fv, addr, attrs, buf, le= n, addr1, l, mr); diff --git a/system/physmem.c b/system/physmem.c index 7bcbf87573..45a17cd580 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -3160,6 +3160,177 @@ void memory_region_flush_rom_device(MemoryRegion *m= r, hwaddr addr, hwaddr size) invalidate_and_set_dirty(mr, addr, size); } =20 +static void qemu_ram_copy_aligned(void *dst, const void *src, size_t n) +{ + switch (n) { + case 1: + __builtin_memcpy(dst, src, 1); + break; + case 2: + __builtin_memcpy(dst, src, 2); + break; + case 4: + __builtin_memcpy(dst, src, 4); + break; + case 8: + __builtin_memcpy(dst, src, 8); + break; + default: + memcpy(dst, src, n); + } +} + +static void qemu_ram_move_aligned(void *dst, const void *src, size_t n) +{ + switch (n) { + case 1: + __builtin_memmove(dst, src, 1); + break; + case 2: + __builtin_memmove(dst, src, 2); + break; + case 4: + __builtin_memmove(dst, src, 4); + break; + case 8: + __builtin_memmove(dst, src, 8); + break; + default: + memmove(dst, src, n); + } +} + +static void qemu_ram_copy_unaligned(void *dst, const void *src, + size_t n, size_t max_step) +{ + uintptr_t test, step; + + /* Aligned maximal step */ + max_step =3D pow2floor(max_step); + + while (n) { + test =3D (uintptr_t)src | (uintptr_t)dst | n | max_step; + step =3D test & -test; + + switch (step) { + case 1: + qatomic_set((uint8_t *)dst, qatomic_read((uint8_t *)src)); + src +=3D 1; + dst +=3D 1; + n -=3D 1; + break; + case 2: + qatomic_set((uint16_t *)dst, qatomic_read((uint16_t *)src)); + src +=3D 2; + dst +=3D 2; + n -=3D 2; + break; + case 4: + qatomic_set((uint32_t *)dst, qatomic_read((uint32_t *)src)); + src +=3D 4; + dst +=3D 4; + n -=3D 4; + break; + case 8: + qatomic_set((uint64_t *)dst, qatomic_read((uint64_t *)src)); + src +=3D 8; + dst +=3D 8; + n -=3D 8; + break; + default: + memcpy(dst, src, step); + src +=3D step; + dst +=3D step; + n -=3D step; + } + } +} + +static void qemu_ram_backwards_copy_unaligned(void *dst, const void *src, + size_t n, size_t max_step) +{ + uintptr_t test, step; + + /* Aligned maximal step */ + max_step =3D pow2floor(max_step); + + /* End of the blocks */ + src +=3D n; + dst +=3D n; + + while (n) { + test =3D (uintptr_t)src | (uintptr_t)dst | n | max_step; + step =3D test & -test; + + switch (step) { + case 1: + src -=3D 1; + dst -=3D 1; + n -=3D 1; + qatomic_set((uint8_t *)dst, qatomic_read((uint8_t *)src)); + break; + case 2: + src -=3D 2; + dst -=3D 2; + n -=3D 2; + qatomic_set((uint16_t *)dst, qatomic_read((uint16_t *)src)); + break; + case 4: + src -=3D 4; + dst -=3D 4; + n -=3D 4; + qatomic_set((uint32_t *)dst, qatomic_read((uint32_t *)src)); + break; + case 8: + src -=3D 8; + dst -=3D 8; + n -=3D 8; + qatomic_set((uint64_t *)dst, qatomic_read((uint64_t *)src)); + break; + default: + src -=3D step; + dst -=3D step; + n -=3D step; + memmove(dst, src, step); + } + } +} + +/* x86 should work with __builtin_{memcpy, memmove}() for IO access */ +#if defined(__i386__) || defined(__x86_64__) +#define HOST_UNALIGNED_MMIO_OK 1 +#else +#define HOST_UNALIGNED_MMIO_OK 0 +#endif + +void qemu_ram_copy(void *dst, const void *src, size_t n) +{ + if (dst =3D=3D src || n =3D=3D 0) { + return; + } + + if (HOST_UNALIGNED_MMIO_OK) { + qemu_ram_copy_aligned(dst, src, n); + } else { + qemu_ram_copy_unaligned(dst, src, n, 8); + } +} + +void qemu_ram_move(void *dst, const void *src, size_t n) +{ + if (src =3D=3D dst || n =3D=3D 0) { + return; + } + + if (HOST_UNALIGNED_MMIO_OK) { + qemu_ram_move_aligned(dst, src, n); + } else if (dst < src) { + qemu_ram_copy_unaligned(dst, src, n, src - dst); + } else { + qemu_ram_backwards_copy_unaligned(dst, src, n, dst - src); + } +} + int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr) { unsigned access_size_max =3D mr->ops->valid.max_access_size; @@ -3272,7 +3443,7 @@ static MemTxResult flatview_write_continue_step(MemTx= Attrs attrs, uint8_t *ram_ptr =3D qemu_ram_ptr_length(mr->ram_block, mr_addr, l, false, true); =20 - memmove(ram_ptr, buf, *l); + qemu_ram_move(ram_ptr, buf, *l); invalidate_and_set_dirty(mr, mr_addr, *l); =20 return MEMTX_OK; @@ -3365,7 +3536,7 @@ static MemTxResult flatview_read_continue_step(MemTxA= ttrs attrs, uint8_t *buf, uint8_t *ram_ptr =3D qemu_ram_ptr_length(mr->ram_block, mr_addr, l, false, false); =20 - memcpy(buf, ram_ptr, *l); + qemu_ram_copy(buf, ram_ptr, *l); =20 return MEMTX_OK; } @@ -3503,8 +3674,7 @@ MemTxResult address_space_write_rom(AddressSpace *as,= hwaddr addr, l =3D memory_access_size(mr, l, addr1); } else { /* ROM/RAM case */ - void *ram_ptr =3D qemu_map_ram_ptr(mr->ram_block, addr1); - memcpy(ram_ptr, buf, l); + qemu_ram_copy(qemu_map_ram_ptr(mr->ram_block, addr1), buf, l); invalidate_and_set_dirty(mr, addr1, l); } len -=3D l; --=20 2.54.0 From nobody Sun Jul 26 13:29:02 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1781587623; cv=none; d=zohomail.com; s=zohoarc; b=gH0F/N7OXGAuf0YuauZ5kamBiqxbY5Ozgks/crPSkp72SG+/n+sDPN2kY/k42eC6P8vCjTnZ6RaByvER8F0QK01M/hhuhVgNJ8eQC/h/Lck81zETnJYPWjKDDqAuPxOPGnSv/qxKkLSI/O3h1CWKJaJrkSCUVwqFDvxtU4/encI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1781587623; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=ZBZ/pfNaeKFaN1Z2Da1JxVMciN0d9deiOJrFxM8lFhY=; b=D2yFe307VvN/1t4JyE04uzwwHOrH4ZdScY/QTQkAoMdBWQYrQbm6zQaKl8OcL9GXkUYCZ3LZ9GbaZzfa8MM08QCYQbgcAo/U/9hEz9SlChe7CHqPpjezdpoFCR/gpqUL/yjl6mCSlm4qjOw9t/1D9+6LtpJVJj/dEFUnh4xzAA4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178158762389370.55334203482994; Mon, 15 Jun 2026 22:27:03 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wZMJr-00075L-NJ; Tue, 16 Jun 2026 01:26:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wZMJp-00074M-Ug for qemu-devel@nongnu.org; Tue, 16 Jun 2026 01:26:37 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wZMJo-0002Ru-9E for qemu-devel@nongnu.org; Tue, 16 Jun 2026 01:26:37 -0400 Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-612-hRqJDn2tM4-3-va8waAWaA-1; Tue, 16 Jun 2026 01:26:32 -0400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 20DA919560AB; Tue, 16 Jun 2026 05:26:30 +0000 (UTC) Received: from gshan-thinkpadx1nanogen2.rmtau.csb (unknown [10.64.136.2]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id CC5761800367; Tue, 16 Jun 2026 05:26:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1781587595; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZBZ/pfNaeKFaN1Z2Da1JxVMciN0d9deiOJrFxM8lFhY=; b=TWBsVj/RYpQ8rd88EHNX8b1/7GbNCHI2W+U8DKa61O4mpE9nE1n0QXPHjTf/FbDVROnrTo gbjdyNdHx9nsAlu3Qd5o/T6WJS+/m9OK3WPQXbnYdY8pYr/x50VCnUP5XFeLbYmfSHtvHq v+wV50bmPClmRQkTOdTAhttLUTWYvIw= X-MC-Unique: hRqJDn2tM4-3-va8waAWaA-1 X-Mimecast-MFC-AGG-ID: hRqJDn2tM4-3-va8waAWaA_1781587590 From: Gavin Shan To: qemu-arm@nongnu.org Cc: qemu-devel@nongnu.org, mst@redhat.com, peterx@redhat.com, alex@shazbot.org, richard.henderson@linaro.org, peter.maydell@linaro.org, berrange@redhat.com, philmd@oss.qualcomm.com, philmd@mailo.com, david@kernel.org, clg@redhat.com, pbonzini@redhat.com, phrdina@redhat.com, jugraham@redhat.com, liugang24219@sangfor.com.cn, dinghui@sangfor.com.cn, shan.gavin@gmail.com Subject: [PATCH v3 2/2] system/memory: Make ram device region directly accessible Date: Tue, 16 Jun 2026 15:25:52 +1000 Message-ID: <20260616052552.389021-3-gshan@redhat.com> In-Reply-To: <20260616052552.389021-1-gshan@redhat.com> References: <20260616052552.389021-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=gshan@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: 8 X-Spam_score: 0.8 X-Spam_bar: / X-Spam_report: (0.8 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1781587625977158500 Content-Type: text/plain; charset="utf-8" This basically reverts 4a2e242bbb30 ("memory: Don't use memcpy for ram_device regions") to make ram device region directly accessible again. With this, the bounce buffer is bypassed in address_space_map() when a ram device region is involved, potentially avoid to overrun the (small) bounce buffer. Reported-by: Julia Graham Suggested-by: Michael S. Tsirkin Suggested-by: Peter Xu Suggested-by: Richard Henderson Suggested-by: Peter Maydell Signed-off-by: Gavin Shan --- include/system/memory.h | 11 ++--------- system/memory.c | 41 +---------------------------------------- system/trace-events | 2 -- 3 files changed, 3 insertions(+), 51 deletions(-) diff --git a/include/system/memory.h b/include/system/memory.h index 84203c312d..28bfb6f1c9 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -2944,15 +2944,8 @@ static inline bool memory_region_supports_direct_acc= ess(const MemoryRegion *mr) if (memory_region_is_romd(mr)) { return true; } - if (!memory_region_is_ram(mr)) { - return false; - } - /* - * RAM DEVICE regions can be accessed directly using memcpy, but it mi= ght - * be MMIO and access using mempy can be wrong (e.g., using instructio= ns not - * intended for MMIO access). So we treat this as IO. - */ - return !memory_region_is_ram_device(mr); + + return memory_region_is_ram(mr); } =20 static inline bool memory_access_is_direct(const MemoryRegion *mr, diff --git a/system/memory.c b/system/memory.c index 739ba11da6..9549dd1a94 100644 --- a/system/memory.c +++ b/system/memory.c @@ -1362,43 +1362,6 @@ const MemoryRegionOps unassigned_mem_ops =3D { .endianness =3D DEVICE_NATIVE_ENDIAN, }; =20 -static uint64_t memory_region_ram_device_read(void *opaque, - hwaddr addr, unsigned size) -{ - MemoryRegion *mr =3D opaque; - uint64_t data =3D ldn_he_p(mr->ram_block->host + addr, size); - - trace_memory_region_ram_device_read(get_cpu_index(), mr, addr, data, s= ize); - - return data; -} - -static void memory_region_ram_device_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - MemoryRegion *mr =3D opaque; - - trace_memory_region_ram_device_write(get_cpu_index(), mr, addr, data, = size); - - stn_he_p(mr->ram_block->host + addr, size, data); -} - -static const MemoryRegionOps ram_device_mem_ops =3D { - .read =3D memory_region_ram_device_read, - .write =3D memory_region_ram_device_write, - .endianness =3D HOST_BIG_ENDIAN ? DEVICE_BIG_ENDIAN : DEVICE_LITTLE_EN= DIAN, - .valid =3D { - .min_access_size =3D 1, - .max_access_size =3D 8, - .unaligned =3D true, - }, - .impl =3D { - .min_access_size =3D 1, - .max_access_size =3D 8, - .unaligned =3D true, - }, -}; - bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, unsigned size, @@ -1676,10 +1639,8 @@ void memory_region_init_ram_device_ptr(MemoryRegion = *mr, Object *owner, const char *name, uint64_t size, void *ptr) { - memory_region_init_io(mr, owner, &ram_device_mem_ops, mr, name, size); - mr->ram =3D true; + memory_region_init_ram_ptr(mr, owner, name, size, ptr); mr->ram_device =3D true; - memory_region_set_ram_ptr(mr, size, ptr); } =20 void memory_region_init_alias(MemoryRegion *mr, Object *owner, diff --git a/system/trace-events b/system/trace-events index e6e1b61279..34af0a3a1e 100644 --- a/system/trace-events +++ b/system/trace-events @@ -20,8 +20,6 @@ memory_region_ops_read(int cpu_index, void *mr, uint64_t = addr, uint64_t value, u memory_region_ops_write(int cpu_index, void *mr, uint64_t addr, uint64_t v= alue, unsigned size, const char *name) "cpu %d mr %p addr 0x%"PRIx64" value= 0x%"PRIx64" size %u name '%s'" memory_region_subpage_read(int cpu_index, void *mr, uint64_t offset, uint6= 4_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx64= " size %u" memory_region_subpage_write(int cpu_index, void *mr, uint64_t offset, uint= 64_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx6= 4" size %u" -memory_region_ram_device_read(int cpu_index, void *mr, uint64_t addr, uint= 64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64"= size %u" -memory_region_ram_device_write(int cpu_index, void *mr, uint64_t addr, uin= t64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64= " size %u" memory_region_sync_dirty(const char *mr, const char *listener, int global)= "mr '%s' listener '%s' synced (global=3D%d)" flatview_new(void *view, void *root) "%p (root %p)" flatview_destroy(void *view, void *root) "%p (root %p)" --=20 2.54.0