diff mbox series

[4/6] exec: Factor out cpu_watchpoint_address_matches

Message ID 20190824213451.31118-5-richard.henderson@linaro.org
State Superseded
Headers show
Series exec: Cleanup watchpoints | expand

Commit Message

Richard Henderson Aug. 24, 2019, 9:34 p.m. UTC
We want to move the check for watchpoints from
memory_region_section_get_iotlb to tlb_set_page_with_attrs.
Isolate the loop over watchpoints to an exported function.

Rename the existing cpu_watchpoint_address_matches to
watchpoint_address_matches, since it doesn't actually
have a cpu argument.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

---
 include/hw/core/cpu.h |  7 +++++++
 exec.c                | 45 ++++++++++++++++++++++++++++---------------
 2 files changed, 36 insertions(+), 16 deletions(-)

-- 
2.17.1

Comments

David Hildenbrand Aug. 26, 2019, 8:41 a.m. UTC | #1
On 24.08.19 23:34, Richard Henderson wrote:
> We want to move the check for watchpoints from

> memory_region_section_get_iotlb to tlb_set_page_with_attrs.

> Isolate the loop over watchpoints to an exported function.

> 

> Rename the existing cpu_watchpoint_address_matches to

> watchpoint_address_matches, since it doesn't actually

> have a cpu argument.

> 

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

> ---

>  include/hw/core/cpu.h |  7 +++++++

>  exec.c                | 45 ++++++++++++++++++++++++++++---------------

>  2 files changed, 36 insertions(+), 16 deletions(-)

> 

> diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h

> index 7bd8bed5b2..c7cda65c66 100644

> --- a/include/hw/core/cpu.h

> +++ b/include/hw/core/cpu.h

> @@ -1096,6 +1096,12 @@ static inline void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,

>                                          MemTxAttrs atr, int fl, uintptr_t ra)

>  {

>  }

> +

> +static inline int cpu_watchpoint_address_matches(CPUState *cpu,

> +                                                 vaddr addr, vaddr len)

> +{

> +    return 0;

> +}

>  #else

>  int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,

>                            int flags, CPUWatchpoint **watchpoint);

> @@ -1105,6 +1111,7 @@ void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint);

>  void cpu_watchpoint_remove_all(CPUState *cpu, int mask);

>  void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,

>                            MemTxAttrs attrs, int flags, uintptr_t ra);

> +int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len);

>  #endif

>  

>  /**

> diff --git a/exec.c b/exec.c

> index cb6f5763dc..8575ce51ad 100644

> --- a/exec.c

> +++ b/exec.c

> @@ -1138,9 +1138,8 @@ void cpu_watchpoint_remove_all(CPUState *cpu, int mask)

>   * partially or completely with the address range covered by the

>   * access).

>   */

> -static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp,

> -                                                  vaddr addr,

> -                                                  vaddr len)

> +static inline bool watchpoint_address_matches(CPUWatchpoint *wp,

> +                                              vaddr addr, vaddr len)

>  {

>      /* We know the lengths are non-zero, but a little caution is

>       * required to avoid errors in the case where the range ends

> @@ -1152,6 +1151,20 @@ static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp,

>  

>      return !(addr > wpend || wp->vaddr > addrend);

>  }

> +

> +/* Return flags for watchpoints that match addr + prot.  */

> +int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len)

> +{

> +    CPUWatchpoint *wp;

> +    int ret = 0;

> +

> +    QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {

> +        if (watchpoint_address_matches(wp, addr, TARGET_PAGE_SIZE)) {

> +            ret |= wp->flags;

> +        }

> +    }

> +    return ret;

> +}

>  #endif /* !CONFIG_USER_ONLY */

>  

>  /* Add a breakpoint.  */

> @@ -1459,7 +1472,7 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,

>                                         target_ulong *address)

>  {

>      hwaddr iotlb;

> -    CPUWatchpoint *wp;

> +    int flags, match;

>  

>      if (memory_region_is_ram(section->mr)) {

>          /* Normal RAM.  */

> @@ -1477,17 +1490,17 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,

>          iotlb += xlat;

>      }

>  

> -    /* Make accesses to pages with watchpoints go via the

> -       watchpoint trap routines.  */

> -    QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {

> -        if (cpu_watchpoint_address_matches(wp, vaddr, TARGET_PAGE_SIZE)) {

> -            /* Avoid trapping reads of pages with a write breakpoint. */

> -            if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {

> -                iotlb = PHYS_SECTION_WATCH + paddr;

> -                *address |= TLB_MMIO;

> -                break;


In the old code, we were able to break once we found a hit ...

> -            }

> -        }

> +    /* Avoid trapping reads of pages with a write breakpoint. */

> +    match = (prot & PAGE_READ ? BP_MEM_READ : 0)

> +          | (prot & PAGE_WRITE ? BP_MEM_WRITE : 0);

> +    flags = cpu_watchpoint_address_matches(cpu, vaddr, TARGET_PAGE_SIZE);

> +    if (flags & match) {


... now you cannot break early anymore. Maybe pass in the match to
cpu_watchpoint_address_matches() ?

Anyhow, code seems to be correct, so

Reviewed-by: David Hildenbrand <david@redhat.com>


-- 

Thanks,

David / dhildenb
Richard Henderson Aug. 28, 2019, 9:28 p.m. UTC | #2
On 8/26/19 1:41 AM, David Hildenbrand wrote:
>> -    /* Make accesses to pages with watchpoints go via the

>> -       watchpoint trap routines.  */

>> -    QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {

>> -        if (cpu_watchpoint_address_matches(wp, vaddr, TARGET_PAGE_SIZE)) {

>> -            /* Avoid trapping reads of pages with a write breakpoint. */

>> -            if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {

>> -                iotlb = PHYS_SECTION_WATCH + paddr;

>> -                *address |= TLB_MMIO;

>> -                break;

> In the old code, we were able to break once we found a hit ...

> 

>> -            }

>> -        }

>> +    /* Avoid trapping reads of pages with a write breakpoint. */

>> +    match = (prot & PAGE_READ ? BP_MEM_READ : 0)

>> +          | (prot & PAGE_WRITE ? BP_MEM_WRITE : 0);

>> +    flags = cpu_watchpoint_address_matches(cpu, vaddr, TARGET_PAGE_SIZE);

>> +    if (flags & match) {

> ... now you cannot break early anymore. Maybe pass in the match to

> cpu_watchpoint_address_matches() ?


Hmm, yes, perhaps.

OTOH, summing a bitmask is a very quick operation.  Depending on the total
number of watchpoints, of course...


r~
David Hildenbrand Aug. 28, 2019, 9:54 p.m. UTC | #3
On 28.08.19 23:28, Richard Henderson wrote:
> On 8/26/19 1:41 AM, David Hildenbrand wrote:

>>> -    /* Make accesses to pages with watchpoints go via the

>>> -       watchpoint trap routines.  */

>>> -    QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {

>>> -        if (cpu_watchpoint_address_matches(wp, vaddr, TARGET_PAGE_SIZE)) {

>>> -            /* Avoid trapping reads of pages with a write breakpoint. */

>>> -            if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {

>>> -                iotlb = PHYS_SECTION_WATCH + paddr;

>>> -                *address |= TLB_MMIO;

>>> -                break;

>> In the old code, we were able to break once we found a hit ...

>>

>>> -            }

>>> -        }

>>> +    /* Avoid trapping reads of pages with a write breakpoint. */

>>> +    match = (prot & PAGE_READ ? BP_MEM_READ : 0)

>>> +          | (prot & PAGE_WRITE ? BP_MEM_WRITE : 0);

>>> +    flags = cpu_watchpoint_address_matches(cpu, vaddr, TARGET_PAGE_SIZE);

>>> +    if (flags & match) {

>> ... now you cannot break early anymore. Maybe pass in the match to

>> cpu_watchpoint_address_matches() ?

> 

> Hmm, yes, perhaps.

> 

> OTOH, summing a bitmask is a very quick operation.  Depending on the total

> number of watchpoints, of course...


And for anything that is not a hit, we have to walk all watchpoints
either way, so the speedup would most probably be neglectable.

-- 

Thanks,

David / dhildenb
diff mbox series

Patch

diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 7bd8bed5b2..c7cda65c66 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -1096,6 +1096,12 @@  static inline void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
                                         MemTxAttrs atr, int fl, uintptr_t ra)
 {
 }
+
+static inline int cpu_watchpoint_address_matches(CPUState *cpu,
+                                                 vaddr addr, vaddr len)
+{
+    return 0;
+}
 #else
 int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
                           int flags, CPUWatchpoint **watchpoint);
@@ -1105,6 +1111,7 @@  void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint);
 void cpu_watchpoint_remove_all(CPUState *cpu, int mask);
 void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
                           MemTxAttrs attrs, int flags, uintptr_t ra);
+int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len);
 #endif
 
 /**
diff --git a/exec.c b/exec.c
index cb6f5763dc..8575ce51ad 100644
--- a/exec.c
+++ b/exec.c
@@ -1138,9 +1138,8 @@  void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
  * partially or completely with the address range covered by the
  * access).
  */
-static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp,
-                                                  vaddr addr,
-                                                  vaddr len)
+static inline bool watchpoint_address_matches(CPUWatchpoint *wp,
+                                              vaddr addr, vaddr len)
 {
     /* We know the lengths are non-zero, but a little caution is
      * required to avoid errors in the case where the range ends
@@ -1152,6 +1151,20 @@  static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp,
 
     return !(addr > wpend || wp->vaddr > addrend);
 }
+
+/* Return flags for watchpoints that match addr + prot.  */
+int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len)
+{
+    CPUWatchpoint *wp;
+    int ret = 0;
+
+    QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
+        if (watchpoint_address_matches(wp, addr, TARGET_PAGE_SIZE)) {
+            ret |= wp->flags;
+        }
+    }
+    return ret;
+}
 #endif /* !CONFIG_USER_ONLY */
 
 /* Add a breakpoint.  */
@@ -1459,7 +1472,7 @@  hwaddr memory_region_section_get_iotlb(CPUState *cpu,
                                        target_ulong *address)
 {
     hwaddr iotlb;
-    CPUWatchpoint *wp;
+    int flags, match;
 
     if (memory_region_is_ram(section->mr)) {
         /* Normal RAM.  */
@@ -1477,17 +1490,17 @@  hwaddr memory_region_section_get_iotlb(CPUState *cpu,
         iotlb += xlat;
     }
 
-    /* Make accesses to pages with watchpoints go via the
-       watchpoint trap routines.  */
-    QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
-        if (cpu_watchpoint_address_matches(wp, vaddr, TARGET_PAGE_SIZE)) {
-            /* Avoid trapping reads of pages with a write breakpoint. */
-            if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {
-                iotlb = PHYS_SECTION_WATCH + paddr;
-                *address |= TLB_MMIO;
-                break;
-            }
-        }
+    /* Avoid trapping reads of pages with a write breakpoint. */
+    match = (prot & PAGE_READ ? BP_MEM_READ : 0)
+          | (prot & PAGE_WRITE ? BP_MEM_WRITE : 0);
+    flags = cpu_watchpoint_address_matches(cpu, vaddr, TARGET_PAGE_SIZE);
+    if (flags & match) {
+        /*
+         * Make accesses to pages with watchpoints go via the
+         * watchpoint trap routines.
+         */
+        iotlb = PHYS_SECTION_WATCH + paddr;
+        *address |= TLB_MMIO;
     }
 
     return iotlb;
@@ -2806,7 +2819,7 @@  void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
 
     addr = cc->adjust_watchpoint_address(cpu, addr, len);
     QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
-        if (cpu_watchpoint_address_matches(wp, addr, len)
+        if (watchpoint_address_matches(wp, addr, len)
             && (wp->flags & flags)) {
             if (flags == BP_MEM_READ) {
                 wp->flags |= BP_WATCHPOINT_HIT_READ;