Re: [PATCH v4 2/3] system/memory: Use qemu_ram_move() for directly accessible regions

Gavin Shan <[email protected]> Tue, 28 Jul 2026 20:23:48 +1000
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <[email protected]>
On 7/28/26 7:35 PM, Peter Maydell wrote:
> On Tue, 28 Jul 2026 at 10:22, Philippe Mathieu-Daudé
> <[email protected]> wrote:
>>
>> On 28/7/26 11:01, Peter Maydell wrote:
>>> On Tue, 28 Jul 2026 at 04:01, Gavin Shan <[email protected]> wrote:
>>>>
>>>> On 7/27/26 10:51 PM, Peter Maydell wrote:
> 
> 
>>>>>> +    test = (uintptr_t)src | (uintptr_t)dst | n;
>>>>>> +    len = test & -test;
>>>>>
>>>>> What is this doing? I am not a fan of clever bit twiddling
>>>>> that isn't commented to explain itself. Readers of the code
>>>>> shouldn't have to go off and search for an explanation of what
>>>>> is going on.
>>>>>
>>>>
>>>> The following comments will be added for (v5).
>>>>
>>>>        /*
>>>>         * Maximal length of aligned access that are determined by @src,
>>>>         * @dst and @n
>>>>         */
>>>
>>> What I mean is more that it ought to say why "x & -x"
>>> achieves that goal.
>>
>> Hmm isn't "x & -x" restricted to power of 2? Here we have no garanty
>> @test is, because we have no garanty @n is. Ah, this is catched by
>> the 'len != n' check and returns after calling memmove(). Indeed not
>> very clear notation. Again:
>>
>>     ...
>>
>>     /* Overlapping buffers, unaligned or oversized access */
>>     if (!QEMU_IS_ALIGNED((uintptr_t)src | (uintptr_t)dst, n)) {
>>         memmove(dst, src, n);
>>         return;
>>     }
>>
>>     switch (n) {
>>     ...
> 
> I'm not inherently against the bit twiddling (QEMU_IS_ALIGNED
> on a variable length will do a division, maybe we care?);
> I just want that if we do use a bit-twiddling trick that we
> explain why it does the thing we want it to do.
> 

Ok, PeterM and Philippe, Could you please help to check if below code looks
good to you? Thanks a lot :-)

void qemu_ram_move(void *dst, const void *src, size_t n)
{
     if (n == 0) {
         return;
     }

     /* Overlapping areas, unaligned or oversized access */
     if (!is_power_of_2(n) || n > 8 ||
         !QEMU_IS_ALIGNED((uintptr_t)src | (uintptr_t)dst, n)) {
         memmove(dst, src, n);
         return;
     }

      switch (n) {
      case 1:
          qatomic_set((uint8_t *)dst, qatomic_read((uint8_t *)src));
          break;
      case 2:
          qatomic_set((uint16_t *)dst, qatomic_read((uint16_t *)src));
          break;
      case 4:
          qatomic_set((uint32_t *)dst, qatomic_read((uint32_t *)src));
          break;
      case 8:
          qatomic_set((uint64_t *)dst, qatomic_read((uint64_t *)src));
          break;
      default:
          g_assert_not_reached();
      }
}

QEMU_IS_ALIGNED() doesn't require the arguments are power-of-two values.

#define QEMU_IS_ALIGNED(n, m) (((n) % (m)) == 0)   /* QEMU_IS_ALIGNED(3, 3) => true */

I also need to drop "and the memory areas do not overlap" in (v6) from the
comments for include/system/memory.h::qemu_ram_move() as the check 'src == dst'
check has been dropped. Sorry that I sent (v5) too quick because our downstream
need a stabilized version to integrate.

Thanks,
Gavin