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

Philippe Mathieu-Daudé <[email protected]> Tue, 28 Jul 2026 11:22:01 +0200
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <[email protected]>
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:
> 
>>>> +void qemu_ram_move(void *dst, const void *src, size_t n)
>>>> +{
>>>> +    uintptr_t test, len;
>>>> +
>>>> +    if (src == dst || n == 0) {
>>>
>>> I think we should not bother testing for src == dst. It's
>>> vanishingly unlikely to actually happen, and if it does
>>> happen then the code will work fine, and it's probably better
>>> to actually do the access in that case than to skip it.
>>>
>>
>> We can drop the check of (src == dst), but it will introduce inconsistent
>> behaviors. For example, qemu_ram_move(0x1, 0x1, 0x2) is finally turned to
>> memmove(0x1, 0x1,0x2) where no memory movement happens in glibc::memmove(),
>> but qemu_ram_move(0x0, 0x0, 0x2) is turned to qatomic_set((uint16_t *)dst,
>> qatomic_read((uint16_t *)src)) where we do have memory movement happening.
>> So I would like to keep the check of (src == dst) in order for the consistent
>> behaviors.
> 
> Well, it depends on which kind of consistency you want.
> If we do the src == dst check, then we have the inconsistency
> that a small aligned access always happens exactly once,
> *unless* it happens that src == dst, in which case it doesn't
> happen even though the caller asked for it.
> 
> You can see this in the documentation comment I suggested above:
> if you don't check 'src == dst' then you can document it as
> "memmove, plus for a small access where src and dst are naturally
> aligned we guarantee it to happen exactly once atomically".
> If you do check src == dst then it gets more complicated,
> because you have to say "memmove, plus for a small access
> where src and dest are naturally aligned *and* src != dst then ...".
> 
> I think that because it's the small sized accesses where we
> know that it might be necessary to really actually do the
> access, that we should do that also for src == dst.
> 
>>>> +    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) {
   ...