powerpc/watchpoint: Fix length calculation for unaligned target

Watchpoint match range is always doubleword(8 bytes) aligned on
powerpc. If the given range is crossing doubleword boundary, we need
to increase the length such that next doubleword also get
covered. Ex,

          address   len = 6 bytes
                |=========.
   |------------v--|------v--------|
   | | | | | | | | | | | | | | | | |
   |---------------|---------------|
    <---8 bytes--->

In such case, current code configures hw as:
  start_addr = address & ~HW_BREAKPOINT_ALIGN
  len = 8 bytes

And thus read/write in last 4 bytes of the given range is ignored.
Fix this by including next doubleword in the length.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20191017093204.7511-3-ravi.bangoria@linux.ibm.com
This commit is contained in:
Ravi Bangoria
2019-10-17 15:01:59 +05:30
committed by Michael Ellerman
parent b811be615c
commit b57aeab811
5 changed files with 56 additions and 23 deletions

View File

@@ -126,6 +126,49 @@ int arch_bp_generic_fields(int type, int *gen_bp_type)
return 0;
}
/*
* Watchpoint match range is always doubleword(8 bytes) aligned on
* powerpc. If the given range is crossing doubleword boundary, we
* need to increase the length such that next doubleword also get
* covered. Ex,
*
* address len = 6 bytes
* |=========.
* |------------v--|------v--------|
* | | | | | | | | | | | | | | | | |
* |---------------|---------------|
* <---8 bytes--->
*
* In this case, we should configure hw as:
* start_addr = address & ~HW_BREAKPOINT_ALIGN
* len = 16 bytes
*
* @start_addr and @end_addr are inclusive.
*/
static int hw_breakpoint_validate_len(struct arch_hw_breakpoint *hw)
{
u16 max_len = DABR_MAX_LEN;
u16 hw_len;
unsigned long start_addr, end_addr;
start_addr = hw->address & ~HW_BREAKPOINT_ALIGN;
end_addr = (hw->address + hw->len - 1) | HW_BREAKPOINT_ALIGN;
hw_len = end_addr - start_addr + 1;
if (dawr_enabled()) {
max_len = DAWR_MAX_LEN;
/* DAWR region can't cross 512 bytes boundary */
if ((start_addr >> 9) != (end_addr >> 9))
return -EINVAL;
}
if (hw_len > max_len)
return -EINVAL;
hw->hw_len = hw_len;
return 0;
}
/*
* Validate the arch-specific HW Breakpoint register settings
*/
@@ -133,9 +176,9 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
const struct perf_event_attr *attr,
struct arch_hw_breakpoint *hw)
{
int ret = -EINVAL, length_max;
int ret = -EINVAL;
if (!bp)
if (!bp || !attr->bp_len)
return ret;
hw->type = HW_BRK_TYPE_TRANSLATE;
@@ -155,26 +198,10 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
hw->address = attr->bp_addr;
hw->len = attr->bp_len;
/*
* Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8)
* and breakpoint addresses are aligned to nearest double-word
* HW_BREAKPOINT_ALIGN by rounding off to the lower address, the
* 'symbolsize' should satisfy the check below.
*/
if (!ppc_breakpoint_available())
return -ENODEV;
length_max = DABR_MAX_LEN; /* DABR */
if (dawr_enabled()) {
length_max = DAWR_MAX_LEN; /* 64 doublewords */
/* DAWR region can't cross 512 boundary */
if ((attr->bp_addr >> 9) !=
((attr->bp_addr + attr->bp_len - 1) >> 9))
return -EINVAL;
}
if (hw->len >
(length_max - (hw->address & HW_BREAKPOINT_ALIGN)))
return -EINVAL;
return 0;
return hw_breakpoint_validate_len(hw);
}
/*