Skip to content

Commit 39413ae

Browse files
chleroympe
authored andcommitted
powerpc/hw_breakpoints: Rewrite 8xx breakpoints to allow any address range size.
Unlike standard powerpc, Powerpc 8xx doesn't have SPRN_DABR, but it has a breakpoint support based on a set of comparators which allow more flexibility. Commit 4ad8622 ("powerpc/8xx: Implement hw_breakpoint") implemented breakpoints by emulating the DABR behaviour. It did this by setting one comparator the match 4 bytes at breakpoint address and the other comparator to match 4 bytes at breakpoint address + 4. Rewrite 8xx hw_breakpoint to make breakpoints match all addresses defined by the breakpoint address and length by making full use of comparators. Now, comparator E is set to match any address greater than breakpoint address minus one. Comparator F is set to match any address lower than breakpoint address plus breakpoint length. Addresses are aligned to 32 bits. When the breakpoint range starts at address 0, the breakpoint is set to match comparator F only. When the breakpoint range end at address 0xffffffff, the breakpoint is set to match comparator E only. Otherwise the breakpoint is set to match comparator E and F. At the same time, use registers bit names instead of hardcoded values. Signed-off-by: Christophe Leroy <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/05105deeaf63bc02151aea2cdeaf525534e0e9d4.1574790198.git.christophe.leroy@c-s.fr
1 parent 991d656 commit 39413ae

File tree

4 files changed

+61
-29
lines changed

4 files changed

+61
-29
lines changed

arch/powerpc/include/asm/hw_breakpoint.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ struct arch_hw_breakpoint {
3434
#define HW_BRK_TYPE_PRIV_ALL (HW_BRK_TYPE_USER | HW_BRK_TYPE_KERNEL | \
3535
HW_BRK_TYPE_HYP)
3636

37+
#ifdef CONFIG_PPC_8xx
38+
#define HW_BREAKPOINT_ALIGN 0x3
39+
#else
3740
#define HW_BREAKPOINT_ALIGN 0x7
41+
#endif
3842

3943
#define DABR_MAX_LEN 8
4044
#define DAWR_MAX_LEN 512

arch/powerpc/include/asm/reg_8xx.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,21 @@
3535
#define SPRN_CMPE 152
3636
#define SPRN_CMPF 153
3737
#define SPRN_LCTRL1 156
38+
#define LCTRL1_CTE_GT 0xc0000000
39+
#define LCTRL1_CTF_LT 0x14000000
40+
#define LCTRL1_CRWE_RW 0x00000000
41+
#define LCTRL1_CRWE_RO 0x00040000
42+
#define LCTRL1_CRWE_WO 0x000c0000
43+
#define LCTRL1_CRWF_RW 0x00000000
44+
#define LCTRL1_CRWF_RO 0x00010000
45+
#define LCTRL1_CRWF_WO 0x00030000
3846
#define SPRN_LCTRL2 157
47+
#define LCTRL2_LW0EN 0x80000000
48+
#define LCTRL2_LW0LA_E 0x00000000
49+
#define LCTRL2_LW0LA_F 0x04000000
50+
#define LCTRL2_LW0LA_EandF 0x08000000
51+
#define LCTRL2_LW0LADC 0x02000000
52+
#define LCTRL2_SLW0EN 0x00000002
3953
#ifdef CONFIG_PPC_8xx
4054
#define SPRN_ICTRL 158
4155
#endif

arch/powerpc/kernel/hw_breakpoint.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ static int hw_breakpoint_validate_len(struct arch_hw_breakpoint *hw)
160160
/* DAWR region can't cross 512 bytes boundary */
161161
if ((start_addr >> 9) != (end_addr >> 9))
162162
return -EINVAL;
163+
} else if (IS_ENABLED(CONFIG_PPC_8xx)) {
164+
/* 8xx can setup a range without limitation */
165+
max_len = U16_MAX;
163166
}
164167

165168
if (hw_len > max_len)
@@ -328,13 +331,11 @@ int hw_breakpoint_handler(struct die_args *args)
328331
}
329332

330333
info->type &= ~HW_BRK_TYPE_EXTRANEOUS_IRQ;
331-
if (IS_ENABLED(CONFIG_PPC_8xx)) {
332-
if (!dar_within_range(regs->dar, info))
333-
info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
334-
} else {
335-
if (!stepping_handler(regs, bp, info))
336-
goto out;
337-
}
334+
if (!dar_within_range(regs->dar, info))
335+
info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
336+
337+
if (!IS_ENABLED(CONFIG_PPC_8xx) && !stepping_handler(regs, bp, info))
338+
goto out;
338339

339340
/*
340341
* As a policy, the callback is invoked in a 'trigger-after-execute'

arch/powerpc/kernel/process.c

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -740,28 +740,6 @@ static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
740740
mtspr(SPRN_DABRX, dabrx);
741741
return 0;
742742
}
743-
#elif defined(CONFIG_PPC_8xx)
744-
static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
745-
{
746-
unsigned long addr = dabr & ~HW_BRK_TYPE_DABR;
747-
unsigned long lctrl1 = 0x90000000; /* compare type: equal on E & F */
748-
unsigned long lctrl2 = 0x8e000002; /* watchpoint 1 on cmp E | F */
749-
750-
if ((dabr & HW_BRK_TYPE_RDWR) == HW_BRK_TYPE_READ)
751-
lctrl1 |= 0xa0000;
752-
else if ((dabr & HW_BRK_TYPE_RDWR) == HW_BRK_TYPE_WRITE)
753-
lctrl1 |= 0xf0000;
754-
else if ((dabr & HW_BRK_TYPE_RDWR) == 0)
755-
lctrl2 = 0;
756-
757-
mtspr(SPRN_LCTRL2, 0);
758-
mtspr(SPRN_CMPE, addr);
759-
mtspr(SPRN_CMPF, addr + 4);
760-
mtspr(SPRN_LCTRL1, lctrl1);
761-
mtspr(SPRN_LCTRL2, lctrl2);
762-
763-
return 0;
764-
}
765743
#else
766744
static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
767745
{
@@ -782,13 +760,48 @@ static inline int set_dabr(struct arch_hw_breakpoint *brk)
782760
return __set_dabr(dabr, dabrx);
783761
}
784762

763+
static inline int set_breakpoint_8xx(struct arch_hw_breakpoint *brk)
764+
{
765+
unsigned long lctrl1 = LCTRL1_CTE_GT | LCTRL1_CTF_LT | LCTRL1_CRWE_RW |
766+
LCTRL1_CRWF_RW;
767+
unsigned long lctrl2 = LCTRL2_LW0EN | LCTRL2_LW0LADC | LCTRL2_SLW0EN;
768+
unsigned long start_addr = brk->address & ~HW_BREAKPOINT_ALIGN;
769+
unsigned long end_addr = (brk->address + brk->len - 1) | HW_BREAKPOINT_ALIGN;
770+
771+
if (start_addr == 0)
772+
lctrl2 |= LCTRL2_LW0LA_F;
773+
else if (end_addr == ~0U)
774+
lctrl2 |= LCTRL2_LW0LA_E;
775+
else
776+
lctrl2 |= LCTRL2_LW0LA_EandF;
777+
778+
mtspr(SPRN_LCTRL2, 0);
779+
780+
if ((brk->type & HW_BRK_TYPE_RDWR) == 0)
781+
return 0;
782+
783+
if ((brk->type & HW_BRK_TYPE_RDWR) == HW_BRK_TYPE_READ)
784+
lctrl1 |= LCTRL1_CRWE_RO | LCTRL1_CRWF_RO;
785+
if ((brk->type & HW_BRK_TYPE_RDWR) == HW_BRK_TYPE_WRITE)
786+
lctrl1 |= LCTRL1_CRWE_WO | LCTRL1_CRWF_WO;
787+
788+
mtspr(SPRN_CMPE, start_addr - 1);
789+
mtspr(SPRN_CMPF, end_addr + 1);
790+
mtspr(SPRN_LCTRL1, lctrl1);
791+
mtspr(SPRN_LCTRL2, lctrl2);
792+
793+
return 0;
794+
}
795+
785796
void __set_breakpoint(struct arch_hw_breakpoint *brk)
786797
{
787798
memcpy(this_cpu_ptr(&current_brk), brk, sizeof(*brk));
788799

789800
if (dawr_enabled())
790801
// Power8 or later
791802
set_dawr(brk);
803+
else if (IS_ENABLED(CONFIG_PPC_8xx))
804+
set_breakpoint_8xx(brk);
792805
else if (!cpu_has_feature(CPU_FTR_ARCH_207S))
793806
// Power7 or earlier
794807
set_dabr(brk);

0 commit comments

Comments
 (0)