diff mbox

[RFC,01/30] softmmu: add cmpxchg helpers

Message ID 1467054136-10430-2-git-send-email-cota@braap.org
State New
Headers show

Commit Message

Emilio Cota June 27, 2016, 7:01 p.m. UTC
Signed-off-by: Emilio G. Cota <cota@braap.org>
---
 softmmu_template.h | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tcg/tcg.h          | 16 +++++++++++++++
 2 files changed, 74 insertions(+)

Comments

Richard Henderson June 27, 2016, 8:11 p.m. UTC | #1
On 06/27/2016 12:01 PM, Emilio G. Cota wrote:
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> ---
>  softmmu_template.h | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  tcg/tcg.h          | 16 +++++++++++++++
>  2 files changed, 74 insertions(+)
>
> diff --git a/softmmu_template.h b/softmmu_template.h
> index 208f808..7b519dc 100644
> --- a/softmmu_template.h
> +++ b/softmmu_template.h
> @@ -548,6 +548,64 @@ void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx,
>      }
>  }
>  #endif
> +
> +DATA_TYPE
> +glue(glue(helper_cmpxchg, SUFFIX),
> +     MMUSUFFIX)(CPUArchState *env, target_ulong addr, DATA_TYPE old,
> +                DATA_TYPE new, TCGMemOpIdx oi, uintptr_t retaddr)
> +{
> +    unsigned mmu_idx = get_mmuidx(oi);
> +    int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
> +    target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
> +    uintptr_t haddr;
> +
> +    /* Adjust the given return address.  */
> +    retaddr -= GETPC_ADJ;
> +
> +    /* If the TLB entry is for a different page, reload and try again.  */
> +    if ((addr & TARGET_PAGE_MASK)
> +        != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
> +        if (unlikely((addr & (DATA_SIZE - 1)) != 0
> +                     && (get_memop(oi) & MO_AMASK) == MO_ALIGN)) {
> +            cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
> +                                 mmu_idx, retaddr);
> +        }
> +        if (!VICTIM_TLB_HIT(addr_write)) {
> +            tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
> +        }
> +        tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
> +    }

You need to verify that addr_read == addr_write as well, so that tlb_fill can 
signal an exception in the rare case of a guest attempting a cmpxchg on a 
write-only page.

> +    /*
> +     * If the host allows unaligned accesses, then let the compiler
> +     * do its thing when performing the access on the host.
> +     */
> +    haddr = addr + env->tlb_table[mmu_idx][index].addend;
> +    return atomic_cmpxchg((DATA_TYPE *)haddr, old, new);

Host endian operation?


r~
Emilio Cota June 27, 2016, 9:19 p.m. UTC | #2
On Mon, Jun 27, 2016 at 13:11:28 -0700, Richard Henderson wrote:
> On 06/27/2016 12:01 PM, Emilio G. Cota wrote:
> >Signed-off-by: Emilio G. Cota <cota@braap.org>
> >---
> > softmmu_template.h | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > tcg/tcg.h          | 16 +++++++++++++++
> > 2 files changed, 74 insertions(+)
> >
> >diff --git a/softmmu_template.h b/softmmu_template.h
> >index 208f808..7b519dc 100644
> >--- a/softmmu_template.h
> >+++ b/softmmu_template.h
> >@@ -548,6 +548,64 @@ void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx,
> >     }
> > }
> > #endif
> >+
> >+DATA_TYPE
> >+glue(glue(helper_cmpxchg, SUFFIX),
> >+     MMUSUFFIX)(CPUArchState *env, target_ulong addr, DATA_TYPE old,
> >+                DATA_TYPE new, TCGMemOpIdx oi, uintptr_t retaddr)
> >+{
> >+    unsigned mmu_idx = get_mmuidx(oi);
> >+    int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
> >+    target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
> >+    uintptr_t haddr;
> >+
> >+    /* Adjust the given return address.  */
> >+    retaddr -= GETPC_ADJ;
> >+
> >+    /* If the TLB entry is for a different page, reload and try again.  */
> >+    if ((addr & TARGET_PAGE_MASK)
> >+        != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
> >+        if (unlikely((addr & (DATA_SIZE - 1)) != 0
> >+                     && (get_memop(oi) & MO_AMASK) == MO_ALIGN)) {
> >+            cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
> >+                                 mmu_idx, retaddr);
> >+        }
> >+        if (!VICTIM_TLB_HIT(addr_write)) {
> >+            tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
> >+        }
> >+        tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
> >+    }
> 
> You need to verify that addr_read == addr_write as well, so that tlb_fill
> can signal an exception in the rare case of a guest attempting a cmpxchg on
> a write-only page.

Will do.

> >+    /*
> >+     * If the host allows unaligned accesses, then let the compiler
> >+     * do its thing when performing the access on the host.
> >+     */
> >+    haddr = addr + env->tlb_table[mmu_idx][index].addend;
> >+    return atomic_cmpxchg((DATA_TYPE *)haddr, old, new);
> 
> Host endian operation?

I forgot to add byte ordering in the cover letter under "why this is
an RFC" -- I admit I'm confused by all the macro trickery done for
regular loads and stores.

We store data in memory as per the guests' byte ordering, right?
If so, I don't see how it would be possible to leverage the
host compiler for things like atomic_add -- we'd increment garbage,
not a meaningful value.

		Emilio
Richard Henderson June 27, 2016, 9:43 p.m. UTC | #3
On 06/27/2016 02:19 PM, Emilio G. Cota wrote:
>> Host endian operation?
>
> I forgot to add byte ordering in the cover letter under "why this is
> an RFC" -- I admit I'm confused by all the macro trickery done for
> regular loads and stores.
>
> We store data in memory as per the guests' byte ordering, right?

Sometimes.  The guest can also explicitly request a reversed byte load/store. 
This is used both for explicit byte-reversing instructions (e.g. x86 movbe) and 
toggling the system byte order (arm setbe).


> If so, I don't see how it would be possible to leverage the
> host compiler for things like atomic_add -- we'd increment garbage,
> not a meaningful value.

All you need to do is byte-reverse the data.

   bswap(a + b) == bswap(a) + bswap(b).


r~
Peter Maydell June 27, 2016, 9:48 p.m. UTC | #4
On 27 June 2016 at 22:43, Richard Henderson <rth@twiddle.net> wrote:
> All you need to do is byte-reverse the data.
>
>   bswap(a + b) == bswap(a) + bswap(b).

?

0xFF + 0xFF == 0x1FE, bswap(0x1FE) == 0xFE010000
bswap(0xFF) + bswap(0xFF) == 0xFF000000 + 0xFF000000 == 0x1FE000000
(or 0xFE000000 with truncate to 32-bit).

Or am I missing something?

thanks
-- PMM
Richard Henderson June 27, 2016, 9:53 p.m. UTC | #5
On 06/27/2016 02:48 PM, Peter Maydell wrote:
> On 27 June 2016 at 22:43, Richard Henderson <rth@twiddle.net> wrote:
>> All you need to do is byte-reverse the data.
>>
>>   bswap(a + b) == bswap(a) + bswap(b).
>
> ?
>
> 0xFF + 0xFF == 0x1FE, bswap(0x1FE) == 0xFE010000
> bswap(0xFF) + bswap(0xFF) == 0xFF000000 + 0xFF000000 == 0x1FE000000
> (or 0xFE000000 with truncate to 32-bit).
>
> Or am I missing something?

No, you're quite right.  I think I didn't have enough coffee this morning.

So we'd need a cmpxchg loop for reverse-endian add.


r~
diff mbox

Patch

diff --git a/softmmu_template.h b/softmmu_template.h
index 208f808..7b519dc 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -548,6 +548,64 @@  void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx,
     }
 }
 #endif
+
+DATA_TYPE
+glue(glue(helper_cmpxchg, SUFFIX),
+     MMUSUFFIX)(CPUArchState *env, target_ulong addr, DATA_TYPE old,
+                DATA_TYPE new, TCGMemOpIdx oi, uintptr_t retaddr)
+{
+    unsigned mmu_idx = get_mmuidx(oi);
+    int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+    target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
+    uintptr_t haddr;
+
+    /* Adjust the given return address.  */
+    retaddr -= GETPC_ADJ;
+
+    /* If the TLB entry is for a different page, reload and try again.  */
+    if ((addr & TARGET_PAGE_MASK)
+        != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+        if (unlikely((addr & (DATA_SIZE - 1)) != 0
+                     && (get_memop(oi) & MO_AMASK) == MO_ALIGN)) {
+            cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
+                                 mmu_idx, retaddr);
+        }
+        if (!VICTIM_TLB_HIT(addr_write)) {
+            tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
+        }
+        tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
+    }
+
+    /* Handle an IO access.  */
+    if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) {
+        /* XXX */
+        abort();
+    }
+
+    /* Handle slow unaligned access (it spans two pages or IO).  */
+    if (DATA_SIZE > 1
+        && unlikely((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1
+                     >= TARGET_PAGE_SIZE)) {
+        if ((get_memop(oi) & MO_AMASK) == MO_ALIGN) {
+            cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
+                                 mmu_idx, retaddr);
+        }
+    }
+
+    /* Handle aligned access or unaligned access in the same page.  */
+    if (unlikely((addr & (DATA_SIZE - 1)) != 0
+                 && (get_memop(oi) & MO_AMASK) == MO_ALIGN)) {
+        cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
+                             mmu_idx, retaddr);
+    }
+    /*
+     * If the host allows unaligned accesses, then let the compiler
+     * do its thing when performing the access on the host.
+     */
+    haddr = addr + env->tlb_table[mmu_idx][index].addend;
+    return atomic_cmpxchg((DATA_TYPE *)haddr, old, new);
+}
+
 #endif /* !defined(SOFTMMU_CODE_ACCESS) */
 
 #undef READ_ACCESS_TYPE
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 66d7fc0..1fd7ec3 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -1101,6 +1101,22 @@  uint64_t helper_be_ldq_cmmu(CPUArchState *env, target_ulong addr,
 # define helper_ret_ldq_cmmu  helper_le_ldq_cmmu
 #endif
 
+uint8_t helper_cmpxchgb_mmu(CPUArchState *env, target_ulong addr,
+                            uint8_t old, uint8_t new,
+                            TCGMemOpIdx oi, uintptr_t retaddr);
+
+uint16_t helper_cmpxchgw_mmu(CPUArchState *env, target_ulong addr,
+                             uint16_t old, uint16_t new,
+                             TCGMemOpIdx oi, uintptr_t retaddr);
+
+uint32_t helper_cmpxchgl_mmu(CPUArchState *env, target_ulong addr,
+                             uint32_t old, uint32_t new,
+                             TCGMemOpIdx oi, uintptr_t retaddr);
+
+uint64_t helper_cmpxchgq_mmu(CPUArchState *env, target_ulong addr,
+                             uint64_t old, uint64_t new,
+                             TCGMemOpIdx oi, uintptr_t retaddr);
+
 #endif /* CONFIG_SOFTMMU */
 
 #endif /* TCG_H */