qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v2] arm/ptw: Handle atomic updates of page tables entries in MMIO during PTW.
@ 2024-02-19 16:12 Jonathan Cameron via
  2024-02-22 21:21 ` Richard Henderson
  0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Cameron via @ 2024-02-19 16:12 UTC (permalink / raw)
  To: qemu-devel, Peter Maydell, Gregory Price, Alex Bennée,
	richard.henderson
  Cc: linux-cxl, linuxarm

I'm far from confident this handling here is correct. Hence
RFC.  In particular not sure on what locks I should hold for this
to be even moderately safe.

The function already appears to be inconsistent in what it returns
as the CONFIG_ATOMIC64 block returns the endian converted 'eventual'
value of the cmpxchg whereas the TCG_OVERSIZED_GUEST case returns
the previous value.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
v2: Thanks Peter for reviewing.
 - Handle the address space as in arm_ldq_ptw() - I should have looked
   at the code immediately above :(
   The result ends up a little more convoluted than I'd like. Could factor
   this block of code out perhaps. I'm also not sure on the fault type
   that is appropriate here.
 - Switch to 'need_lock' as per Philippe's feedback on the x86 fixes.
   likely() doesn't seem appropriate here though.
 
target/arm/ptw.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 62 insertions(+), 2 deletions(-)

diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 5eb3577bcd..ba1a27ca2b 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -711,8 +711,68 @@ static uint64_t arm_casq_ptw(CPUARMState *env, uint64_t old_val,
     void *host = ptw->out_host;
 
     if (unlikely(!host)) {
-        fi->type = ARMFault_UnsuppAtomicUpdate;
-        return 0;
+        /* Page table in MMIO Memory Region */
+        CPUState *cs = env_cpu(env);
+        MemTxAttrs attrs = {
+            .space = ptw->out_space,
+            .secure = arm_space_is_secure(ptw->out_space),
+        };
+        AddressSpace *as = arm_addressspace(cs, attrs);
+        MemTxResult result = MEMTX_OK;
+        bool need_lock = !bql_locked();
+
+        if (need_lock) {
+            bql_lock();
+        }
+        if (ptw->out_be) {
+            cur_val = address_space_ldq_be(as, ptw->out_phys, attrs, &result);
+            if (unlikely(result != MEMTX_OK)) {
+                fi->type = ARMFault_SyncExternalOnWalk;
+                fi->ea = arm_extabort_type(result);
+                if (need_lock) {
+                    bql_unlock();
+                }
+                return old_val;
+            }
+            if (cur_val == old_val) {
+                address_space_stq_be(as, ptw->out_phys, new_val, attrs, &result);
+                if (unlikely(result != MEMTX_OK)) {
+                    fi->type = ARMFault_SyncExternalOnWalk;
+                    fi->ea = arm_extabort_type(result);
+                    if (need_lock) {
+                        bql_unlock();
+                    }
+                    return old_val;
+                }
+                cur_val = new_val;
+            }
+        } else {
+            cur_val = address_space_ldq_le(as, ptw->out_phys, attrs, &result);
+            if (unlikely(result != MEMTX_OK)) {
+                fi->type = ARMFault_SyncExternalOnWalk;
+                fi->ea = arm_extabort_type(result);
+                if (need_lock) {
+                    bql_unlock();
+                }
+                return old_val;
+            }
+            if (cur_val == old_val) {
+                address_space_stq_le(as, ptw->out_phys, new_val, attrs, &result);
+                if (unlikely(result != MEMTX_OK)) {
+                    fi->type = ARMFault_SyncExternalOnWalk;
+                    fi->ea = arm_extabort_type(result);
+                    if (need_lock) {
+                        bql_unlock();
+                    }
+                    return old_val;
+                }
+                cur_val = new_val;
+            }
+        }
+        if (need_lock) {
+            bql_unlock();
+        }
+        return cur_val;
     }
 
     /*
-- 
2.39.2



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [RFC PATCH v2] arm/ptw: Handle atomic updates of page tables entries in MMIO during PTW.
  2024-02-19 16:12 [RFC PATCH v2] arm/ptw: Handle atomic updates of page tables entries in MMIO during PTW Jonathan Cameron via
@ 2024-02-22 21:21 ` Richard Henderson
  2024-02-23 10:02   ` Peter Maydell
  0 siblings, 1 reply; 4+ messages in thread
From: Richard Henderson @ 2024-02-22 21:21 UTC (permalink / raw)
  To: Jonathan Cameron, qemu-devel, Peter Maydell, Gregory Price,
	Alex Bennée
  Cc: linux-cxl, linuxarm

On 2/19/24 06:12, Jonathan Cameron wrote:
> I'm far from confident this handling here is correct. Hence
> RFC.  In particular not sure on what locks I should hold for this
> to be even moderately safe.
> 
> The function already appears to be inconsistent in what it returns
> as the CONFIG_ATOMIC64 block returns the endian converted 'eventual'
> value of the cmpxchg whereas the TCG_OVERSIZED_GUEST case returns
> the previous value.
> 
> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> ---
> v2: Thanks Peter for reviewing.
>   - Handle the address space as in arm_ldq_ptw() - I should have looked
>     at the code immediately above :(
>     The result ends up a little more convoluted than I'd like. Could factor
>     this block of code out perhaps. I'm also not sure on the fault type
>     that is appropriate here.
>   - Switch to 'need_lock' as per Philippe's feedback on the x86 fixes.
>     likely() doesn't seem appropriate here though.
>   
> target/arm/ptw.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++--
>   1 file changed, 62 insertions(+), 2 deletions(-)
> 
> diff --git a/target/arm/ptw.c b/target/arm/ptw.c
> index 5eb3577bcd..ba1a27ca2b 100644
> --- a/target/arm/ptw.c
> +++ b/target/arm/ptw.c
> @@ -711,8 +711,68 @@ static uint64_t arm_casq_ptw(CPUARMState *env, uint64_t old_val,
>       void *host = ptw->out_host;
>   
>       if (unlikely(!host)) {
> -        fi->type = ARMFault_UnsuppAtomicUpdate;
> -        return 0;
> +        /* Page table in MMIO Memory Region */
> +        CPUState *cs = env_cpu(env);
> +        MemTxAttrs attrs = {
> +            .space = ptw->out_space,
> +            .secure = arm_space_is_secure(ptw->out_space),
> +        };
> +        AddressSpace *as = arm_addressspace(cs, attrs);
> +        MemTxResult result = MEMTX_OK;
> +        bool need_lock = !bql_locked();
> +
> +        if (need_lock) {
> +            bql_lock();
> +        }
> +        if (ptw->out_be) {
> +            cur_val = address_space_ldq_be(as, ptw->out_phys, attrs, &result);
> +            if (unlikely(result != MEMTX_OK)) {
> +                fi->type = ARMFault_SyncExternalOnWalk;
> +                fi->ea = arm_extabort_type(result);
> +                if (need_lock) {
> +                    bql_unlock();
> +                }
> +                return old_val;
> +            }

Use BQL_LOCK_GUARD() and avoid all of the repeated unlocks at each return point.

You can merge all of the error paths, e.g.

     cur_val = (ptw->out_be
                ? address_space_ldq_be(as, ptw->out_phys, attrs, &result)
                : address_space_ldq_le(as, ptw->out_phys, attrs, &result));
     if (result == MEMTX_OK && cur_val == old_val) {
         if (ptw->out_be) {
             address_space_stq_be(as, ptw->out_phys, new_val, attrs, &result);
         } else {
             address_space_stq_le(as, ptw->out_phys, new_val, attrs, &result);
         }
     }
     if (unlikely(result != MEMTX_OK)) {
         fi->type = ...
         return old_val;
     }
     return cur_val;



r~


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC PATCH v2] arm/ptw: Handle atomic updates of page tables entries in MMIO during PTW.
  2024-02-22 21:21 ` Richard Henderson
@ 2024-02-23 10:02   ` Peter Maydell
  2024-02-23 18:08     ` Peter Maydell
  0 siblings, 1 reply; 4+ messages in thread
From: Peter Maydell @ 2024-02-23 10:02 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Jonathan Cameron, qemu-devel, Gregory Price, Alex Bennée,
	linux-cxl, linuxarm

On Thu, 22 Feb 2024 at 21:21, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 2/19/24 06:12, Jonathan Cameron wrote:
> > I'm far from confident this handling here is correct. Hence
> > RFC.  In particular not sure on what locks I should hold for this
> > to be even moderately safe.
> >
> > The function already appears to be inconsistent in what it returns
> > as the CONFIG_ATOMIC64 block returns the endian converted 'eventual'
> > value of the cmpxchg whereas the TCG_OVERSIZED_GUEST case returns
> > the previous value.

I think this is a bug in the TCG_OVERSIZED_GUEST handling,
which we've never noticed because you only see that case
on a 32-bit host.

> > Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > ---
> > v2: Thanks Peter for reviewing.
> >   - Handle the address space as in arm_ldq_ptw() - I should have looked
> >     at the code immediately above :(
> >     The result ends up a little more convoluted than I'd like. Could factor
> >     this block of code out perhaps. I'm also not sure on the fault type
> >     that is appropriate here.
> >   - Switch to 'need_lock' as per Philippe's feedback on the x86 fixes.
> >     likely() doesn't seem appropriate here though.
> >
> > target/arm/ptw.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++--
> >   1 file changed, 62 insertions(+), 2 deletions(-)
> >
> > diff --git a/target/arm/ptw.c b/target/arm/ptw.c
> > index 5eb3577bcd..ba1a27ca2b 100644
> > --- a/target/arm/ptw.c
> > +++ b/target/arm/ptw.c
> > @@ -711,8 +711,68 @@ static uint64_t arm_casq_ptw(CPUARMState *env, uint64_t old_val,
> >       void *host = ptw->out_host;
> >
> >       if (unlikely(!host)) {
> > -        fi->type = ARMFault_UnsuppAtomicUpdate;
> > -        return 0;
> > +        /* Page table in MMIO Memory Region */
> > +        CPUState *cs = env_cpu(env);
> > +        MemTxAttrs attrs = {
> > +            .space = ptw->out_space,
> > +            .secure = arm_space_is_secure(ptw->out_space),
> > +        };
> > +        AddressSpace *as = arm_addressspace(cs, attrs);
> > +        MemTxResult result = MEMTX_OK;
> > +        bool need_lock = !bql_locked();
> > +
> > +        if (need_lock) {
> > +            bql_lock();
> > +        }
> > +        if (ptw->out_be) {
> > +            cur_val = address_space_ldq_be(as, ptw->out_phys, attrs, &result);
> > +            if (unlikely(result != MEMTX_OK)) {
> > +                fi->type = ARMFault_SyncExternalOnWalk;
> > +                fi->ea = arm_extabort_type(result);
> > +                if (need_lock) {
> > +                    bql_unlock();
> > +                }
> > +                return old_val;
> > +            }
>
> Use BQL_LOCK_GUARD() and avoid all of the repeated unlocks at each return point.

Is the BQL definitely sufficient to ensure atomicity here?
I guess that given that we know it's not backed by host
memory, any other vCPU trying to access the MMIO region
at the same time will have to take the BQL first, so it
seems like it ought to be good enough.

-- PMM


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC PATCH v2] arm/ptw: Handle atomic updates of page tables entries in MMIO during PTW.
  2024-02-23 10:02   ` Peter Maydell
@ 2024-02-23 18:08     ` Peter Maydell
  0 siblings, 0 replies; 4+ messages in thread
From: Peter Maydell @ 2024-02-23 18:08 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Jonathan Cameron, qemu-devel, Gregory Price, Alex Bennée,
	linux-cxl, linuxarm

On Fri, 23 Feb 2024 at 10:02, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Thu, 22 Feb 2024 at 21:21, Richard Henderson
> <richard.henderson@linaro.org> wrote:
> >
> > On 2/19/24 06:12, Jonathan Cameron wrote:
> > > I'm far from confident this handling here is correct. Hence
> > > RFC.  In particular not sure on what locks I should hold for this
> > > to be even moderately safe.
> > >
> > > The function already appears to be inconsistent in what it returns
> > > as the CONFIG_ATOMIC64 block returns the endian converted 'eventual'
> > > value of the cmpxchg whereas the TCG_OVERSIZED_GUEST case returns
> > > the previous value.
>
> I think this is a bug in the TCG_OVERSIZED_GUEST handling,
> which we've never noticed because you only see that case
> on a 32-bit host.

Having looked through the code and talked to Richard on IRC,
I think that the TCG_OVERSIZED_GUEST handling is correct.
The return value of qatomic_cmpxchg__nocheck() is the value
that was in memory before the cmpxchg. So the TCG_OVERSIZED_GUEST
code's semantics are the same as the normal path. (The comment on
qatomic_cmpxchg__nocheck() that describes this as the
"eventual value" is rather confusing so we should improve that.)

thanks
-- PMM


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-02-23 18:22 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-19 16:12 [RFC PATCH v2] arm/ptw: Handle atomic updates of page tables entries in MMIO during PTW Jonathan Cameron via
2024-02-22 21:21 ` Richard Henderson
2024-02-23 10:02   ` Peter Maydell
2024-02-23 18:08     ` Peter Maydell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).