qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/2] tcg: fix TLB miss check in get_page_addr_code()
@ 2018-06-29 16:21 Peter Maydell
  2018-06-29 16:21 ` [Qemu-devel] [PATCH 1/2] tcg: Define and use new tlb_hit() and tlb_hit_page() functions Peter Maydell
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Peter Maydell @ 2018-06-29 16:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: patches, Richard Henderson, Laurent Vivier

In commit 71b9a45330fe220d1 we changed the condition we use to
determine whether we need to refill the TLB in get_page_addr_code() to
        if (unlikely(env->tlb_table[mmu_idx][index].addr_code !=
                     (addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)))) {

This isn't the right check (it will falsely fail if the
input addr happens to have the low bit corresponding to
TLB_INVALID_MASK set, for instance).

This patchset first factors out the "check for a hit" logic
into some new functions tlb_hit() and tlb_hit_page() (the
latter is for when the address is known to be page-aligned),
uses those functions in the various places that do TLB hit tests,
and then uses tlb_hit() to replace the erroneous code in
get_page_addr_code().

I noticed this while trying to debug Laurent's m68k test case:
it meant that we would come into get_page_addr_code() for a
TLB hit, falsely decide it was a miss, and then fish an
older entry out of the TLB victim cache...


Peter Maydell (2):
  tcg: Define and use new tlb_hit() and tlb_hit_page() functions
  accel/tcg: Correct "is this a TLB miss" check in get_page_addr_code()

 accel/tcg/softmmu_template.h | 16 ++++++----------
 include/exec/cpu-all.h       | 23 +++++++++++++++++++++++
 include/exec/cpu_ldst.h      |  3 +--
 accel/tcg/cputlb.c           | 18 ++++++------------
 4 files changed, 36 insertions(+), 24 deletions(-)

-- 
2.17.1

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

* [Qemu-devel] [PATCH 1/2] tcg: Define and use new tlb_hit() and tlb_hit_page() functions
  2018-06-29 16:21 [Qemu-devel] [PATCH 0/2] tcg: fix TLB miss check in get_page_addr_code() Peter Maydell
@ 2018-06-29 16:21 ` Peter Maydell
  2018-06-29 16:21 ` [Qemu-devel] [PATCH 2/2] accel/tcg: Correct "is this a TLB miss" check in get_page_addr_code() Peter Maydell
  2018-06-29 17:39 ` [Qemu-devel] [PATCH 0/2] tcg: fix TLB miss " Richard Henderson
  2 siblings, 0 replies; 4+ messages in thread
From: Peter Maydell @ 2018-06-29 16:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: patches, Richard Henderson, Laurent Vivier

The condition to check whether an address has hit against a particular
TLB entry is not completely trivial. We do this in various places, and
in fact in one place (get_page_addr_code()) we have got the condition
wrong. Abstract it out into new tlb_hit() and tlb_hit_page() inline
functions (one for a known-page-aligned address and one for an
arbitrary address), and use them in all the places where we had the
condition correct.

This is a no-behaviour-change patch; we leave fixing the buggy
code in get_page_addr_code() to a subsequent patch.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 accel/tcg/softmmu_template.h | 16 ++++++----------
 include/exec/cpu-all.h       | 23 +++++++++++++++++++++++
 include/exec/cpu_ldst.h      |  3 +--
 accel/tcg/cputlb.c           | 15 +++++----------
 4 files changed, 35 insertions(+), 22 deletions(-)

diff --git a/accel/tcg/softmmu_template.h b/accel/tcg/softmmu_template.h
index c47591c9709..badbf148803 100644
--- a/accel/tcg/softmmu_template.h
+++ b/accel/tcg/softmmu_template.h
@@ -123,8 +123,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr,
     }
 
     /* 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 (!tlb_hit(tlb_addr, addr)) {
         if (!VICTIM_TLB_HIT(ADDR_READ, addr)) {
             tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, READ_ACCESS_TYPE,
                      mmu_idx, retaddr);
@@ -191,8 +190,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr,
     }
 
     /* 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 (!tlb_hit(tlb_addr, addr)) {
         if (!VICTIM_TLB_HIT(ADDR_READ, addr)) {
             tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, READ_ACCESS_TYPE,
                      mmu_idx, retaddr);
@@ -286,8 +284,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
     }
 
     /* 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 (!tlb_hit(tlb_addr, addr)) {
         if (!VICTIM_TLB_HIT(addr_write, addr)) {
             tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, MMU_DATA_STORE,
                      mmu_idx, retaddr);
@@ -322,7 +319,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
         page2 = (addr + DATA_SIZE) & TARGET_PAGE_MASK;
         index2 = (page2 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
         tlb_addr2 = env->tlb_table[mmu_idx][index2].addr_write;
-        if (page2 != (tlb_addr2 & (TARGET_PAGE_MASK | TLB_INVALID_MASK))
+        if (!tlb_hit_page(tlb_addr2, page2)
             && !VICTIM_TLB_HIT(addr_write, page2)) {
             tlb_fill(ENV_GET_CPU(env), page2, DATA_SIZE, MMU_DATA_STORE,
                      mmu_idx, retaddr);
@@ -364,8 +361,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
     }
 
     /* 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 (!tlb_hit(tlb_addr, addr)) {
         if (!VICTIM_TLB_HIT(addr_write, addr)) {
             tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, MMU_DATA_STORE,
                      mmu_idx, retaddr);
@@ -400,7 +396,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
         page2 = (addr + DATA_SIZE) & TARGET_PAGE_MASK;
         index2 = (page2 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
         tlb_addr2 = env->tlb_table[mmu_idx][index2].addr_write;
-        if (page2 != (tlb_addr2 & (TARGET_PAGE_MASK | TLB_INVALID_MASK))
+        if (!tlb_hit_page(tlb_addr2, page2)
             && !VICTIM_TLB_HIT(addr_write, page2)) {
             tlb_fill(ENV_GET_CPU(env), page2, DATA_SIZE, MMU_DATA_STORE,
                      mmu_idx, retaddr);
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index 7338f57062f..117d2fbbcac 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -339,6 +339,29 @@ CPUArchState *cpu_copy(CPUArchState *env);
 #define TLB_FLAGS_MASK  (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO \
                          | TLB_RECHECK)
 
+/**
+ * tlb_hit_page: return true if page aligned @addr is a hit against the
+ * TLB entry @tlb_addr
+ *
+ * @addr: virtual address to test (must be page aligned)
+ * @tlb_addr: TLB entry address (a CPUTLBEntry addr_read/write/code value)
+ */
+static inline bool tlb_hit_page(target_ulong tlb_addr, target_ulong addr)
+{
+    return addr == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK));
+}
+
+/**
+ * tlb_hit: return true if @addr is a hit against the TLB entry @tlb_addr
+ *
+ * @addr: virtual address to test (need not be page aligned)
+ * @tlb_addr: TLB entry address (a CPUTLBEntry addr_read/write/code value)
+ */
+static inline bool tlb_hit(target_ulong tlb_addr, target_ulong addr)
+{
+    return tlb_hit_page(tlb_addr, addr & TARGET_PAGE_MASK);
+}
+
 void dump_exec_info(FILE *f, fprintf_function cpu_fprintf);
 void dump_opcount_info(FILE *f, fprintf_function cpu_fprintf);
 #endif /* !CONFIG_USER_ONLY */
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
index 5de8c8a5afe..0f2cb717b15 100644
--- a/include/exec/cpu_ldst.h
+++ b/include/exec/cpu_ldst.h
@@ -422,8 +422,7 @@ static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
         g_assert_not_reached();
     }
 
-    if ((addr & TARGET_PAGE_MASK)
-        != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+    if (!tlb_hit(tlb_addr, addr)) {
         /* TLB entry is for a different page */
         return NULL;
     }
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index eebe97dabb7..adb711963bf 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -239,12 +239,9 @@ void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *src_cpu,
 
 static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
 {
-    if (addr == (tlb_entry->addr_read &
-                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
-        addr == (tlb_entry->addr_write &
-                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
-        addr == (tlb_entry->addr_code &
-                 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+    if (tlb_hit_page(tlb_entry->addr_read, addr) ||
+        tlb_hit_page(tlb_entry->addr_write, addr) ||
+        tlb_hit_page(tlb_entry->addr_code, addr)) {
         memset(tlb_entry, -1, sizeof(*tlb_entry));
     }
 }
@@ -1046,8 +1043,7 @@ void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx,
     int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
 
-    if ((addr & TARGET_PAGE_MASK)
-        != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+    if (!tlb_hit(tlb_addr, addr)) {
         /* TLB entry is for a different page */
         if (!VICTIM_TLB_HIT(addr_write, addr)) {
             tlb_fill(ENV_GET_CPU(env), addr, size, MMU_DATA_STORE,
@@ -1091,8 +1087,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
     }
 
     /* Check TLB entry and enforce page permissions.  */
-    if ((addr & TARGET_PAGE_MASK)
-        != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+    if (!tlb_hit(tlb_addr, addr)) {
         if (!VICTIM_TLB_HIT(addr_write, addr)) {
             tlb_fill(ENV_GET_CPU(env), addr, 1 << s_bits, MMU_DATA_STORE,
                      mmu_idx, retaddr);
-- 
2.17.1

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

* [Qemu-devel] [PATCH 2/2] accel/tcg: Correct "is this a TLB miss" check in get_page_addr_code()
  2018-06-29 16:21 [Qemu-devel] [PATCH 0/2] tcg: fix TLB miss check in get_page_addr_code() Peter Maydell
  2018-06-29 16:21 ` [Qemu-devel] [PATCH 1/2] tcg: Define and use new tlb_hit() and tlb_hit_page() functions Peter Maydell
@ 2018-06-29 16:21 ` Peter Maydell
  2018-06-29 17:39 ` [Qemu-devel] [PATCH 0/2] tcg: fix TLB miss " Richard Henderson
  2 siblings, 0 replies; 4+ messages in thread
From: Peter Maydell @ 2018-06-29 16:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: patches, Richard Henderson, Laurent Vivier

In commit 71b9a45330fe220d1 we changed the condition we use
to determine whether we need to refill the TLB in
get_page_addr_code() to
    if (unlikely(env->tlb_table[mmu_idx][index].addr_code !=
                 (addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)))) {

This isn't the right check (it will falsely fail if the
input addr happens to have the low bit corresponding to
TLB_INVALID_MASK set, for instance). Replace it with a
use of the new tlb_hit() function, which is the correct test.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 accel/tcg/cputlb.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index adb711963bf..3ae1198c245 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -957,8 +957,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
 
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     mmu_idx = cpu_mmu_index(env, true);
-    if (unlikely(env->tlb_table[mmu_idx][index].addr_code !=
-                 (addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)))) {
+    if (unlikely(!tlb_hit(env->tlb_table[mmu_idx][index].addr_code, addr))) {
         if (!VICTIM_TLB_HIT(addr_read, addr)) {
             tlb_fill(ENV_GET_CPU(env), addr, 0, MMU_INST_FETCH, mmu_idx, 0);
         }
-- 
2.17.1

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

* Re: [Qemu-devel] [PATCH 0/2] tcg: fix TLB miss check in get_page_addr_code()
  2018-06-29 16:21 [Qemu-devel] [PATCH 0/2] tcg: fix TLB miss check in get_page_addr_code() Peter Maydell
  2018-06-29 16:21 ` [Qemu-devel] [PATCH 1/2] tcg: Define and use new tlb_hit() and tlb_hit_page() functions Peter Maydell
  2018-06-29 16:21 ` [Qemu-devel] [PATCH 2/2] accel/tcg: Correct "is this a TLB miss" check in get_page_addr_code() Peter Maydell
@ 2018-06-29 17:39 ` Richard Henderson
  2 siblings, 0 replies; 4+ messages in thread
From: Richard Henderson @ 2018-06-29 17:39 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel; +Cc: patches, Laurent Vivier

On 06/29/2018 09:21 AM, Peter Maydell wrote:
> In commit 71b9a45330fe220d1 we changed the condition we use to
> determine whether we need to refill the TLB in get_page_addr_code() to
>         if (unlikely(env->tlb_table[mmu_idx][index].addr_code !=
>                      (addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)))) {
> 
> This isn't the right check (it will falsely fail if the
> input addr happens to have the low bit corresponding to
> TLB_INVALID_MASK set, for instance).
> 
> This patchset first factors out the "check for a hit" logic
> into some new functions tlb_hit() and tlb_hit_page() (the
> latter is for when the address is known to be page-aligned),
> uses those functions in the various places that do TLB hit tests,
> and then uses tlb_hit() to replace the erroneous code in
> get_page_addr_code().
> 
> I noticed this while trying to debug Laurent's m68k test case:
> it meant that we would come into get_page_addr_code() for a
> TLB hit, falsely decide it was a miss, and then fish an
> older entry out of the TLB victim cache...
> 
> 
> Peter Maydell (2):
>   tcg: Define and use new tlb_hit() and tlb_hit_page() functions
>   accel/tcg: Correct "is this a TLB miss" check in get_page_addr_code()

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Also, queued to tcg-next.


r~

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

end of thread, other threads:[~2018-06-29 17:39 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-06-29 16:21 [Qemu-devel] [PATCH 0/2] tcg: fix TLB miss check in get_page_addr_code() Peter Maydell
2018-06-29 16:21 ` [Qemu-devel] [PATCH 1/2] tcg: Define and use new tlb_hit() and tlb_hit_page() functions Peter Maydell
2018-06-29 16:21 ` [Qemu-devel] [PATCH 2/2] accel/tcg: Correct "is this a TLB miss" check in get_page_addr_code() Peter Maydell
2018-06-29 17:39 ` [Qemu-devel] [PATCH 0/2] tcg: fix TLB miss " Richard Henderson

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).