LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v8 23/30] powerpc: Add prefixed instructions to instruction data type
From: Christophe Leroy @ 2020-05-14 12:57 UTC (permalink / raw)
  To: Alistair Popple
  Cc: christophe.leroy, Jordan Niethe, npiggin, bala24, naveen.n.rao,
	linuxppc-dev, dja
In-Reply-To: <1850220.JuIOMCfrUL@townsend>



Le 14/05/2020 à 14:06, Alistair Popple a écrit :
> On Thursday, 14 May 2020 4:11:43 PM AEST Christophe Leroy wrote:
>> @@ -249,7 +249,7 @@ int arch_prepare_optimized_kprobe(struct
>> optimized_kprobe *op, struct kprobe *p)
>>> * Fixup the template with instructions to:
>>> * 1. load the address of the actual probepoint
>>> */
>>> -       patch_imm64_load_insns((unsigned long)op, buff + TMPL_OP_IDX);
>>> +       patch_imm64_load_insns((unsigned long)op, 3, buff + TMPL_OP_IDX);
>>>
>>> /*
>>> * 2. branch to optimized_callback() and emulate_step()
>>> @@ -282,7 +282,11 @@ int arch_prepare_optimized_kprobe(struct
>>> optimized_kprobe *op, struct kprobe *p) /*
>>> * 3. load instruction to be emulated into relevant register, and
>>> */
>>> -       patch_imm32_load_insns(*p->ainsn.insn, buff + TMPL_INSN_IDX);
>>> +       temp = ppc_inst_read((struct ppc_inst *)p->ainsn.insn);
>>> +       patch_imm64_load_insns(ppc_inst_val(temp) |
>>> +                              ((u64)ppc_inst_suffix(temp) << 32),
>>> +                              4,
>>
>> So now we are also using r4 ? Any explanation somewhere on the way it
>> works ? This change seems unrelated to this patch, nothing in the
>> description about it. Can we suddenly use a new register without problem ?
> 
> Unless I missed something there is no change in register usage here that I
> could see. patch_imm32_load_insns() was/is hardcoded to use register r4.
> 

Ah ... Euh ... Ok I missed the change from patch_imm32_load_insns() to 
patch_imm64_load_insns(), I'll check again.

^ permalink raw reply

* Re: [PATCH v8 23/30] powerpc: Add prefixed instructions to instruction data type
From: Jordan Niethe @ 2020-05-14 12:29 UTC (permalink / raw)
  To: Alistair Popple
  Cc: Christophe Leroy, Nicholas Piggin, Balamuruhan S, naveen.n.rao,
	linuxppc-dev, Daniel Axtens
In-Reply-To: <1850220.JuIOMCfrUL@townsend>

On Thu, May 14, 2020 at 10:06 PM Alistair Popple <alistair@popple.id.au> wrote:
>
> On Thursday, 14 May 2020 4:11:43 PM AEST Christophe Leroy wrote:
> > @@ -249,7 +249,7 @@ int arch_prepare_optimized_kprobe(struct
> > optimized_kprobe *op, struct kprobe *p)
> > > * Fixup the template with instructions to:
> > > * 1. load the address of the actual probepoint
> > > */
> > > -       patch_imm64_load_insns((unsigned long)op, buff + TMPL_OP_IDX);
> > > +       patch_imm64_load_insns((unsigned long)op, 3, buff + TMPL_OP_IDX);
> > >
> > > /*
> > > * 2. branch to optimized_callback() and emulate_step()
> > > @@ -282,7 +282,11 @@ int arch_prepare_optimized_kprobe(struct
> > > optimized_kprobe *op, struct kprobe *p) /*
> > > * 3. load instruction to be emulated into relevant register, and
> > > */
> > > -       patch_imm32_load_insns(*p->ainsn.insn, buff + TMPL_INSN_IDX);
> > > +       temp = ppc_inst_read((struct ppc_inst *)p->ainsn.insn);
> > > +       patch_imm64_load_insns(ppc_inst_val(temp) |
> > > +                              ((u64)ppc_inst_suffix(temp) << 32),
> > > +                              4,
> >
> > So now we are also using r4 ? Any explanation somewhere on the way it
> > works ? This change seems unrelated to this patch, nothing in the
> > description about it. Can we suddenly use a new register without problem ?
>
> Unless I missed something there is no change in register usage here that I
> could see. patch_imm32_load_insns() was/is hardcoded to use register r4.
Yes, that is right.
>
> - Alistair
>
>

^ permalink raw reply

* Re: [PATCH v8 23/30] powerpc: Add prefixed instructions to instruction data type
From: Jordan Niethe @ 2020-05-14 12:28 UTC (permalink / raw)
  To: Christophe Leroy
  Cc: Christophe Leroy, Alistair Popple, Nicholas Piggin, Balamuruhan S,
	naveen.n.rao, linuxppc-dev, Daniel Axtens
In-Reply-To: <56ca6bcb-c719-a049-63b0-aae73023bde5@csgroup.eu>

On Thu, May 14, 2020 at 4:12 PM Christophe Leroy
<christophe.leroy@csgroup.eu> wrote:
>
>
>
> Le 06/05/2020 à 05:40, Jordan Niethe a écrit :
> > For powerpc64, redefine the ppc_inst type so both word and prefixed
> > instructions can be represented. On powerpc32 the type will remain the
> > same.  Update places which had assumed instructions to be 4 bytes long.
> >
> > Reviewed-by: Alistair Popple <alistair@popple.id.au>
> > Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
> > ---
> > v4: New to series
> > v5:  - Distinguish normal instructions from prefixed instructions with a
> >         0xff marker for the suffix.
> >       - __patch_instruction() using std for prefixed instructions
> > v6:  - Return false instead of 0 in ppc_inst_prefixed()
> >       - Fix up types for ppc32 so it compiles
> >       - remove ppc_inst_write()
> >       - __patching_instruction(): move flush out of condition
> > v8:  - style
> >       - Define and use OP_PREFIX instead of '1' (back from v3)
> >       - __patch_instruction() fix for big endian
> > ---
> >   arch/powerpc/include/asm/inst.h       | 69 ++++++++++++++++++++++++---
> >   arch/powerpc/include/asm/kprobes.h    |  2 +-
> >   arch/powerpc/include/asm/ppc-opcode.h |  3 ++
> >   arch/powerpc/include/asm/uaccess.h    | 40 +++++++++++++++-
> >   arch/powerpc/include/asm/uprobes.h    |  2 +-
> >   arch/powerpc/kernel/crash_dump.c      |  2 +-
> >   arch/powerpc/kernel/optprobes.c       | 42 ++++++++--------
> >   arch/powerpc/kernel/optprobes_head.S  |  3 ++
> >   arch/powerpc/lib/code-patching.c      | 19 ++++++--
> >   arch/powerpc/lib/feature-fixups.c     |  5 +-
> >   arch/powerpc/lib/inst.c               | 41 ++++++++++++++++
> >   arch/powerpc/lib/sstep.c              |  4 +-
> >   arch/powerpc/xmon/xmon.c              |  4 +-
> >   arch/powerpc/xmon/xmon_bpts.S         |  2 +
> >   14 files changed, 200 insertions(+), 38 deletions(-)
> >
> > diff --git a/arch/powerpc/include/asm/inst.h b/arch/powerpc/include/asm/inst.h
> > index 2f3c9d5bcf7c..7868b80b610e 100644
> > --- a/arch/powerpc/include/asm/inst.h
> > +++ b/arch/powerpc/include/asm/inst.h
> > @@ -2,29 +2,79 @@
> >   #ifndef _ASM_INST_H
> >   #define _ASM_INST_H
> >
> > +#include <asm/ppc-opcode.h>
> >   /*
> >    * Instruction data type for POWER
> >    */
> >
> >   struct ppc_inst {
> >       u32 val;
> > +#ifdef __powerpc64__
>
> CONFIG_PPC64 should be used instead. This is also reported by checkpatch.
Sure will use that instead.
>
> > +     u32 suffix;
> > +#endif /* __powerpc64__ */
> >   } __packed;
> >
> > -#define ppc_inst(x) ((struct ppc_inst){ .val = x })
> > -
> >   static inline u32 ppc_inst_val(struct ppc_inst x)
> >   {
> >       return x.val;
> >   }
> >
> > -static inline int ppc_inst_len(struct ppc_inst x)
> > +static inline int ppc_inst_primary_opcode(struct ppc_inst x)
> >   {
> > -     return sizeof(struct ppc_inst);
> > +     return ppc_inst_val(x) >> 26;
>
> What about using get_op() from asm/disassemble.h instead of hardcodiing ?
Okay will use it here and the other places you point out.
>
> >   }
> >
> > -static inline int ppc_inst_primary_opcode(struct ppc_inst x)
> > +#ifdef __powerpc64__
>
> Use CONFIG_PPC64
>
> > +#define ppc_inst(x) ((struct ppc_inst){ .val = (x), .suffix = 0xff })
> > +
> > +#define ppc_inst_prefix(x, y) ((struct ppc_inst){ .val = (x), .suffix = (y) })
> > +
> > +static inline u32 ppc_inst_suffix(struct ppc_inst x)
> >   {
> > -     return ppc_inst_val(x) >> 26;
> > +     return x.suffix;
> > +}
> > +
> > +static inline bool ppc_inst_prefixed(struct ppc_inst x)
> > +{
> > +     return (ppc_inst_primary_opcode(x) == 1) && ppc_inst_suffix(x) != 0xff;
> > +}
> > +
> > +static inline struct ppc_inst ppc_inst_swab(struct ppc_inst x)
> > +{
> > +     return ppc_inst_prefix(swab32(ppc_inst_val(x)),
> > +                            swab32(ppc_inst_suffix(x)));
> > +}
> > +
> > +static inline struct ppc_inst ppc_inst_read(const struct ppc_inst *ptr)
> > +{
> > +     u32 val, suffix;
> > +
> > +     val = *(u32 *)ptr;
> > +     if ((val >> 26) == 1) {
>
> Don't hardcode, use ppc_inst_primary_opcode() and compare it to OP_PREFIX
> Or use get_op() from asm/disassemble.h
>
>
> > +             suffix = *((u32 *)ptr + 1);
> > +             return ppc_inst_prefix(val, suffix);
> > +     } else {
> > +             return ppc_inst(val);
> > +     }
> > +}
> > +
> > +static inline bool ppc_inst_equal(struct ppc_inst x, struct ppc_inst y)
> > +{
> > +     return *(u64 *)&x == *(u64 *)&y;
> > +}
> > +
> > +#else
> > +
> > +#define ppc_inst(x) ((struct ppc_inst){ .val = x })
> > +
> > +static inline bool ppc_inst_prefixed(struct ppc_inst x)
> > +{
> > +     return false;
> > +}
> > +
> > +static inline u32 ppc_inst_suffix(struct ppc_inst x)
> > +{
> > +     return 0;
> >   }
> >
> >   static inline struct ppc_inst ppc_inst_swab(struct ppc_inst x)
> > @@ -42,6 +92,13 @@ static inline bool ppc_inst_equal(struct ppc_inst x, struct ppc_inst y)
> >       return ppc_inst_val(x) == ppc_inst_val(y);
> >   }
> >
> > +#endif /* __powerpc64__ */
> > +
> > +static inline int ppc_inst_len(struct ppc_inst x)
> > +{
> > +     return (ppc_inst_prefixed(x)) ? 8  : 4;
> > +}
> > +
> >   int probe_user_read_inst(struct ppc_inst *inst,
> >                        struct ppc_inst *nip);
> >   int probe_kernel_read_inst(struct ppc_inst *inst,
> > diff --git a/arch/powerpc/include/asm/kprobes.h b/arch/powerpc/include/asm/kprobes.h
> > index 66b3f2983b22..4fc0e15e23a5 100644
> > --- a/arch/powerpc/include/asm/kprobes.h
> > +++ b/arch/powerpc/include/asm/kprobes.h
> > @@ -43,7 +43,7 @@ extern kprobe_opcode_t optprobe_template_ret[];
> >   extern kprobe_opcode_t optprobe_template_end[];
> >
> >   /* Fixed instruction size for powerpc */
> > -#define MAX_INSN_SIZE                1
> > +#define MAX_INSN_SIZE                2
> >   #define MAX_OPTIMIZED_LENGTH        sizeof(kprobe_opcode_t) /* 4 bytes */
> >   #define MAX_OPTINSN_SIZE    (optprobe_template_end - optprobe_template_entry)
> >   #define RELATIVEJUMP_SIZE   sizeof(kprobe_opcode_t) /* 4 bytes */
> > diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
> > index c1df75edde44..2a39c716c343 100644
> > --- a/arch/powerpc/include/asm/ppc-opcode.h
> > +++ b/arch/powerpc/include/asm/ppc-opcode.h
> > @@ -158,6 +158,9 @@
> >   /* VMX Vector Store Instructions */
> >   #define OP_31_XOP_STVX          231
> >
> > +/* Prefixed Instructions */
> > +#define OP_PREFIX            1
> > +
> >   #define OP_31   31
> >   #define OP_LWZ  32
> >   #define OP_STFS 52
> > diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
> > index c0a35e4586a5..217897927926 100644
> > --- a/arch/powerpc/include/asm/uaccess.h
> > +++ b/arch/powerpc/include/asm/uaccess.h
> > @@ -105,11 +105,49 @@ static inline int __access_ok(unsigned long addr, unsigned long size,
> >   #define __put_user_inatomic(x, ptr) \
> >       __put_user_nosleep((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
> >
> > +#ifdef __powerpc64__
>
> Replace by CONFIG_PPC64
>
> > +#define __get_user_instr(x, ptr)                     \
> > +({                                                   \
> > +     long __gui_ret = 0;                             \
> > +     unsigned long __gui_ptr = (unsigned long)ptr;   \
> > +     struct ppc_inst __gui_inst;                     \
> > +     unsigned int prefix, suffix;                    \
> > +     __gui_ret = __get_user(prefix, (unsigned int __user *)__gui_ptr);       \
>
> __get_user() can be costly especially with KUAP. I think you should
> perform a 64 bits read and fallback on a 32 bits read only if the 64
> bits read failed.
Thanks, I will try doing it that way.
>
> > +     if (!__gui_ret && (prefix >> 26) == OP_PREFIX) {        \
>
> What about using get_op() from asm/disassemble.h instead of hardcodiing ?
>
> > +             __gui_ret = __get_user(suffix,          \
> > +                                    (unsigned int __user *)__gui_ptr + 1);   \
> > +             __gui_inst = ppc_inst_prefix(prefix, suffix);   \
> > +     } else {                                        \
> > +             __gui_inst = ppc_inst(prefix);          \
> > +     }                                               \
> > +     (x) = __gui_inst;                               \
> > +     __gui_ret;                                      \
> > +})
> > +
> > +#define __get_user_instr_inatomic(x, ptr)            \
> > +({                                                   \
> > +     long __gui_ret = 0;                             \
> > +     unsigned long __gui_ptr = (unsigned long)ptr;   \
> > +     struct ppc_inst __gui_inst;                     \
> > +     unsigned int prefix, suffix;                    \
> > +     __gui_ret = __get_user_inatomic(prefix, (unsigned int __user *)__gui_ptr);      \
>
> Same
>
> > +     if (!__gui_ret && (prefix >> 26) == OP_PREFIX) {        \
> > +             __gui_ret = __get_user_inatomic(suffix, \
> > +                                             (unsigned int __user *)__gui_ptr + 1);  \
> > +             __gui_inst = ppc_inst_prefix(prefix, suffix);   \
> > +     } else {                                        \
> > +             __gui_inst = ppc_inst(prefix);          \
> > +     }                                               \
> > +     (x) = __gui_inst;                               \
> > +     __gui_ret;                                      \
> > +})
> > +#else
> >   #define __get_user_instr(x, ptr) \
> >       __get_user_nocheck((x).val, (u32 *)(ptr), sizeof(u32), true)
> > -
> >   #define __get_user_instr_inatomic(x, ptr) \
> >       __get_user_nosleep((x).val, (u32 *)(ptr), sizeof(u32))
> > +#endif
> > +
> >   extern long __put_user_bad(void);
> >
> >   /*
> > diff --git a/arch/powerpc/include/asm/uprobes.h b/arch/powerpc/include/asm/uprobes.h
> > index 7e3b329ba2d3..5bf65f5d44a9 100644
> > --- a/arch/powerpc/include/asm/uprobes.h
> > +++ b/arch/powerpc/include/asm/uprobes.h
> > @@ -15,7 +15,7 @@
> >
> >   typedef ppc_opcode_t uprobe_opcode_t;
> >
> > -#define MAX_UINSN_BYTES              4
> > +#define MAX_UINSN_BYTES              8
> >   #define UPROBE_XOL_SLOT_BYTES       (MAX_UINSN_BYTES)
> >
> >   /* The following alias is needed for reference from arch-agnostic code */
> > diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
> > index 72bafb47e757..735e89337398 100644
> > --- a/arch/powerpc/kernel/crash_dump.c
> > +++ b/arch/powerpc/kernel/crash_dump.c
> > @@ -46,7 +46,7 @@ static void __init create_trampoline(unsigned long addr)
> >        * two instructions it doesn't require any registers.
> >        */
> >       patch_instruction(p, ppc_inst(PPC_INST_NOP));
> > -     patch_branch(++p, addr + PHYSICAL_START, 0);
> > +     patch_branch((void *)p + 4, addr + PHYSICAL_START, 0);
> >   }
> >
> >   void __init setup_kdump_trampoline(void)
> > diff --git a/arch/powerpc/kernel/optprobes.c b/arch/powerpc/kernel/optprobes.c
> > index 52c1ab3f85aa..a8e66603d12b 100644
> > --- a/arch/powerpc/kernel/optprobes.c
> > +++ b/arch/powerpc/kernel/optprobes.c
> > @@ -162,43 +162,43 @@ void patch_imm32_load_insns(unsigned int val, kprobe_opcode_t *addr)
> >
> >   /*
> >    * Generate instructions to load provided immediate 64-bit value
> > - * to register 'r3' and patch these instructions at 'addr'.
> > + * to register 'reg' and patch these instructions at 'addr'.
> >    */
> > -void patch_imm64_load_insns(unsigned long val, kprobe_opcode_t *addr)
> > +void patch_imm64_load_insns(unsigned long val, int reg, kprobe_opcode_t *addr)
>
> I think this change should go in a separate patch.
Okay.
>
> >   {
> > -     /* lis r3,(op)@highest */
> > +     /* lis reg,(op)@highest */
> >       patch_instruction((struct ppc_inst *)addr,
> > -                       ppc_inst(PPC_INST_ADDIS | ___PPC_RT(3) |
> > +                       ppc_inst(PPC_INST_ADDIS | ___PPC_RT(reg) |
> >                                  ((val >> 48) & 0xffff)));
> >       addr++;
> >
> > -     /* ori r3,r3,(op)@higher */
> > +     /* ori reg,reg,(op)@higher */
> >       patch_instruction((struct ppc_inst *)addr,
> > -                       ppc_inst(PPC_INST_ORI | ___PPC_RA(3) |
> > -                                ___PPC_RS(3) | ((val >> 32) & 0xffff)));
> > +                       ppc_inst(PPC_INST_ORI | ___PPC_RA(reg) |
> > +                                ___PPC_RS(reg) | ((val >> 32) & 0xffff)));
> >       addr++;
> >
> > -     /* rldicr r3,r3,32,31 */
> > +     /* rldicr reg,reg,32,31 */
> >       patch_instruction((struct ppc_inst *)addr,
> > -                       ppc_inst(PPC_INST_RLDICR | ___PPC_RA(3) |
> > -                                ___PPC_RS(3) | __PPC_SH64(32) | __PPC_ME64(31)));
> > +                       ppc_inst(PPC_INST_RLDICR | ___PPC_RA(reg) |
> > +                                ___PPC_RS(reg) | __PPC_SH64(32) | __PPC_ME64(31)));
> >       addr++;
> >
> > -     /* oris r3,r3,(op)@h */
> > +     /* oris reg,reg,(op)@h */
> >       patch_instruction((struct ppc_inst *)addr,
> > -                       ppc_inst(PPC_INST_ORIS | ___PPC_RA(3) |
> > -                                ___PPC_RS(3) | ((val >> 16) & 0xffff)));
> > +                       ppc_inst(PPC_INST_ORIS | ___PPC_RA(reg) |
> > +                                ___PPC_RS(reg) | ((val >> 16) & 0xffff)));
> >       addr++;
> >
> > -     /* ori r3,r3,(op)@l */
> > +     /* ori reg,reg,(op)@l */
> >       patch_instruction((struct ppc_inst *)addr,
> > -                       ppc_inst(PPC_INST_ORI | ___PPC_RA(3) |
> > -                                ___PPC_RS(3) | (val & 0xffff)));
> > +                       ppc_inst(PPC_INST_ORI | ___PPC_RA(reg) |
> > +                                ___PPC_RS(reg) | (val & 0xffff)));
> >   }
> >
> >   int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *p)
> >   {
> > -     struct ppc_inst branch_op_callback, branch_emulate_step;
> > +     struct ppc_inst branch_op_callback, branch_emulate_step, temp;
> >       kprobe_opcode_t *op_callback_addr, *emulate_step_addr, *buff;
> >       long b_offset;
> >       unsigned long nip, size;
> > @@ -249,7 +249,7 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *p)
> >        * Fixup the template with instructions to:
> >        * 1. load the address of the actual probepoint
> >        */
> > -     patch_imm64_load_insns((unsigned long)op, buff + TMPL_OP_IDX);
> > +     patch_imm64_load_insns((unsigned long)op, 3, buff + TMPL_OP_IDX);
> >
> >       /*
> >        * 2. branch to optimized_callback() and emulate_step()
> > @@ -282,7 +282,11 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *p)
> >       /*
> >        * 3. load instruction to be emulated into relevant register, and
> >        */
> > -     patch_imm32_load_insns(*p->ainsn.insn, buff + TMPL_INSN_IDX);
> > +     temp = ppc_inst_read((struct ppc_inst *)p->ainsn.insn);
> > +     patch_imm64_load_insns(ppc_inst_val(temp) |
> > +                            ((u64)ppc_inst_suffix(temp) << 32),
> > +                            4,
>
> So now we are also using r4 ? Any explanation somewhere on the way it
> works ? This change seems unrelated to this patch, nothing in the
> description about it. Can we suddenly use a new register without problem ?
Sorry it is not very clear, r4 was always being used.
patch_imm32_load_insns() hardcoded r4. We now need to load 64 bits as
we just introduced prefixed instruction, so are using
patch_imm64_load_insns(). That is the connection to the patch. But a
separate patch and description would probably make that clearer.

>
> > +                            buff + TMPL_INSN_IDX);
>
> What's the point with splitting this line in 4 lines ? Can't it fit in 2
> lines ?
Sure.
>
> >
> >       /*
> >        * 4. branch back from trampoline
> > diff --git a/arch/powerpc/kernel/optprobes_head.S b/arch/powerpc/kernel/optprobes_head.S
> > index cf383520843f..ff8ba4d3824d 100644
> > --- a/arch/powerpc/kernel/optprobes_head.S
> > +++ b/arch/powerpc/kernel/optprobes_head.S
> > @@ -94,6 +94,9 @@ optprobe_template_insn:
> >       /* 2, Pass instruction to be emulated in r4 */
> >       nop
> >       nop
> > +     nop
> > +     nop
> > +     nop
> >
> >       .global optprobe_template_call_emulate
> >   optprobe_template_call_emulate:
> > diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c
> > index d946f7d6bb32..58b67b62d5d3 100644
> > --- a/arch/powerpc/lib/code-patching.c
> > +++ b/arch/powerpc/lib/code-patching.c
> > @@ -24,13 +24,24 @@ static int __patch_instruction(struct ppc_inst *exec_addr, struct ppc_inst instr
> >   {
> >       int err = 0;
> >
> > -     __put_user_asm(ppc_inst_val(instr), patch_addr, err, "stw");
> > -     if (err)
> > -             return err;
> > +     if (!ppc_inst_prefixed(instr)) {
> > +             __put_user_asm(ppc_inst_val(instr), patch_addr, err, "stw");
> > +             if (err)
> > +                     return err;
>
> This test should remain outside of the if/else, it doesn't need to be
> duplicated.
Okay.
>
> > +     } else {
> > +#ifdef CONFIG_CPU_LITTLE_ENDIAN
> > +             __put_user_asm((u64)ppc_inst_suffix(instr) << 32 |
> > +                            ppc_inst_val(instr), patch_addr, err, "std");
> > +#else
> > +             __put_user_asm((u64)ppc_inst_val(instr) << 32 |
> > +                            ppc_inst_suffix(instr), patch_addr, err, "std");
> > +#endif /* CONFIG_CPU_LITTLE_ENDIAN */
> > +             if (err)
> > +                     return err;
> > +     }
> >
> >       asm ("dcbst 0, %0; sync; icbi 0,%1; sync; isync" :: "r" (patch_addr),
> >                                                           "r" (exec_addr));
> > -
>
> Why remove the blank line ?
Sorry that was by mistake.
>
> >       return 0;
> >   }
> >
> > diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
> > index 2bd2b752de4f..a8238eff3a31 100644
> > --- a/arch/powerpc/lib/feature-fixups.c
> > +++ b/arch/powerpc/lib/feature-fixups.c
> > @@ -84,12 +84,13 @@ static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
> >       src = alt_start;
> >       dest = start;
> >
> > -     for (; src < alt_end; src++, dest++) {
> > +     for (; src < alt_end; src = (void *)src + ppc_inst_len(ppc_inst_read(src)),
> > +          (dest = (void *)dest + ppc_inst_len(ppc_inst_read(dest)))) {
>
> Can we do this outside the for() for readability ?
You are right, I will make it clearer.
>
> >               if (patch_alt_instruction(src, dest, alt_start, alt_end))
> >                       return 1;
> >       }
> >
> > -     for (; dest < end; dest++)
> > +     for (; dest < end; dest = (void *)dest + ppc_inst_len(ppc_inst(PPC_INST_NOP)))
> >               raw_patch_instruction(dest, ppc_inst(PPC_INST_NOP));
> >
> >       return 0;
> > diff --git a/arch/powerpc/lib/inst.c b/arch/powerpc/lib/inst.c
> > index 08dedd927268..eb6f9ee28ac6 100644
> > --- a/arch/powerpc/lib/inst.c
> > +++ b/arch/powerpc/lib/inst.c
> > @@ -3,9 +3,49 @@
> >    *  Copyright 2020, IBM Corporation.
> >    */
> >
> > +#include <asm/ppc-opcode.h>
> >   #include <linux/uaccess.h>
> >   #include <asm/inst.h>
> >
> > +#ifdef __powerpc64__
> > +int probe_user_read_inst(struct ppc_inst *inst,
> > +                      struct ppc_inst *nip)
> > +{
> > +     unsigned int val, suffix;
> > +     int err;
> > +
> > +     err = probe_user_read(&val, nip, sizeof(val));
>
> A user read is costly with KUAP. Can we do a 64 bits read and perform a
> 32 bits read only when 64 bits read fails ?
>
> > +     if (err)
> > +             return err;
> > +     if ((val >> 26) == OP_PREFIX) {
>
> What about using get_op() from asm/disassemble.h instead of hardcodiing ?
>
> > +             err = probe_user_read(&suffix, (void *)nip + 4,
>
> 4 or sizeof(unsigned int) ? Why use both in the same line ?
True, doesn't really make sense.
>
> > +                                   sizeof(unsigned int));
> > +             *inst = ppc_inst_prefix(val, suffix);
> > +     } else {
> > +             *inst = ppc_inst(val);
> > +     }
> > +     return err;
> > +}
> > +
> > +int probe_kernel_read_inst(struct ppc_inst *inst,
> > +                        struct ppc_inst *src)
> > +{
> > +     unsigned int val, suffix;
> > +     int err;
> > +
> > +     err = probe_kernel_read(&val, src, sizeof(val));
> > +     if (err)
> > +             return err;
> > +     if ((val >> 26) == OP_PREFIX) {
> > +             err = probe_kernel_read(&suffix, (void *)src + 4,
> > +                                     sizeof(unsigned int));
> > +             *inst = ppc_inst_prefix(val, suffix);
> > +     } else {
> > +             *inst = ppc_inst(val);
> > +     }
> > +     return err;
> > +}
> > +#else
> >   int probe_user_read_inst(struct ppc_inst *inst,
> >                        struct ppc_inst *nip)
> >   {
> > @@ -27,3 +67,4 @@ int probe_kernel_read_inst(struct ppc_inst *inst,
> >       *inst = ppc_inst(val);
> >       return err;
> >   }
> > +#endif /* __powerpc64__ */
> > diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
> > index 95a56bb1ba3f..ecd756c346fd 100644
> > --- a/arch/powerpc/lib/sstep.c
> > +++ b/arch/powerpc/lib/sstep.c
> > @@ -1169,10 +1169,12 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
> >       unsigned long int imm;
> >       unsigned long int val, val2;
> >       unsigned int mb, me, sh;
> > -     unsigned int word;
> > +     unsigned int word, suffix;
> >       long ival;
> >
> >       word = ppc_inst_val(instr);
> > +     suffix = ppc_inst_suffix(instr);
> > +
> >       op->type = COMPUTE;
> >
> >       opcode = ppc_inst_primary_opcode(instr);
> > diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
> > index 4d6980d51456..647b3829c4eb 100644
> > --- a/arch/powerpc/xmon/xmon.c
> > +++ b/arch/powerpc/xmon/xmon.c
> > @@ -758,8 +758,8 @@ static int xmon_bpt(struct pt_regs *regs)
> >
> >       /* Are we at the trap at bp->instr[1] for some bp? */
> >       bp = in_breakpoint_table(regs->nip, &offset);
> > -     if (bp != NULL && offset == 4) {
> > -             regs->nip = bp->address + 4;
> > +     if (bp != NULL && (offset == 4 || offset == 8)) {
> > +             regs->nip = bp->address + offset;
> >               atomic_dec(&bp->ref_count);
> >               return 1;
> >       }
> > diff --git a/arch/powerpc/xmon/xmon_bpts.S b/arch/powerpc/xmon/xmon_bpts.S
> > index f3ad0ab50854..69726814cd27 100644
> > --- a/arch/powerpc/xmon/xmon_bpts.S
> > +++ b/arch/powerpc/xmon/xmon_bpts.S
> > @@ -4,6 +4,8 @@
> >   #include <asm/asm-offsets.h>
> >   #include "xmon_bpts.h"
> >
> > +/* Prefixed instructions can not cross 64 byte boundaries */
> > +.align 6
> >   .global bpt_table
> >   bpt_table:
> >       .space NBPTS * BPT_SIZE
> >
>
> Christophe

^ permalink raw reply

* Re: [PATCH v8 29/30] powerpc sstep: Add support for prefixed load/stores
From: Alistair Popple @ 2020-05-14 12:19 UTC (permalink / raw)
  To: Christophe Leroy
  Cc: Jordan Niethe, npiggin, bala24, naveen.n.rao, linuxppc-dev, dja
In-Reply-To: <5a82008c-a5fa-0292-94fa-eb6fb0d41c42@csgroup.eu>

On Thursday, 14 May 2020 4:15:06 PM AEST Christophe Leroy wrote:
> Shouldn't this patch go before patch 23 ?

Perhaps I am missing something, but it seems reasonable enough to me that you 
would introduce the machinery for dealing with prefix instructions prior to 
defining them. What would be the advantage of doing things the other way 
around?

- Alistair

> Christophe
> 
> Le 06/05/2020 à 05:40, Jordan Niethe a écrit :
> > This adds emulation support for the following prefixed integer
> > 
> > load/stores:
> >    * Prefixed Load Byte and Zero (plbz)
> >    * Prefixed Load Halfword and Zero (plhz)
> >    * Prefixed Load Halfword Algebraic (plha)
> >    * Prefixed Load Word and Zero (plwz)
> >    * Prefixed Load Word Algebraic (plwa)
> >    * Prefixed Load Doubleword (pld)
> >    * Prefixed Store Byte (pstb)
> >    * Prefixed Store Halfword (psth)
> >    * Prefixed Store Word (pstw)
> >    * Prefixed Store Doubleword (pstd)
> >    * Prefixed Load Quadword (plq)
> >    * Prefixed Store Quadword (pstq)
> > 
> > the follow prefixed floating-point load/stores:
> >    * Prefixed Load Floating-Point Single (plfs)
> >    * Prefixed Load Floating-Point Double (plfd)
> >    * Prefixed Store Floating-Point Single (pstfs)
> >    * Prefixed Store Floating-Point Double (pstfd)
> > 
> > and for the following prefixed VSX load/stores:
> >    * Prefixed Load VSX Scalar Doubleword (plxsd)
> >    * Prefixed Load VSX Scalar Single-Precision (plxssp)
> >    * Prefixed Load VSX Vector [0|1]  (plxv, plxv0, plxv1)
> >    * Prefixed Store VSX Scalar Doubleword (pstxsd)
> >    * Prefixed Store VSX Scalar Single-Precision (pstxssp)
> >    * Prefixed Store VSX Vector [0|1] (pstxv, pstxv0, pstxv1)
> > 
> > Reviewed-by: Balamuruhan S <bala24@linux.ibm.com>
> > Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
> > ---
> > v2: - Combine all load/store patches
> > 
> >      - Fix the name of Type 01 instructions
> >      - Remove sign extension flag from pstd/pld
> >      - Rename sufx -> suffix
> > 
> > v3: - Move prefixed loads and stores into the switch statement
> > v6: - Compile on ppc32
> > 
> >      - Add back in + GETLENGTH(op->type)
> > 
> > v8: Use fallthrough; keyword
> > ---
> > 
> >   arch/powerpc/include/asm/sstep.h |   4 +
> >   arch/powerpc/lib/sstep.c         | 163 ++++++++++++++++++++++++++++++-
> >   2 files changed, 165 insertions(+), 2 deletions(-)
> > 
> > diff --git a/arch/powerpc/include/asm/sstep.h
> > b/arch/powerpc/include/asm/sstep.h index c3ce903ac488..9b200a5f8794
> > 100644
> > --- a/arch/powerpc/include/asm/sstep.h
> > +++ b/arch/powerpc/include/asm/sstep.h
> > @@ -90,11 +90,15 @@ enum instruction_type {
> > 
> >   #define VSX_LDLEFT	4	/* load VSX register from left */
> >   #define VSX_CHECK_VEC	8	/* check MSR_VEC not MSR_VSX for reg >= 32 */
> > 
> > +/* Prefixed flag, ORed in with type */
> > +#define PREFIXED       0x800
> > +
> > 
> >   /* Size field in type word */
> >   #define SIZE(n)		((n) << 12)
> >   #define GETSIZE(w)	((w) >> 12)
> >   
> >   #define GETTYPE(t)	((t) & INSTR_TYPE_MASK)
> > 
> > +#define GETLENGTH(t)   (((t) & PREFIXED) ? 8 : 4)
> > 
> >   #define MKOP(t, f, s)	((t) | (f) | SIZE(s))
> > 
> > diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
> > index ecd756c346fd..6794a7672ad5 100644
> > --- a/arch/powerpc/lib/sstep.c
> > +++ b/arch/powerpc/lib/sstep.c
> > @@ -187,6 +187,44 @@ static nokprobe_inline unsigned long
> > xform_ea(unsigned int instr,> 
> >   	return ea;
> >   
> >   }
> > 
> > +/*
> > + * Calculate effective address for a MLS:D-form / 8LS:D-form
> > + * prefixed instruction
> > + */
> > +static nokprobe_inline unsigned long mlsd_8lsd_ea(unsigned int instr,
> > +						  unsigned int suffix,
> > +						  const struct pt_regs *regs)
> > +{
> > +	int ra, prefix_r;
> > +	unsigned int  dd;
> > +	unsigned long ea, d0, d1, d;
> > +
> > +	prefix_r = instr & (1ul << 20);
> > +	ra = (suffix >> 16) & 0x1f;
> > +
> > +	d0 = instr & 0x3ffff;
> > +	d1 = suffix & 0xffff;
> > +	d = (d0 << 16) | d1;
> > +
> > +	/*
> > +	 * sign extend a 34 bit number
> > +	 */
> > +	dd = (unsigned int)(d >> 2);
> > +	ea = (signed int)dd;
> > +	ea = (ea << 2) | (d & 0x3);
> > +
> > +	if (!prefix_r && ra)
> > +		ea += regs->gpr[ra];
> > +	else if (!prefix_r && !ra)
> > +		; /* Leave ea as is */
> > +	else if (prefix_r && !ra)
> > +		ea += regs->nip;
> > +	else if (prefix_r && ra)
> > +		; /* Invalid form. Should already be checked for by caller! */
> > +
> > +	return ea;
> > +}
> > +
> > 
> >   /*
> >   
> >    * Return the largest power of 2, not greater than sizeof(unsigned
> >    long),
> >    * such that x is a multiple of it.
> > 
> > @@ -1166,6 +1204,9 @@ int analyse_instr(struct instruction_op *op, const
> > struct pt_regs *regs,> 
> >   		  struct ppc_inst instr)
> >   
> >   {
> >   
> >   	unsigned int opcode, ra, rb, rc, rd, spr, u;
> > 
> > +#ifdef __powerpc64__
> > +	unsigned int suffixopcode, prefixtype, prefix_r;
> > +#endif
> > 
> >   	unsigned long int imm;
> >   	unsigned long int val, val2;
> >   	unsigned int mb, me, sh;
> > 
> > @@ -2652,6 +2693,124 @@ int analyse_instr(struct instruction_op *op, const
> > struct pt_regs *regs,> 
> >   			break;
> >   		
> >   		}
> >   		break;
> > 
> > +	case 1: /* Prefixed instructions */
> > +		prefix_r = word & (1ul << 20);
> > +		ra = (suffix >> 16) & 0x1f;
> > +		op->update_reg = ra;
> > +		rd = (suffix >> 21) & 0x1f;
> > +		op->reg = rd;
> > +		op->val = regs->gpr[rd];
> > +
> > +		suffixopcode = suffix >> 26;
> > +		prefixtype = (word >> 24) & 0x3;
> > +		switch (prefixtype) {
> > +		case 0: /* Type 00  Eight-Byte Load/Store */
> > +			if (prefix_r && ra)
> > +				break;
> > +			op->ea = mlsd_8lsd_ea(word, suffix, regs);
> > +			switch (suffixopcode) {
> > +			case 41:	/* plwa */
> > +				op->type = MKOP(LOAD, PREFIXED | SIGNEXT, 4);
> > +				break;
> > +			case 42:        /* plxsd */
> > +				op->reg = rd + 32;
> > +				op->type = MKOP(LOAD_VSX, PREFIXED, 8);
> > +				op->element_size = 8;
> > +				op->vsx_flags = VSX_CHECK_VEC;
> > +				break;
> > +			case 43:	/* plxssp */
> > +				op->reg = rd + 32;
> > +				op->type = MKOP(LOAD_VSX, PREFIXED, 4);
> > +				op->element_size = 8;
> > +				op->vsx_flags = VSX_FPCONV | VSX_CHECK_VEC;
> > +				break;
> > +			case 46:	/* pstxsd */
> > +				op->reg = rd + 32;
> > +				op->type = MKOP(STORE_VSX, PREFIXED, 8);
> > +				op->element_size = 8;
> > +				op->vsx_flags = VSX_CHECK_VEC;
> > +				break;
> > +			case 47:	/* pstxssp */
> > +				op->reg = rd + 32;
> > +				op->type = MKOP(STORE_VSX, PREFIXED, 4);
> > +				op->element_size = 8;
> > +				op->vsx_flags = VSX_FPCONV | VSX_CHECK_VEC;
> > +				break;
> > +			case 51:	/* plxv1 */
> > +				op->reg += 32;
> > +				fallthrough;
> > +			case 50:	/* plxv0 */
> > +				op->type = MKOP(LOAD_VSX, PREFIXED, 16);
> > +				op->element_size = 16;
> > +				op->vsx_flags = VSX_CHECK_VEC;
> > +				break;
> > +			case 55:	/* pstxv1 */
> > +				op->reg = rd + 32;
> > +				fallthrough;
> > +			case 54:	/* pstxv0 */
> > +				op->type = MKOP(STORE_VSX, PREFIXED, 16);
> > +				op->element_size = 16;
> > +				op->vsx_flags = VSX_CHECK_VEC;
> > +				break;
> > +			case 56:        /* plq */
> > +				op->type = MKOP(LOAD, PREFIXED, 16);
> > +				break;
> > +			case 57:	/* pld */
> > +				op->type = MKOP(LOAD, PREFIXED, 8);
> > +				break;
> > +			case 60:        /* stq */
> > +				op->type = MKOP(STORE, PREFIXED, 16);
> > +				break;
> > +			case 61:	/* pstd */
> > +				op->type = MKOP(STORE, PREFIXED, 8);
> > +				break;
> > +			}
> > +			break;
> > +		case 1: /* Type 01 Eight-Byte Register-to-Register */
> > +			break;
> > +		case 2: /* Type 10 Modified Load/Store */
> > +			if (prefix_r && ra)
> > +				break;
> > +			op->ea = mlsd_8lsd_ea(word, suffix, regs);
> > +			switch (suffixopcode) {
> > +			case 32:	/* plwz */
> > +				op->type = MKOP(LOAD, PREFIXED, 4);
> > +				break;
> > +			case 34:	/* plbz */
> > +				op->type = MKOP(LOAD, PREFIXED, 1);
> > +				break;
> > +			case 36:	/* pstw */
> > +				op->type = MKOP(STORE, PREFIXED, 4);
> > +				break;
> > +			case 38:	/* pstb */
> > +				op->type = MKOP(STORE, PREFIXED, 1);
> > +				break;
> > +			case 40:	/* plhz */
> > +				op->type = MKOP(LOAD, PREFIXED, 2);
> > +				break;
> > +			case 42:	/* plha */
> > +				op->type = MKOP(LOAD, PREFIXED | SIGNEXT, 2);
> > +				break;
> > +			case 44:	/* psth */
> > +				op->type = MKOP(STORE, PREFIXED, 2);
> > +				break;
> > +			case 48:        /* plfs */
> > +				op->type = MKOP(LOAD_FP, PREFIXED | FPCONV, 4);
> > +				break;
> > +			case 50:        /* plfd */
> > +				op->type = MKOP(LOAD_FP, PREFIXED, 8);
> > +				break;
> > +			case 52:        /* pstfs */
> > +				op->type = MKOP(STORE_FP, PREFIXED | FPCONV, 4);
> > +				break;
> > +			case 54:        /* pstfd */
> > +				op->type = MKOP(STORE_FP, PREFIXED, 8);
> > +				break;
> > +			}
> > +			break;
> > +		case 3: /* Type 11 Modified Register-to-Register */
> > +			break;
> > +		}
> > 
> >   #endif /* __powerpc64__ */
> >   
> >   	}
> > 
> > @@ -2760,7 +2919,7 @@ void emulate_update_regs(struct pt_regs *regs,
> > struct instruction_op *op)> 
> >   {
> >   
> >   	unsigned long next_pc;
> > 
> > -	next_pc = truncate_if_32bit(regs->msr, regs->nip + 4);
> > +	next_pc = truncate_if_32bit(regs->msr, regs->nip + GETLENGTH(op-
>type));
> > 
> >   	switch (GETTYPE(op->type)) {
> >   	
> >   	case COMPUTE:
> >   		if (op->type & SETREG)
> > 
> > @@ -3205,7 +3364,7 @@ int emulate_step(struct pt_regs *regs, struct
> > ppc_inst instr)> 
> >   	return 0;
> >   	
> >    instr_done:
> > -	regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
> > +	regs->nip = truncate_if_32bit(regs->msr, regs->nip +
> > GETLENGTH(op.type));
> > 
> >   	return 1;
> >   
> >   }
> >   NOKPROBE_SYMBOL(emulate_step);





^ permalink raw reply

* Re: [PATCH v8 28/30] powerpc: Support prefixed instructions in alignment handler
From: Alistair Popple @ 2020-05-14 12:15 UTC (permalink / raw)
  To: Christophe Leroy
  Cc: christophe.leroy, Jordan Niethe, npiggin, bala24, naveen.n.rao,
	linuxppc-dev, dja
In-Reply-To: <0bfb8015-44e4-7693-e32e-39b46a87dd3a@csgroup.eu>

On Thursday, 14 May 2020 4:14:12 PM AEST Christophe Leroy wrote:
> Le 06/05/2020 à 05:40, Jordan Niethe a écrit :
> > If a prefixed instruction results in an alignment exception, the
> > SRR1_PREFIXED bit is set. The handler attempts to emulate the
> > responsible instruction and then increment the NIP past it. Use
> > SRR1_PREFIXED to determine by how much the NIP should be incremented.
> > 
> > Prefixed instructions are not permitted to cross 64-byte boundaries. If
> > they do the alignment interrupt is invoked with SRR1 BOUNDARY bit set.
> > If this occurs send a SIGBUS to the offending process if in user mode.
> > If in kernel mode call bad_page_fault().
> 
> Shouldn't this patch go before patch 23 ?

Is there a particular reason you think it needs to go before patch 23? Neither 
seem particularly related to one another and it seems logical to me at least 
that you would introduce prefix support to the datatype prior to using them.

- Alistair
 
> Christophe
> 
> > Reviewed-by: Alistair Popple <alistair@popple.id.au>
> > Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
> > ---
> > v2: - Move __get_user_instr() and __get_user_instr_inatomic() to this
> > commit (previously in "powerpc sstep: Prepare to support prefixed
> > instructions").
> > 
> >      - Rename sufx to suffix
> >      - Use a macro for calculating instruction length
> > 
> > v3: Move __get_user_{instr(), instr_inatomic()} up with the other
> > get_user definitions and remove nested if.
> > v4: Rolled into "Add prefixed instructions to instruction data type"
> > v5: Only one definition of inst_length()
> > ---
> > 
> >   arch/powerpc/kernel/traps.c | 19 ++++++++++++++++++-
> >   1 file changed, 18 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
> > index 493a3fa0ac1a..105242cc2f28 100644
> > --- a/arch/powerpc/kernel/traps.c
> > +++ b/arch/powerpc/kernel/traps.c
> > @@ -583,6 +583,8 @@ static inline int check_io_access(struct pt_regs
> > *regs)
> > 
> >   #define REASON_ILLEGAL		(ESR_PIL | ESR_PUO)
> >   #define REASON_PRIVILEGED	ESR_PPR
> >   #define REASON_TRAP		ESR_PTR
> > 
> > +#define REASON_PREFIXED		0
> > +#define REASON_BOUNDARY		0
> > 
> >   /* single-step stuff */
> >   #define single_stepping(regs)	(current->thread.debug.dbcr0 & DBCR0_IC)
> > 
> > @@ -597,12 +599,16 @@ static inline int check_io_access(struct pt_regs
> > *regs)> 
> >   #define REASON_ILLEGAL		SRR1_PROGILL
> >   #define REASON_PRIVILEGED	SRR1_PROGPRIV
> >   #define REASON_TRAP		SRR1_PROGTRAP
> > 
> > +#define REASON_PREFIXED		SRR1_PREFIXED
> > +#define REASON_BOUNDARY		SRR1_BOUNDARY
> > 
> >   #define single_stepping(regs)	((regs)->msr & MSR_SE)
> >   #define clear_single_step(regs)	((regs)->msr &= ~MSR_SE)
> >   #define clear_br_trace(regs)	((regs)->msr &= ~MSR_BE)
> >   #endif
> > 
> > +#define inst_length(reason)	(((reason) & REASON_PREFIXED) ? 8 : 4)
> > +
> > 
> >   #if defined(CONFIG_E500)
> >   int machine_check_e500mc(struct pt_regs *regs)
> >   {
> > 
> > @@ -1593,11 +1599,20 @@ void alignment_exception(struct pt_regs *regs)
> > 
> >   {
> >   
> >   	enum ctx_state prev_state = exception_enter();
> >   	int sig, code, fixed = 0;
> > 
> > +	unsigned long  reason;
> > 
> >   	/* We restore the interrupt state now */
> >   	if (!arch_irq_disabled_regs(regs))
> >   	
> >   		local_irq_enable();
> > 
> > +	reason = get_reason(regs);
> > +
> > +	if (reason & REASON_BOUNDARY) {
> > +		sig = SIGBUS;
> > +		code = BUS_ADRALN;
> > +		goto bad;
> > +	}
> > +
> > 
> >   	if (tm_abort_check(regs, TM_CAUSE_ALIGNMENT | TM_CAUSE_PERSISTENT))
> >   	
> >   		goto bail;
> > 
> > @@ -1606,7 +1621,8 @@ void alignment_exception(struct pt_regs *regs)
> > 
> >   		fixed = fix_alignment(regs);
> >   	
> >   	if (fixed == 1) {
> > 
> > -		regs->nip += 4;	/* skip over emulated instruction */
> > +		/* skip over emulated instruction */
> > +		regs->nip += inst_length(reason);
> > 
> >   		emulate_single_step(regs);
> >   		goto bail;
> >   	
> >   	}
> > 
> > @@ -1619,6 +1635,7 @@ void alignment_exception(struct pt_regs *regs)
> > 
> >   		sig = SIGBUS;
> >   		code = BUS_ADRALN;
> >   	
> >   	}
> > 
> > +bad:
> >   	if (user_mode(regs))
> >   	
> >   		_exception(sig, regs, code, regs->dar);
> >   	
> >   	else





^ permalink raw reply

* Re: [PATCH v8 23/30] powerpc: Add prefixed instructions to instruction data type
From: Alistair Popple @ 2020-05-14 12:06 UTC (permalink / raw)
  To: Christophe Leroy
  Cc: christophe.leroy, Jordan Niethe, npiggin, bala24, naveen.n.rao,
	linuxppc-dev, dja
In-Reply-To: <56ca6bcb-c719-a049-63b0-aae73023bde5@csgroup.eu>

On Thursday, 14 May 2020 4:11:43 PM AEST Christophe Leroy wrote:
> @@ -249,7 +249,7 @@ int arch_prepare_optimized_kprobe(struct
> optimized_kprobe *op, struct kprobe *p)
> > * Fixup the template with instructions to:
> > * 1. load the address of the actual probepoint
> > */
> > -       patch_imm64_load_insns((unsigned long)op, buff + TMPL_OP_IDX);
> > +       patch_imm64_load_insns((unsigned long)op, 3, buff + TMPL_OP_IDX);
> > 
> > /*
> > * 2. branch to optimized_callback() and emulate_step()
> > @@ -282,7 +282,11 @@ int arch_prepare_optimized_kprobe(struct
> > optimized_kprobe *op, struct kprobe *p) /*
> > * 3. load instruction to be emulated into relevant register, and
> > */
> > -       patch_imm32_load_insns(*p->ainsn.insn, buff + TMPL_INSN_IDX);
> > +       temp = ppc_inst_read((struct ppc_inst *)p->ainsn.insn);
> > +       patch_imm64_load_insns(ppc_inst_val(temp) |
> > +                              ((u64)ppc_inst_suffix(temp) << 32),
> > +                              4,
> 
> So now we are also using r4 ? Any explanation somewhere on the way it
> works ? This change seems unrelated to this patch, nothing in the
> description about it. Can we suddenly use a new register without problem ?

Unless I missed something there is no change in register usage here that I 
could see. patch_imm32_load_insns() was/is hardcoded to use register r4.

- Alistair



^ permalink raw reply

* [PATCH v6 16/16] powerpc/watchpoint/xmon: Support 2nd DAWR
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

Add support for 2nd DAWR in xmon. With this, we can have two
simultaneous breakpoints from xmon.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/xmon/xmon.c | 101 ++++++++++++++++++++++++++-------------
 1 file changed, 69 insertions(+), 32 deletions(-)

diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 094bf4715f2c..de585204d1d2 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -112,7 +112,7 @@ struct bpt {
 #define BP_DABR		4
 
 static struct bpt bpts[NBPTS];
-static struct bpt dabr;
+static struct bpt dabr[HBP_NUM_MAX];
 static struct bpt *iabr;
 static unsigned bpinstr = 0x7fe00008;	/* trap */
 
@@ -784,10 +784,17 @@ static int xmon_sstep(struct pt_regs *regs)
 
 static int xmon_break_match(struct pt_regs *regs)
 {
+	int i;
+
 	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
 		return 0;
-	if (dabr.enabled == 0)
-		return 0;
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (dabr[i].enabled)
+			goto found;
+	}
+	return 0;
+
+found:
 	xmon_core(regs, 0);
 	return 1;
 }
@@ -948,13 +955,16 @@ static void insert_bpts(void)
 
 static void insert_cpu_bpts(void)
 {
+	int i;
 	struct arch_hw_breakpoint brk;
 
-	if (dabr.enabled) {
-		brk.address = dabr.address;
-		brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
-		brk.len = DABR_MAX_LEN;
-		__set_breakpoint(0, &brk);
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (dabr[i].enabled) {
+			brk.address = dabr[i].address;
+			brk.type = (dabr[i].enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
+			brk.len = 8;
+			__set_breakpoint(i, &brk);
+		}
 	}
 
 	if (iabr)
@@ -1366,6 +1376,35 @@ static long check_bp_loc(unsigned long addr)
 	return 1;
 }
 
+static int find_free_data_bpt(void)
+{
+	int i;
+
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (!dabr[i].enabled)
+			return i;
+	}
+	printf("Couldn't find free breakpoint register\n");
+	return -1;
+}
+
+static void print_data_bpts(void)
+{
+	int i;
+
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (!dabr[i].enabled)
+			continue;
+
+		printf("   data   "REG"  [", dabr[i].address);
+		if (dabr[i].enabled & 1)
+			printf("r");
+		if (dabr[i].enabled & 2)
+			printf("w");
+		printf("]\n");
+	}
+}
+
 static char *breakpoint_help_string =
     "Breakpoint command usage:\n"
     "b                show breakpoints\n"
@@ -1399,10 +1438,9 @@ bpt_cmds(void)
 			printf("Hardware data breakpoint not supported on this cpu\n");
 			break;
 		}
-		if (dabr.enabled) {
-			printf("Couldn't find free breakpoint register\n");
+		i = find_free_data_bpt();
+		if (i < 0)
 			break;
-		}
 		mode = 7;
 		cmd = inchar();
 		if (cmd == 'r')
@@ -1411,15 +1449,15 @@ bpt_cmds(void)
 			mode = 6;
 		else
 			termch = cmd;
-		dabr.address = 0;
-		dabr.enabled = 0;
-		if (scanhex(&dabr.address)) {
-			if (!is_kernel_addr(dabr.address)) {
+		dabr[i].address = 0;
+		dabr[i].enabled = 0;
+		if (scanhex(&dabr[i].address)) {
+			if (!is_kernel_addr(dabr[i].address)) {
 				printf(badaddr);
 				break;
 			}
-			dabr.address &= ~HW_BRK_TYPE_DABR;
-			dabr.enabled = mode | BP_DABR;
+			dabr[i].address &= ~HW_BRK_TYPE_DABR;
+			dabr[i].enabled = mode | BP_DABR;
 		}
 
 		force_enable_xmon();
@@ -1458,7 +1496,9 @@ bpt_cmds(void)
 			for (i = 0; i < NBPTS; ++i)
 				bpts[i].enabled = 0;
 			iabr = NULL;
-			dabr.enabled = 0;
+			for (i = 0; i < nr_wp_slots(); i++)
+				dabr[i].enabled = 0;
+
 			printf("All breakpoints cleared\n");
 			break;
 		}
@@ -1492,14 +1532,7 @@ bpt_cmds(void)
 		if (xmon_is_ro || !scanhex(&a)) {
 			/* print all breakpoints */
 			printf("   type            address\n");
-			if (dabr.enabled) {
-				printf("   data   "REG"  [", dabr.address);
-				if (dabr.enabled & 1)
-					printf("r");
-				if (dabr.enabled & 2)
-					printf("w");
-				printf("]\n");
-			}
+			print_data_bpts();
 			for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
 				if (!bp->enabled)
 					continue;
@@ -1959,8 +1992,13 @@ static void dump_207_sprs(void)
 
 	printf("hfscr  = %.16lx  dhdes = %.16lx rpr    = %.16lx\n",
 		mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
-	printf("dawr   = %.16lx  dawrx = %.16lx ciabr  = %.16lx\n",
-		mfspr(SPRN_DAWR0), mfspr(SPRN_DAWRX0), mfspr(SPRN_CIABR));
+	printf("dawr0  = %.16lx dawrx0 = %.16lx\n",
+	       mfspr(SPRN_DAWR0), mfspr(SPRN_DAWRX0));
+	if (nr_wp_slots() > 1) {
+		printf("dawr1  = %.16lx dawrx1 = %.16lx\n",
+		       mfspr(SPRN_DAWR1), mfspr(SPRN_DAWRX1));
+	}
+	printf("ciabr  = %.16lx\n", mfspr(SPRN_CIABR));
 #endif
 }
 
@@ -3909,10 +3947,9 @@ static void clear_all_bpt(void)
 		bpts[i].enabled = 0;
 
 	/* Clear any data or iabr breakpoints */
-	if (iabr || dabr.enabled) {
-		iabr = NULL;
-		dabr.enabled = 0;
-	}
+	iabr = NULL;
+	for (i = 0; i < nr_wp_slots(); i++)
+		dabr[i].enabled = 0;
 }
 
 #ifdef CONFIG_DEBUG_FS
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 15/16] powerpc/watchpoint/xmon: Don't allow breakpoint overwriting
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

Xmon allows overwriting breakpoints because it's supported by only
one DAWR. But with multiple DAWRs, overwriting becomes ambiguous
or unnecessary complicated. So let's not allow it.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/xmon/xmon.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 30b3e3d99c0d..094bf4715f2c 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -1399,6 +1399,10 @@ bpt_cmds(void)
 			printf("Hardware data breakpoint not supported on this cpu\n");
 			break;
 		}
+		if (dabr.enabled) {
+			printf("Couldn't find free breakpoint register\n");
+			break;
+		}
 		mode = 7;
 		cmd = inchar();
 		if (cmd == 'r')
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 14/16] powerpc/watchpoint: Don't allow concurrent perf and ptrace events
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

With Book3s DAWR, ptrace and perf watchpoints on powerpc behaves
differently. Ptrace watchpoint works in one-shot mode and generates
signal before executing instruction. It's ptrace user's job to
single-step the instruction and re-enable the watchpoint. OTOH, in
case of perf watchpoint, kernel emulates/single-steps the instruction
and then generates event. If perf and ptrace creates two events with
same or overlapping address ranges, it's ambiguous to decide who
should single-step the instruction. Because of this issue, don't
allow perf and ptrace watchpoint at the same time if their address
range overlaps.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/include/asm/hw_breakpoint.h |   2 +
 arch/powerpc/kernel/hw_breakpoint.c      | 221 +++++++++++++++++++++++
 kernel/events/hw_breakpoint.c            |  16 ++
 3 files changed, 239 insertions(+)

diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index add5aa076919..f42a55eb77d2 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -70,6 +70,8 @@ extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
 						unsigned long val, void *data);
 int arch_install_hw_breakpoint(struct perf_event *bp);
 void arch_uninstall_hw_breakpoint(struct perf_event *bp);
+int arch_reserve_bp_slot(struct perf_event *bp);
+void arch_release_bp_slot(struct perf_event *bp);
 void arch_unregister_hw_breakpoint(struct perf_event *bp);
 void hw_breakpoint_pmu_read(struct perf_event *bp);
 extern void flush_ptrace_hw_breakpoint(struct task_struct *tsk);
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index da858bc6a414..80396f3f7e90 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -124,6 +124,227 @@ static bool is_ptrace_bp(struct perf_event *bp)
 	return bp->overflow_handler == ptrace_triggered;
 }
 
+struct breakpoint {
+	struct list_head list;
+	struct perf_event *bp;
+	bool ptrace_bp;
+};
+
+static DEFINE_PER_CPU(struct breakpoint *, cpu_bps[HBP_NUM_MAX]);
+static LIST_HEAD(task_bps);
+
+static struct breakpoint *alloc_breakpoint(struct perf_event *bp)
+{
+	struct breakpoint *tmp;
+
+	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+	if (!tmp)
+		return ERR_PTR(-ENOMEM);
+	tmp->bp = bp;
+	tmp->ptrace_bp = is_ptrace_bp(bp);
+	return tmp;
+}
+
+static bool bp_addr_range_overlap(struct perf_event *bp1, struct perf_event *bp2)
+{
+	__u64 bp1_saddr, bp1_eaddr, bp2_saddr, bp2_eaddr;
+
+	bp1_saddr = ALIGN_DOWN(bp1->attr.bp_addr, HW_BREAKPOINT_SIZE);
+	bp1_eaddr = ALIGN(bp1->attr.bp_addr + bp1->attr.bp_len, HW_BREAKPOINT_SIZE);
+	bp2_saddr = ALIGN_DOWN(bp2->attr.bp_addr, HW_BREAKPOINT_SIZE);
+	bp2_eaddr = ALIGN(bp2->attr.bp_addr + bp2->attr.bp_len, HW_BREAKPOINT_SIZE);
+
+	return (bp1_saddr < bp2_eaddr && bp1_eaddr > bp2_saddr);
+}
+
+static bool alternate_infra_bp(struct breakpoint *b, struct perf_event *bp)
+{
+	return is_ptrace_bp(bp) ? !b->ptrace_bp : b->ptrace_bp;
+}
+
+static bool can_co_exist(struct breakpoint *b, struct perf_event *bp)
+{
+	return !(alternate_infra_bp(b, bp) && bp_addr_range_overlap(b->bp, bp));
+}
+
+static int task_bps_add(struct perf_event *bp)
+{
+	struct breakpoint *tmp;
+
+	tmp = alloc_breakpoint(bp);
+	if (IS_ERR(tmp))
+		return PTR_ERR(tmp);
+
+	list_add(&tmp->list, &task_bps);
+	return 0;
+}
+
+static void task_bps_remove(struct perf_event *bp)
+{
+	struct list_head *pos, *q;
+
+	list_for_each_safe(pos, q, &task_bps) {
+		struct breakpoint *tmp = list_entry(pos, struct breakpoint, list);
+
+		if (tmp->bp == bp) {
+			list_del(&tmp->list);
+			kfree(tmp);
+			break;
+		}
+	}
+}
+
+/*
+ * If any task has breakpoint from alternate infrastructure,
+ * return true. Otherwise return false.
+ */
+static bool all_task_bps_check(struct perf_event *bp)
+{
+	struct breakpoint *tmp;
+
+	list_for_each_entry(tmp, &task_bps, list) {
+		if (!can_co_exist(tmp, bp))
+			return true;
+	}
+	return false;
+}
+
+/*
+ * If same task has breakpoint from alternate infrastructure,
+ * return true. Otherwise return false.
+ */
+static bool same_task_bps_check(struct perf_event *bp)
+{
+	struct breakpoint *tmp;
+
+	list_for_each_entry(tmp, &task_bps, list) {
+		if (tmp->bp->hw.target == bp->hw.target &&
+		    !can_co_exist(tmp, bp))
+			return true;
+	}
+	return false;
+}
+
+static int cpu_bps_add(struct perf_event *bp)
+{
+	struct breakpoint **cpu_bp;
+	struct breakpoint *tmp;
+	int i = 0;
+
+	tmp = alloc_breakpoint(bp);
+	if (IS_ERR(tmp))
+		return PTR_ERR(tmp);
+
+	cpu_bp = per_cpu_ptr(cpu_bps, bp->cpu);
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (!cpu_bp[i]) {
+			cpu_bp[i] = tmp;
+			break;
+		}
+	}
+	return 0;
+}
+
+static void cpu_bps_remove(struct perf_event *bp)
+{
+	struct breakpoint **cpu_bp;
+	int i = 0;
+
+	cpu_bp = per_cpu_ptr(cpu_bps, bp->cpu);
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (!cpu_bp[i])
+			continue;
+
+		if (cpu_bp[i]->bp == bp) {
+			kfree(cpu_bp[i]);
+			cpu_bp[i] = NULL;
+			break;
+		}
+	}
+}
+
+static bool cpu_bps_check(int cpu, struct perf_event *bp)
+{
+	struct breakpoint **cpu_bp;
+	int i;
+
+	cpu_bp = per_cpu_ptr(cpu_bps, cpu);
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (cpu_bp[i] && !can_co_exist(cpu_bp[i], bp))
+			return true;
+	}
+	return false;
+}
+
+static bool all_cpu_bps_check(struct perf_event *bp)
+{
+	int cpu;
+
+	for_each_online_cpu(cpu) {
+		if (cpu_bps_check(cpu, bp))
+			return true;
+	}
+	return false;
+}
+
+/*
+ * We don't use any locks to serialize accesses to cpu_bps or task_bps
+ * because are already inside nr_bp_mutex.
+ */
+int arch_reserve_bp_slot(struct perf_event *bp)
+{
+	int ret;
+
+	/* ptrace breakpoint */
+	if (is_ptrace_bp(bp)) {
+		if (all_cpu_bps_check(bp))
+			return -ENOSPC;
+
+		if (same_task_bps_check(bp))
+			return -ENOSPC;
+
+		return task_bps_add(bp);
+	}
+
+	/* perf breakpoint */
+	if (is_kernel_addr(bp->attr.bp_addr))
+		return 0;
+
+	if (bp->hw.target && bp->cpu == -1) {
+		if (same_task_bps_check(bp))
+			return -ENOSPC;
+
+		return task_bps_add(bp);
+	} else if (!bp->hw.target && bp->cpu != -1) {
+		if (all_task_bps_check(bp))
+			return -ENOSPC;
+
+		return cpu_bps_add(bp);
+	}
+
+	if (same_task_bps_check(bp))
+		return -ENOSPC;
+
+	ret = cpu_bps_add(bp);
+	if (ret)
+		return ret;
+	ret = task_bps_add(bp);
+	if (ret)
+		cpu_bps_remove(bp);
+
+	return ret;
+}
+
+void arch_release_bp_slot(struct perf_event *bp)
+{
+	if (!is_kernel_addr(bp->attr.bp_addr)) {
+		if (bp->hw.target)
+			task_bps_remove(bp);
+		if (bp->cpu != -1)
+			cpu_bps_remove(bp);
+	}
+}
+
 /*
  * Perform cleanup of arch-specific counters during unregistration
  * of the perf-event
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c
index 3cc8416ec844..b48d7039a015 100644
--- a/kernel/events/hw_breakpoint.c
+++ b/kernel/events/hw_breakpoint.c
@@ -213,6 +213,15 @@ toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type,
 		list_del(&bp->hw.bp_list);
 }
 
+__weak int arch_reserve_bp_slot(struct perf_event *bp)
+{
+	return 0;
+}
+
+__weak void arch_release_bp_slot(struct perf_event *bp)
+{
+}
+
 /*
  * Function to perform processor-specific cleanup during unregistration
  */
@@ -270,6 +279,7 @@ static int __reserve_bp_slot(struct perf_event *bp, u64 bp_type)
 	struct bp_busy_slots slots = {0};
 	enum bp_type_idx type;
 	int weight;
+	int ret;
 
 	/* We couldn't initialize breakpoint constraints on boot */
 	if (!constraints_initialized)
@@ -294,6 +304,10 @@ static int __reserve_bp_slot(struct perf_event *bp, u64 bp_type)
 	if (slots.pinned + (!!slots.flexible) > nr_slots[type])
 		return -ENOSPC;
 
+	ret = arch_reserve_bp_slot(bp);
+	if (ret)
+		return ret;
+
 	toggle_bp_slot(bp, true, type, weight);
 
 	return 0;
@@ -317,6 +331,8 @@ static void __release_bp_slot(struct perf_event *bp, u64 bp_type)
 	enum bp_type_idx type;
 	int weight;
 
+	arch_release_bp_slot(bp);
+
 	type = find_slot_idx(bp_type);
 	weight = hw_breakpoint_weight(bp);
 	toggle_bp_slot(bp, false, type, weight);
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 13/16] powerpc/watchpoint: Prepare handler to handle more than one watcnhpoint
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

Currently we assume that we have only one watchpoint supported by hw.
Get rid of that assumption and use dynamic loop instead. This should
make supporting more watchpoints very easy.

With more than one watchpoint, exception handler needs to know which
DAWR caused the exception, and hw currently does not provide it. So
we need sw logic for the same. To figure out which DAWR caused the
exception, check all different combinations of user specified range,
DAWR address range, actual access range and DAWRX constrains. For ex,
if user specified range and actual access range overlaps but DAWRX is
configured for readonly watchpoint and the instruction is store, this
DAWR must not have caused exception.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/include/asm/processor.h |   2 +-
 arch/powerpc/include/asm/sstep.h     |   2 +
 arch/powerpc/kernel/hw_breakpoint.c  | 397 +++++++++++++++++++++------
 arch/powerpc/kernel/process.c        |   3 -
 4 files changed, 312 insertions(+), 92 deletions(-)

diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index fba6b586e3c8..4e53df163b92 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -185,7 +185,7 @@ struct thread_struct {
 	 * Helps identify source of single-step exception and subsequent
 	 * hw-breakpoint enablement
 	 */
-	struct perf_event *last_hit_ubp;
+	struct perf_event *last_hit_ubp[HBP_NUM_MAX];
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 	struct arch_hw_breakpoint hw_brk[HBP_NUM_MAX]; /* hardware breakpoint info */
 	unsigned long	trap_nr;	/* last trap # on this thread */
diff --git a/arch/powerpc/include/asm/sstep.h b/arch/powerpc/include/asm/sstep.h
index 9b200a5f8794..3b01c69a44aa 100644
--- a/arch/powerpc/include/asm/sstep.h
+++ b/arch/powerpc/include/asm/sstep.h
@@ -49,6 +49,8 @@ enum instruction_type {
 
 #define INSTR_TYPE_MASK	0x1f
 
+#define OP_IS_LOAD(type)	((LOAD <= (type) && (type) <= LOAD_VSX) || (type) == LARX)
+#define OP_IS_STORE(type)	((STORE <= (type) && (type) <= STORE_VSX) || (type) == STCX)
 #define OP_IS_LOAD_STORE(type)	(LOAD <= (type) && (type) <= STCX)
 
 /* Compute flags, ORed in with type */
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index 4366bd0c90c4..da858bc6a414 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -31,7 +31,7 @@
  * Stores the breakpoints currently in use on each breakpoint address
  * register for every cpu
  */
-static DEFINE_PER_CPU(struct perf_event *, bp_per_reg);
+static DEFINE_PER_CPU(struct perf_event *, bp_per_reg[HBP_NUM_MAX]);
 
 /*
  * Returns total number of data or instruction breakpoints available.
@@ -43,6 +43,17 @@ int hw_breakpoint_slots(int type)
 	return 0;		/* no instruction breakpoints available */
 }
 
+static bool single_step_pending(void)
+{
+	int i;
+
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (current->thread.last_hit_ubp[i])
+			return true;
+	}
+	return false;
+}
+
 /*
  * Install a perf counter breakpoint.
  *
@@ -55,16 +66,26 @@ int hw_breakpoint_slots(int type)
 int arch_install_hw_breakpoint(struct perf_event *bp)
 {
 	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
-	struct perf_event **slot = this_cpu_ptr(&bp_per_reg);
+	struct perf_event **slot;
+	int i;
+
+	for (i = 0; i < nr_wp_slots(); i++) {
+		slot = this_cpu_ptr(&bp_per_reg[i]);
+		if (!*slot) {
+			*slot = bp;
+			break;
+		}
+	}
 
-	*slot = bp;
+	if (WARN_ONCE(i == nr_wp_slots(), "Can't find any breakpoint slot"))
+		return -EBUSY;
 
 	/*
 	 * Do not install DABR values if the instruction must be single-stepped.
 	 * If so, DABR will be populated in single_step_dabr_instruction().
 	 */
-	if (current->thread.last_hit_ubp != bp)
-		__set_breakpoint(0, info);
+	if (!single_step_pending())
+		__set_breakpoint(i, info);
 
 	return 0;
 }
@@ -80,15 +101,22 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
  */
 void arch_uninstall_hw_breakpoint(struct perf_event *bp)
 {
-	struct perf_event **slot = this_cpu_ptr(&bp_per_reg);
+	struct arch_hw_breakpoint null_brk = {0};
+	struct perf_event **slot;
+	int i;
 
-	if (*slot != bp) {
-		WARN_ONCE(1, "Can't find the breakpoint");
-		return;
+	for (i = 0; i < nr_wp_slots(); i++) {
+		slot = this_cpu_ptr(&bp_per_reg[i]);
+		if (*slot == bp) {
+			*slot = NULL;
+			break;
+		}
 	}
 
-	*slot = NULL;
-	hw_breakpoint_disable();
+	if (WARN_ONCE(i == nr_wp_slots(), "Can't find any breakpoint slot"))
+		return;
+
+	__set_breakpoint(i, &null_brk);
 }
 
 static bool is_ptrace_bp(struct perf_event *bp)
@@ -108,8 +136,14 @@ void arch_unregister_hw_breakpoint(struct perf_event *bp)
 	 * restoration variables to prevent dangling pointers.
 	 * FIXME, this should not be using bp->ctx at all! Sayeth peterz.
 	 */
-	if (bp->ctx && bp->ctx->task && bp->ctx->task != ((void *)-1L))
-		bp->ctx->task->thread.last_hit_ubp = NULL;
+	if (bp->ctx && bp->ctx->task && bp->ctx->task != ((void *)-1L)) {
+		int i;
+
+		for (i = 0; i < nr_wp_slots(); i++) {
+			if (bp->ctx->task->thread.last_hit_ubp[i] == bp)
+				bp->ctx->task->thread.last_hit_ubp[i] = NULL;
+		}
+	}
 }
 
 /*
@@ -221,90 +255,211 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
 void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
 {
 	struct arch_hw_breakpoint *info;
+	int i;
 
-	if (likely(!tsk->thread.last_hit_ubp))
-		return;
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (unlikely(tsk->thread.last_hit_ubp[i]))
+			goto reset;
+	}
+	return;
 
-	info = counter_arch_bp(tsk->thread.last_hit_ubp);
+reset:
 	regs->msr &= ~MSR_SE;
-	__set_breakpoint(0, info);
-	tsk->thread.last_hit_ubp = NULL;
+	for (i = 0; i < nr_wp_slots(); i++) {
+		info = counter_arch_bp(__this_cpu_read(bp_per_reg[i]));
+		__set_breakpoint(i, info);
+		tsk->thread.last_hit_ubp[i] = NULL;
+	}
 }
 
-static bool dar_within_range(unsigned long dar, struct arch_hw_breakpoint *info)
+static bool dar_in_user_range(unsigned long dar, struct arch_hw_breakpoint *info)
 {
 	return ((info->address <= dar) && (dar - info->address < info->len));
 }
 
-static bool
-dar_range_overlaps(unsigned long dar, int size, struct arch_hw_breakpoint *info)
+static bool dar_user_range_overlaps(unsigned long dar, int size,
+				    struct arch_hw_breakpoint *info)
+{
+	return ((dar < info->address + info->len) &&
+		(dar + size > info->address));
+}
+
+static bool dar_in_hw_range(unsigned long dar, struct arch_hw_breakpoint *info)
+{
+	unsigned long hw_start_addr, hw_end_addr;
+
+	hw_start_addr = ALIGN_DOWN(info->address, HW_BREAKPOINT_SIZE);
+	hw_end_addr = ALIGN(info->address + info->len, HW_BREAKPOINT_SIZE);
+
+	return ((hw_start_addr <= dar) && (hw_end_addr > dar));
+}
+
+static bool dar_hw_range_overlaps(unsigned long dar, int size,
+				  struct arch_hw_breakpoint *info)
 {
-	return ((dar <= info->address + info->len - 1) &&
-		(dar + size - 1 >= info->address));
+	unsigned long hw_start_addr, hw_end_addr;
+
+	hw_start_addr = ALIGN_DOWN(info->address, HW_BREAKPOINT_SIZE);
+	hw_end_addr = ALIGN(info->address + info->len, HW_BREAKPOINT_SIZE);
+
+	return ((dar < hw_end_addr) && (dar + size > hw_start_addr));
 }
 
 /*
- * Handle debug exception notifications.
+ * If hw has multiple DAWR registers, we also need to check all
+ * dawrx constraint bits to confirm this is _really_ a valid event.
  */
-static bool stepping_handler(struct pt_regs *regs, struct perf_event *bp,
-			     struct arch_hw_breakpoint *info)
+static bool check_dawrx_constraints(struct pt_regs *regs, int type,
+				    struct arch_hw_breakpoint *info)
 {
-	struct ppc_inst instr = ppc_inst(0);
-	int ret, type, size;
-	struct instruction_op op;
-	unsigned long addr = info->address;
+	if (OP_IS_LOAD(type) && !(info->type & HW_BRK_TYPE_READ))
+		return false;
 
-	if (__get_user_instr_inatomic(instr, (void __user *)regs->nip))
-		goto fail;
+	if (OP_IS_STORE(type) && !(info->type & HW_BRK_TYPE_WRITE))
+		return false;
 
-	ret = analyse_instr(&op, regs, instr);
-	type = GETTYPE(op.type);
-	size = GETSIZE(op.type);
+	if (is_kernel_addr(regs->nip) && !(info->type & HW_BRK_TYPE_KERNEL))
+		return false;
 
-	if (!ret && (type == LARX || type == STCX)) {
-		printk_ratelimited("Breakpoint hit on instruction that can't be emulated."
-				   " Breakpoint at 0x%lx will be disabled.\n", addr);
-		goto disable;
-	}
+	if (user_mode(regs) && !(info->type & HW_BRK_TYPE_USER))
+		return false;
+
+	return true;
+}
+
+/*
+ * Return true if the event is valid wrt dawr configuration,
+ * including extraneous exception. Otherwise return false.
+ */
+static bool check_constraints(struct pt_regs *regs, struct ppc_inst instr,
+			      int type, int size, struct arch_hw_breakpoint *info)
+{
+	bool in_user_range = dar_in_user_range(regs->dar, info);
+	bool dawrx_constraints;
 
 	/*
-	 * If it's extraneous event, we still need to emulate/single-
-	 * step the instruction, but we don't generate an event.
+	 * 8xx supports only one breakpoint and thus we can
+	 * unconditionally return true.
 	 */
-	if (size && !dar_range_overlaps(regs->dar, size, info))
-		info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
+	if (IS_ENABLED(CONFIG_PPC_8xx)) {
+		if (!in_user_range)
+			info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
+		return true;
+	}
 
-	/* Do not emulate user-space instructions, instead single-step them */
-	if (user_mode(regs)) {
-		current->thread.last_hit_ubp = bp;
-		regs->msr |= MSR_SE;
+	if (unlikely(ppc_inst_equal(instr, ppc_inst(0)))) {
+		if (in_user_range)
+			return true;
+
+		if (dar_in_hw_range(regs->dar, info)) {
+			info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
+			return true;
+		}
 		return false;
 	}
 
-	if (!emulate_step(regs, instr))
-		goto fail;
+	dawrx_constraints = check_dawrx_constraints(regs, type, info);
 
-	return true;
+	if (dar_user_range_overlaps(regs->dar, size, info))
+		return dawrx_constraints;
+
+	if (dar_hw_range_overlaps(regs->dar, size, info)) {
+		if (dawrx_constraints) {
+			info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
+			return true;
+		}
+	}
+	return false;
+}
+
+static void get_instr_detail(struct pt_regs *regs, struct ppc_inst *instr,
+			     int *type, int *size, bool *larx_stcx)
+{
+	struct instruction_op op;
+
+	if (__get_user_instr_inatomic(*instr, (void __user *)regs->nip))
+		return;
+
+	analyse_instr(&op, regs, *instr);
 
-fail:
 	/*
-	 * We've failed in reliably handling the hw-breakpoint. Unregister
-	 * it and throw a warning message to let the user know about it.
+	 * Set size = 8 if analyse_instr() fails. If it's a userspace
+	 * watchpoint(valid or extraneous), we can notify user about it.
+	 * If it's a kernel watchpoint, instruction  emulation will fail
+	 * in stepping_handler() and watchpoint will be disabled.
 	 */
-	WARN(1, "Unable to handle hardware breakpoint. Breakpoint at "
-		"0x%lx will be disabled.", addr);
+	*type = GETTYPE(op.type);
+	*size = !(*type == UNKNOWN) ? GETSIZE(op.type) : 8;
+	*larx_stcx = (*type == LARX || *type == STCX);
+}
+
+/*
+ * We've failed in reliably handling the hw-breakpoint. Unregister
+ * it and throw a warning message to let the user know about it.
+ */
+static void handler_error(struct perf_event *bp, struct arch_hw_breakpoint *info)
+{
+	WARN(1, "Unable to handle hardware breakpoint."
+		"Breakpoint at 0x%lx will be disabled.",
+		info->address);
+	perf_event_disable_inatomic(bp);
+}
 
-disable:
+static void larx_stcx_err(struct perf_event *bp, struct arch_hw_breakpoint *info)
+{
+	printk_ratelimited("Breakpoint hit on instruction that can't "
+			   "be emulated. Breakpoint at 0x%lx will be "
+			   "disabled.\n", info->address);
 	perf_event_disable_inatomic(bp);
-	return false;
+}
+
+static bool stepping_handler(struct pt_regs *regs, struct perf_event **bp,
+			     struct arch_hw_breakpoint **info, int *hit,
+			     struct ppc_inst instr)
+{
+	int i;
+	int stepped;
+
+	/* Do not emulate user-space instructions, instead single-step them */
+	if (user_mode(regs)) {
+		for (i = 0; i < nr_wp_slots(); i++) {
+			if (!hit[i])
+				continue;
+			current->thread.last_hit_ubp[i] = bp[i];
+			info[i] = NULL;
+		}
+		regs->msr |= MSR_SE;
+		return false;
+	}
+
+	stepped = emulate_step(regs, instr);
+	if (!stepped) {
+		for (i = 0; i < nr_wp_slots(); i++) {
+			if (!hit[i])
+				continue;
+			handler_error(bp[i], info[i]);
+			info[i] = NULL;
+		}
+		return false;
+	}
+	return true;
 }
 
 int hw_breakpoint_handler(struct die_args *args)
 {
+	bool err = false;
 	int rc = NOTIFY_STOP;
-	struct perf_event *bp;
+	struct perf_event *bp[HBP_NUM_MAX] = {0};
 	struct pt_regs *regs = args->regs;
-	struct arch_hw_breakpoint *info;
+	struct arch_hw_breakpoint *info[HBP_NUM_MAX] = {0};
+	int i;
+	int hit[HBP_NUM_MAX] = {0};
+	int nr_hit = 0;
+	bool ptrace_bp = false;
+	struct ppc_inst instr = ppc_inst(0);
+	int type = 0;
+	int size = 0;
+	bool larx_stcx = false;
 
 	/* Disable breakpoints during exception handling */
 	hw_breakpoint_disable();
@@ -317,12 +472,40 @@ int hw_breakpoint_handler(struct die_args *args)
 	 */
 	rcu_read_lock();
 
-	bp = __this_cpu_read(bp_per_reg);
-	if (!bp) {
+	if (!IS_ENABLED(CONFIG_PPC_8xx))
+		get_instr_detail(regs, &instr, &type, &size, &larx_stcx);
+
+	for (i = 0; i < nr_wp_slots(); i++) {
+		bp[i] = __this_cpu_read(bp_per_reg[i]);
+		if (!bp[i])
+			continue;
+
+		info[i] = counter_arch_bp(bp[i]);
+		info[i]->type &= ~HW_BRK_TYPE_EXTRANEOUS_IRQ;
+
+		if (check_constraints(regs, instr, type, size, info[i])) {
+			if (!IS_ENABLED(CONFIG_PPC_8xx) &&
+			    ppc_inst_equal(instr, ppc_inst(0))) {
+				handler_error(bp[i], info[i]);
+				info[i] = NULL;
+				err = 1;
+				continue;
+			}
+
+			if (is_ptrace_bp(bp[i]))
+				ptrace_bp = true;
+			hit[i] = 1;
+			nr_hit++;
+		}
+	}
+
+	if (err)
+		goto reset;
+
+	if (!nr_hit) {
 		rc = NOTIFY_DONE;
 		goto out;
 	}
-	info = counter_arch_bp(bp);
 
 	/*
 	 * Return early after invoking user-callback function without restoring
@@ -330,29 +513,50 @@ int hw_breakpoint_handler(struct die_args *args)
 	 * one-shot mode. The ptrace-ed process will receive the SIGTRAP signal
 	 * generated in do_dabr().
 	 */
-	if (is_ptrace_bp(bp)) {
-		perf_bp_event(bp, regs);
+	if (ptrace_bp) {
+		for (i = 0; i < nr_wp_slots(); i++) {
+			if (!hit[i])
+				continue;
+			perf_bp_event(bp[i], regs);
+			info[i] = NULL;
+		}
 		rc = NOTIFY_DONE;
-		goto out;
+		goto reset;
 	}
 
-	info->type &= ~HW_BRK_TYPE_EXTRANEOUS_IRQ;
-	if (IS_ENABLED(CONFIG_PPC_8xx)) {
-		if (!dar_within_range(regs->dar, info))
-			info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
-	} else {
-		if (!stepping_handler(regs, bp, info))
-			goto out;
+	if (!IS_ENABLED(CONFIG_PPC_8xx)) {
+		if (larx_stcx) {
+			for (i = 0; i < nr_wp_slots(); i++) {
+				if (!hit[i])
+					continue;
+				larx_stcx_err(bp[i], info[i]);
+				info[i] = NULL;
+			}
+			goto reset;
+		}
+
+		if (!stepping_handler(regs, bp, info, hit, instr))
+			goto reset;
 	}
 
 	/*
 	 * As a policy, the callback is invoked in a 'trigger-after-execute'
 	 * fashion
 	 */
-	if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ))
-		perf_bp_event(bp, regs);
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (!hit[i])
+			continue;
+		if (!(info[i]->type & HW_BRK_TYPE_EXTRANEOUS_IRQ))
+			perf_bp_event(bp[i], regs);
+	}
+
+reset:
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (!info[i])
+			continue;
+		__set_breakpoint(i, info[i]);
+	}
 
-	__set_breakpoint(0, info);
 out:
 	rcu_read_unlock();
 	return rc;
@@ -367,26 +571,43 @@ static int single_step_dabr_instruction(struct die_args *args)
 	struct pt_regs *regs = args->regs;
 	struct perf_event *bp = NULL;
 	struct arch_hw_breakpoint *info;
+	int i;
+	bool found = false;
 
-	bp = current->thread.last_hit_ubp;
 	/*
 	 * Check if we are single-stepping as a result of a
 	 * previous HW Breakpoint exception
 	 */
-	if (!bp)
-		return NOTIFY_DONE;
+	for (i = 0; i < nr_wp_slots(); i++) {
+		bp = current->thread.last_hit_ubp[i];
+
+		if (!bp)
+			continue;
+
+		found = true;
+		info = counter_arch_bp(bp);
+
+		/*
+		 * We shall invoke the user-defined callback function in the
+		 * single stepping handler to confirm to 'trigger-after-execute'
+		 * semantics
+		 */
+		if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ))
+			perf_bp_event(bp, regs);
+		current->thread.last_hit_ubp[i] = NULL;
+	}
 
-	info = counter_arch_bp(bp);
+	if (!found)
+		return NOTIFY_DONE;
 
-	/*
-	 * We shall invoke the user-defined callback function in the single
-	 * stepping handler to confirm to 'trigger-after-execute' semantics
-	 */
-	if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ))
-		perf_bp_event(bp, regs);
+	for (i = 0; i < nr_wp_slots(); i++) {
+		bp = __this_cpu_read(bp_per_reg[i]);
+		if (!bp)
+			continue;
 
-	__set_breakpoint(0, info);
-	current->thread.last_hit_ubp = NULL;
+		info = counter_arch_bp(bp);
+		__set_breakpoint(i, info);
+	}
 
 	/*
 	 * If the process was being single-stepped by ptrace, let the
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 9b11575dcb8a..048d64c4e115 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -629,9 +629,6 @@ void do_break (struct pt_regs *regs, unsigned long address,
 	if (debugger_break_match(regs))
 		return;
 
-	/* Clear the breakpoint */
-	hw_breakpoint_disable();
-
 	/* Deliver the signal to userspace */
 	force_sig_fault(SIGTRAP, TRAP_HWBKPT, (void __user *)address);
 }
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 12/16] powerpc/watchpoint: Use builtin ALIGN*() macros
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

Currently we calculate hw aligned start and end addresses manually.
Replace them with builtin ALIGN_DOWN() and ALIGN() macros.

So far end_addr was inclusive but this patch makes it exclusive (by
avoiding -1) for better readability.

Suggested-by: Christophe Leroy <christophe.leroy@c-s.fr>
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/include/asm/hw_breakpoint.h  |  5 +++--
 arch/powerpc/kernel/hw_breakpoint.c       | 12 ++++++------
 arch/powerpc/kernel/process.c             |  8 ++++----
 arch/powerpc/kernel/ptrace/ptrace-noadv.c |  2 +-
 4 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index d472b2eb757e..add5aa076919 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -34,10 +34,11 @@ struct arch_hw_breakpoint {
 #define HW_BRK_TYPE_PRIV_ALL	(HW_BRK_TYPE_USER | HW_BRK_TYPE_KERNEL | \
 				 HW_BRK_TYPE_HYP)
 
+/* Minimum granularity */
 #ifdef CONFIG_PPC_8xx
-#define HW_BREAKPOINT_ALIGN 0x3
+#define HW_BREAKPOINT_SIZE  0x4
 #else
-#define HW_BREAKPOINT_ALIGN 0x7
+#define HW_BREAKPOINT_SIZE  0x8
 #endif
 
 #define DABR_MAX_LEN	8
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index 8028a2704874..4366bd0c90c4 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -146,10 +146,10 @@ int arch_bp_generic_fields(int type, int *gen_bp_type)
  *    <---8 bytes--->
  *
  * In this case, we should configure hw as:
- *   start_addr = address & ~HW_BREAKPOINT_ALIGN
+ *   start_addr = address & ~(HW_BREAKPOINT_SIZE - 1)
  *   len = 16 bytes
  *
- * @start_addr and @end_addr are inclusive.
+ * @start_addr is inclusive but @end_addr is exclusive.
  */
 static int hw_breakpoint_validate_len(struct arch_hw_breakpoint *hw)
 {
@@ -157,14 +157,14 @@ static int hw_breakpoint_validate_len(struct arch_hw_breakpoint *hw)
 	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;
+	start_addr = ALIGN_DOWN(hw->address, HW_BREAKPOINT_SIZE);
+	end_addr = ALIGN(hw->address + hw->len, HW_BREAKPOINT_SIZE);
+	hw_len = end_addr - start_addr;
 
 	if (dawr_enabled()) {
 		max_len = DAWR_MAX_LEN;
 		/* DAWR region can't cross 512 bytes boundary */
-		if ((start_addr >> 9) != (end_addr >> 9))
+		if (ALIGN(start_addr, SZ_512M) != ALIGN(end_addr - 1, SZ_512M))
 			return -EINVAL;
 	} else if (IS_ENABLED(CONFIG_PPC_8xx)) {
 		/* 8xx can setup a range without limitation */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 77ec1299e2fd..9b11575dcb8a 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -800,12 +800,12 @@ static inline int set_breakpoint_8xx(struct arch_hw_breakpoint *brk)
 	unsigned long lctrl1 = LCTRL1_CTE_GT | LCTRL1_CTF_LT | LCTRL1_CRWE_RW |
 			       LCTRL1_CRWF_RW;
 	unsigned long lctrl2 = LCTRL2_LW0EN | LCTRL2_LW0LADC | LCTRL2_SLW0EN;
-	unsigned long start_addr = brk->address & ~HW_BREAKPOINT_ALIGN;
-	unsigned long end_addr = (brk->address + brk->len - 1) | HW_BREAKPOINT_ALIGN;
+	unsigned long start_addr = ALIGN_DOWN(brk->address, HW_BREAKPOINT_SIZE);
+	unsigned long end_addr = ALIGN(brk->address + brk->len, HW_BREAKPOINT_SIZE);
 
 	if (start_addr == 0)
 		lctrl2 |= LCTRL2_LW0LA_F;
-	else if (end_addr == ~0U)
+	else if (end_addr == 0)
 		lctrl2 |= LCTRL2_LW0LA_E;
 	else
 		lctrl2 |= LCTRL2_LW0LA_EandF;
@@ -821,7 +821,7 @@ static inline int set_breakpoint_8xx(struct arch_hw_breakpoint *brk)
 		lctrl1 |= LCTRL1_CRWE_WO | LCTRL1_CRWF_WO;
 
 	mtspr(SPRN_CMPE, start_addr - 1);
-	mtspr(SPRN_CMPF, end_addr + 1);
+	mtspr(SPRN_CMPF, end_addr);
 	mtspr(SPRN_LCTRL1, lctrl1);
 	mtspr(SPRN_LCTRL2, lctrl2);
 
diff --git a/arch/powerpc/kernel/ptrace/ptrace-noadv.c b/arch/powerpc/kernel/ptrace/ptrace-noadv.c
index 08cb8c1b504c..697c7e4b5877 100644
--- a/arch/powerpc/kernel/ptrace/ptrace-noadv.c
+++ b/arch/powerpc/kernel/ptrace/ptrace-noadv.c
@@ -216,7 +216,7 @@ long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_inf
 	if ((unsigned long)bp_info->addr >= TASK_SIZE)
 		return -EIO;
 
-	brk.address = bp_info->addr & ~HW_BREAKPOINT_ALIGN;
+	brk.address = ALIGN_DOWN(bp_info->addr, HW_BREAKPOINT_SIZE);
 	brk.type = HW_BRK_TYPE_TRANSLATE;
 	brk.len = DABR_MAX_LEN;
 	if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 11/16] powerpc/watchpoint: Introduce is_ptrace_bp() function
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

Introduce is_ptrace_bp() function and move the check inside the
function. It will be utilize more in later set of patches.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/kernel/hw_breakpoint.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index 917cca73dbc3..8028a2704874 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -91,6 +91,11 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
 	hw_breakpoint_disable();
 }
 
+static bool is_ptrace_bp(struct perf_event *bp)
+{
+	return bp->overflow_handler == ptrace_triggered;
+}
+
 /*
  * Perform cleanup of arch-specific counters during unregistration
  * of the perf-event
@@ -325,7 +330,7 @@ int hw_breakpoint_handler(struct die_args *args)
 	 * one-shot mode. The ptrace-ed process will receive the SIGTRAP signal
 	 * generated in do_dabr().
 	 */
-	if (bp->overflow_handler == ptrace_triggered) {
+	if (is_ptrace_bp(bp)) {
 		perf_bp_event(bp, regs);
 		rc = NOTIFY_DONE;
 		goto out;
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 10/16] powerpc/watchpoint: Use loop for thread_struct->ptrace_bps
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

ptrace_bps is already an array of size HBP_NUM_MAX. But we use
hardcoded index 0 while fetching/updating it. Convert such code
to loop over array.

ptrace interface to use multiple watchpoint remains same. eg:
two PPC_PTRACE_SETHWDEBUG calls will create two watchpoint if
underneath hw supports it.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/kernel/hw_breakpoint.c       |  7 ++++--
 arch/powerpc/kernel/process.c             |  6 ++++-
 arch/powerpc/kernel/ptrace/ptrace-noadv.c | 28 +++++++++++++++++------
 3 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index f5472402c06d..917cca73dbc3 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -420,10 +420,13 @@ NOKPROBE_SYMBOL(hw_breakpoint_exceptions_notify);
  */
 void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
 {
+	int i;
 	struct thread_struct *t = &tsk->thread;
 
-	unregister_hw_breakpoint(t->ptrace_bps[0]);
-	t->ptrace_bps[0] = NULL;
+	for (i = 0; i < nr_wp_slots(); i++) {
+		unregister_hw_breakpoint(t->ptrace_bps[i]);
+		t->ptrace_bps[i] = NULL;
+	}
 }
 
 void hw_breakpoint_pmu_read(struct perf_event *bp)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index d94d8925711c..77ec1299e2fd 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1604,6 +1604,9 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
 	void (*f)(void);
 	unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
 	struct thread_info *ti = task_thread_info(p);
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+	int i;
+#endif
 
 	klp_init_thread_info(p);
 
@@ -1663,7 +1666,8 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
 	p->thread.ksp_limit = (unsigned long)end_of_stack(p);
 #endif
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
-	p->thread.ptrace_bps[0] = NULL;
+	for (i = 0; i < nr_wp_slots(); i++)
+		p->thread.ptrace_bps[i] = NULL;
 #endif
 
 	p->thread.fp_save_area = NULL;
diff --git a/arch/powerpc/kernel/ptrace/ptrace-noadv.c b/arch/powerpc/kernel/ptrace/ptrace-noadv.c
index 0dbb35392dd2..08cb8c1b504c 100644
--- a/arch/powerpc/kernel/ptrace/ptrace-noadv.c
+++ b/arch/powerpc/kernel/ptrace/ptrace-noadv.c
@@ -168,6 +168,19 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned l
 	return 0;
 }
 
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+static int find_empty_ptrace_bp(struct thread_struct *thread)
+{
+	int i;
+
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (!thread->ptrace_bps[i])
+			return i;
+	}
+	return -1;
+}
+#endif
+
 static int find_empty_hw_brk(struct thread_struct *thread)
 {
 	int i;
@@ -217,8 +230,9 @@ long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_inf
 		len = 1;
 	else
 		return -EINVAL;
-	bp = thread->ptrace_bps[0];
-	if (bp)
+
+	i = find_empty_ptrace_bp(thread);
+	if (i < 0)
 		return -ENOSPC;
 
 	/* Create a new breakpoint request if one doesn't exist already */
@@ -228,13 +242,13 @@ long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_inf
 	arch_bp_generic_fields(brk.type, &attr.bp_type);
 
 	bp = register_user_hw_breakpoint(&attr, ptrace_triggered, NULL, child);
-	thread->ptrace_bps[0] = bp;
+	thread->ptrace_bps[i] = bp;
 	if (IS_ERR(bp)) {
-		thread->ptrace_bps[0] = NULL;
+		thread->ptrace_bps[i] = NULL;
 		return PTR_ERR(bp);
 	}
 
-	return 1;
+	return i + 1;
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 
 	if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
@@ -263,10 +277,10 @@ long ppc_del_hwdebug(struct task_struct *child, long data)
 		return -EINVAL;
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
-	bp = thread->ptrace_bps[0];
+	bp = thread->ptrace_bps[data - 1];
 	if (bp) {
 		unregister_hw_breakpoint(bp);
-		thread->ptrace_bps[0] = NULL;
+		thread->ptrace_bps[data - 1] = NULL;
 	} else {
 		ret = -ENOENT;
 	}
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 09/16] powerpc/watchpoint: Convert thread_struct->hw_brk to an array
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

So far powerpc hw supported only one watchpoint. But Power10 is
introducing 2nd DAWR. Convert thread_struct->hw_brk into an array.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/include/asm/processor.h      |  2 +-
 arch/powerpc/kernel/process.c             | 60 ++++++++++++++---------
 arch/powerpc/kernel/ptrace/ptrace-noadv.c | 40 ++++++++++-----
 arch/powerpc/kernel/ptrace/ptrace32.c     |  4 +-
 arch/powerpc/kernel/signal.c              | 13 +++--
 5 files changed, 78 insertions(+), 41 deletions(-)

diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index f209c5703ee2..fba6b586e3c8 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -187,7 +187,7 @@ struct thread_struct {
 	 */
 	struct perf_event *last_hit_ubp;
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
-	struct arch_hw_breakpoint hw_brk; /* info on the hardware breakpoint */
+	struct arch_hw_breakpoint hw_brk[HBP_NUM_MAX]; /* hardware breakpoint info */
 	unsigned long	trap_nr;	/* last trap # on this thread */
 	u8 load_slb;			/* Ages out SLB preload cache entries */
 	u8 load_fp;
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index f303aea61794..d94d8925711c 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -711,21 +711,49 @@ void switch_booke_debug_regs(struct debug_reg *new_debug)
 EXPORT_SYMBOL_GPL(switch_booke_debug_regs);
 #else	/* !CONFIG_PPC_ADV_DEBUG_REGS */
 #ifndef CONFIG_HAVE_HW_BREAKPOINT
-static void set_breakpoint(struct arch_hw_breakpoint *brk)
+static void set_breakpoint(int i, struct arch_hw_breakpoint *brk)
 {
 	preempt_disable();
-	__set_breakpoint(0, brk);
+	__set_breakpoint(i, brk);
 	preempt_enable();
 }
 
 static void set_debug_reg_defaults(struct thread_struct *thread)
 {
-	thread->hw_brk.address = 0;
-	thread->hw_brk.type = 0;
-	thread->hw_brk.len = 0;
-	thread->hw_brk.hw_len = 0;
-	if (ppc_breakpoint_available())
-		set_breakpoint(&thread->hw_brk);
+	int i;
+	struct arch_hw_breakpoint null_brk = {0};
+
+	for (i = 0; i < nr_wp_slots(); i++) {
+		thread->hw_brk[i] = null_brk;
+		if (ppc_breakpoint_available())
+			set_breakpoint(i, &thread->hw_brk[i]);
+	}
+}
+
+static inline bool hw_brk_match(struct arch_hw_breakpoint *a,
+				struct arch_hw_breakpoint *b)
+{
+	if (a->address != b->address)
+		return false;
+	if (a->type != b->type)
+		return false;
+	if (a->len != b->len)
+		return false;
+	/* no need to check hw_len. it's calculated from address and len */
+	return true;
+}
+
+static void switch_hw_breakpoint(struct task_struct *new)
+{
+	int i;
+
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (likely(hw_brk_match(this_cpu_ptr(&current_brk[i]),
+					&new->thread.hw_brk[i])))
+			continue;
+
+		__set_breakpoint(i, &new->thread.hw_brk[i]);
+	}
 }
 #endif /* !CONFIG_HAVE_HW_BREAKPOINT */
 #endif	/* CONFIG_PPC_ADV_DEBUG_REGS */
@@ -829,19 +857,6 @@ bool ppc_breakpoint_available(void)
 }
 EXPORT_SYMBOL_GPL(ppc_breakpoint_available);
 
-static inline bool hw_brk_match(struct arch_hw_breakpoint *a,
-			      struct arch_hw_breakpoint *b)
-{
-	if (a->address != b->address)
-		return false;
-	if (a->type != b->type)
-		return false;
-	if (a->len != b->len)
-		return false;
-	/* no need to check hw_len. it's calculated from address and len */
-	return true;
-}
-
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 
 static inline bool tm_enabled(struct task_struct *tsk)
@@ -1174,8 +1189,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
  * schedule DABR
  */
 #ifndef CONFIG_HAVE_HW_BREAKPOINT
-	if (unlikely(!hw_brk_match(this_cpu_ptr(&current_brk[0]), &new->thread.hw_brk)))
-		__set_breakpoint(0, &new->thread.hw_brk);
+	switch_hw_breakpoint(new);
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 #endif
 
diff --git a/arch/powerpc/kernel/ptrace/ptrace-noadv.c b/arch/powerpc/kernel/ptrace/ptrace-noadv.c
index 12962302d6a4..0dbb35392dd2 100644
--- a/arch/powerpc/kernel/ptrace/ptrace-noadv.c
+++ b/arch/powerpc/kernel/ptrace/ptrace-noadv.c
@@ -67,11 +67,16 @@ int ptrace_get_debugreg(struct task_struct *child, unsigned long addr,
 	/* We only support one DABR and no IABRS at the moment */
 	if (addr > 0)
 		return -EINVAL;
-	dabr_fake = ((child->thread.hw_brk.address & (~HW_BRK_TYPE_DABR)) |
-		     (child->thread.hw_brk.type & HW_BRK_TYPE_DABR));
+	dabr_fake = ((child->thread.hw_brk[0].address & (~HW_BRK_TYPE_DABR)) |
+		     (child->thread.hw_brk[0].type & HW_BRK_TYPE_DABR));
 	return put_user(dabr_fake, datalp);
 }
 
+/*
+ * ptrace_set_debugreg() fakes DABR and DABR is only one. So even if
+ * internal hw supports more than one watchpoint, we support only one
+ * watchpoint with this interface.
+ */
 int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned long data)
 {
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
@@ -137,7 +142,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned l
 			return ret;
 
 		thread->ptrace_bps[0] = bp;
-		thread->hw_brk = hw_brk;
+		thread->hw_brk[0] = hw_brk;
 		return 0;
 	}
 
@@ -159,12 +164,24 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned l
 	if (set_bp && (!ppc_breakpoint_available()))
 		return -ENODEV;
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
-	task->thread.hw_brk = hw_brk;
+	task->thread.hw_brk[0] = hw_brk;
 	return 0;
 }
 
+static int find_empty_hw_brk(struct thread_struct *thread)
+{
+	int i;
+
+	for (i = 0; i < nr_wp_slots(); i++) {
+		if (!thread->hw_brk[i].address)
+			return i;
+	}
+	return -1;
+}
+
 long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_info)
 {
+	int i;
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 	int len = 0;
 	struct thread_struct *thread = &child->thread;
@@ -223,15 +240,16 @@ long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_inf
 	if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
 		return -EINVAL;
 
-	if (child->thread.hw_brk.address)
+	i = find_empty_hw_brk(&child->thread);
+	if (i < 0)
 		return -ENOSPC;
 
 	if (!ppc_breakpoint_available())
 		return -ENODEV;
 
-	child->thread.hw_brk = brk;
+	child->thread.hw_brk[i] = brk;
 
-	return 1;
+	return i + 1;
 }
 
 long ppc_del_hwdebug(struct task_struct *child, long data)
@@ -241,7 +259,7 @@ long ppc_del_hwdebug(struct task_struct *child, long data)
 	struct thread_struct *thread = &child->thread;
 	struct perf_event *bp;
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
-	if (data != 1)
+	if (data < 1 || data > nr_wp_slots())
 		return -EINVAL;
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
@@ -254,11 +272,11 @@ long ppc_del_hwdebug(struct task_struct *child, long data)
 	}
 	return ret;
 #else /* CONFIG_HAVE_HW_BREAKPOINT */
-	if (child->thread.hw_brk.address == 0)
+	if (child->thread.hw_brk[data - 1].address == 0)
 		return -ENOENT;
 
-	child->thread.hw_brk.address = 0;
-	child->thread.hw_brk.type = 0;
+	child->thread.hw_brk[data - 1].address = 0;
+	child->thread.hw_brk[data - 1].type = 0;
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 
 	return 0;
diff --git a/arch/powerpc/kernel/ptrace/ptrace32.c b/arch/powerpc/kernel/ptrace/ptrace32.c
index 7976ddf29c0e..7589a9665ffb 100644
--- a/arch/powerpc/kernel/ptrace/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace/ptrace32.c
@@ -259,8 +259,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 		ret = put_user(child->thread.debug.dac1, (u32 __user *)data);
 #else
 		dabr_fake = (
-			(child->thread.hw_brk.address & (~HW_BRK_TYPE_DABR)) |
-			(child->thread.hw_brk.type & HW_BRK_TYPE_DABR));
+			(child->thread.hw_brk[0].address & (~HW_BRK_TYPE_DABR)) |
+			(child->thread.hw_brk[0].type & HW_BRK_TYPE_DABR));
 		ret = put_user(dabr_fake, (u32 __user *)data);
 #endif
 		break;
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index 8e29138a344a..b4143b6ff093 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -265,15 +265,20 @@ static void do_signal(struct task_struct *tsk)
 		return;               /* no signals delivered */
 	}
 
-#ifndef CONFIG_PPC_ADV_DEBUG_REGS
         /*
 	 * Reenable the DABR before delivering the signal to
 	 * user space. The DABR will have been cleared if it
 	 * triggered inside the kernel.
 	 */
-	if (tsk->thread.hw_brk.address && tsk->thread.hw_brk.type)
-		__set_breakpoint(0, &tsk->thread.hw_brk);
-#endif
+	if (!IS_ENABLED(CONFIG_PPC_ADV_DEBUG_REGS)) {
+		int i;
+
+		for (i = 0; i < nr_wp_slots(); i++) {
+			if (tsk->thread.hw_brk[i].address && tsk->thread.hw_brk[i].type)
+				__set_breakpoint(i, &tsk->thread.hw_brk[i]);
+		}
+	}
+
 	/* Re-enable the breakpoints for the signal stack */
 	thread_change_pc(tsk, tsk->thread.regs);
 
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 08/16] powerpc/watchpoint: Disable all available watchpoints when !dawr_force_enable
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

Instead of disabling only first watchpoint, disable all available
watchpoints while clearing dawr_force_enable.

Callback function is used only for disabling watchpoint, rename it
to disable_dawrs_cb(). And null_brk parameter is not really required
while disabling watchpoint, remove it.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/kernel/dawr.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/kernel/dawr.c b/arch/powerpc/kernel/dawr.c
index 8114ad3a8574..500f52fa4711 100644
--- a/arch/powerpc/kernel/dawr.c
+++ b/arch/powerpc/kernel/dawr.c
@@ -50,9 +50,13 @@ int set_dawr(int nr, struct arch_hw_breakpoint *brk)
 	return 0;
 }
 
-static void set_dawr_cb(void *info)
+static void disable_dawrs_cb(void *info)
 {
-	set_dawr(0, info);
+	struct arch_hw_breakpoint null_brk = {0};
+	int i;
+
+	for (i = 0; i < nr_wp_slots(); i++)
+		set_dawr(i, &null_brk);
 }
 
 static ssize_t dawr_write_file_bool(struct file *file,
@@ -74,7 +78,7 @@ static ssize_t dawr_write_file_bool(struct file *file,
 
 	/* If we are clearing, make sure all CPUs have the DAWR cleared */
 	if (!dawr_force_enable)
-		smp_call_function(set_dawr_cb, &null_brk, 0);
+		smp_call_function(disable_dawrs_cb, NULL, 0);
 
 	return rc;
 }
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 07/16] powerpc/watchpoint: Get watchpoint count dynamically while disabling them
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

Instead of disabling only one watchpoint, get num of available
watchpoints dynamically and disable all of them.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/include/asm/hw_breakpoint.h | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index 1120c7d9db58..d472b2eb757e 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -78,14 +78,14 @@ extern void ptrace_triggered(struct perf_event *bp,
 			struct perf_sample_data *data, struct pt_regs *regs);
 static inline void hw_breakpoint_disable(void)
 {
-	struct arch_hw_breakpoint brk;
-
-	brk.address = 0;
-	brk.type = 0;
-	brk.len = 0;
-	brk.hw_len = 0;
-	if (ppc_breakpoint_available())
-		__set_breakpoint(0, &brk);
+	int i;
+	struct arch_hw_breakpoint null_brk = {0};
+
+	if (!ppc_breakpoint_available())
+		return;
+
+	for (i = 0; i < nr_wp_slots(); i++)
+		__set_breakpoint(i, &null_brk);
 }
 extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs);
 int hw_breakpoint_handler(struct die_args *args);
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 06/16] powerpc/watchpoint: Provide DAWR number to __set_breakpoint
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

Introduce new parameter 'nr' to __set_breakpoint() which indicates
which DAWR should be programed. Also convert current_brk variable
to an array.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/include/asm/debug.h         |  2 +-
 arch/powerpc/include/asm/hw_breakpoint.h |  2 +-
 arch/powerpc/kernel/hw_breakpoint.c      |  8 ++++----
 arch/powerpc/kernel/process.c            | 14 +++++++-------
 arch/powerpc/kernel/signal.c             |  2 +-
 arch/powerpc/xmon/xmon.c                 |  2 +-
 6 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/arch/powerpc/include/asm/debug.h b/arch/powerpc/include/asm/debug.h
index 7756026b95ca..ec57daf87f40 100644
--- a/arch/powerpc/include/asm/debug.h
+++ b/arch/powerpc/include/asm/debug.h
@@ -45,7 +45,7 @@ static inline int debugger_break_match(struct pt_regs *regs) { return 0; }
 static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; }
 #endif
 
-void __set_breakpoint(struct arch_hw_breakpoint *brk);
+void __set_breakpoint(int nr, struct arch_hw_breakpoint *brk);
 bool ppc_breakpoint_available(void);
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
 extern void do_send_trap(struct pt_regs *regs, unsigned long address,
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index 5b3b02834e0b..1120c7d9db58 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -85,7 +85,7 @@ static inline void hw_breakpoint_disable(void)
 	brk.len = 0;
 	brk.hw_len = 0;
 	if (ppc_breakpoint_available())
-		__set_breakpoint(&brk);
+		__set_breakpoint(0, &brk);
 }
 extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs);
 int hw_breakpoint_handler(struct die_args *args);
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index 01f07d91df70..f5472402c06d 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -64,7 +64,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
 	 * If so, DABR will be populated in single_step_dabr_instruction().
 	 */
 	if (current->thread.last_hit_ubp != bp)
-		__set_breakpoint(info);
+		__set_breakpoint(0, info);
 
 	return 0;
 }
@@ -222,7 +222,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
 
 	info = counter_arch_bp(tsk->thread.last_hit_ubp);
 	regs->msr &= ~MSR_SE;
-	__set_breakpoint(info);
+	__set_breakpoint(0, info);
 	tsk->thread.last_hit_ubp = NULL;
 }
 
@@ -347,7 +347,7 @@ int hw_breakpoint_handler(struct die_args *args)
 	if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ))
 		perf_bp_event(bp, regs);
 
-	__set_breakpoint(info);
+	__set_breakpoint(0, info);
 out:
 	rcu_read_unlock();
 	return rc;
@@ -380,7 +380,7 @@ static int single_step_dabr_instruction(struct die_args *args)
 	if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ))
 		perf_bp_event(bp, regs);
 
-	__set_breakpoint(info);
+	__set_breakpoint(0, info);
 	current->thread.last_hit_ubp = NULL;
 
 	/*
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index dc161b0adc82..f303aea61794 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -637,7 +637,7 @@ void do_break (struct pt_regs *regs, unsigned long address,
 }
 #endif	/* CONFIG_PPC_ADV_DEBUG_REGS */
 
-static DEFINE_PER_CPU(struct arch_hw_breakpoint, current_brk);
+static DEFINE_PER_CPU(struct arch_hw_breakpoint, current_brk[HBP_NUM_MAX]);
 
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
 /*
@@ -714,7 +714,7 @@ EXPORT_SYMBOL_GPL(switch_booke_debug_regs);
 static void set_breakpoint(struct arch_hw_breakpoint *brk)
 {
 	preempt_disable();
-	__set_breakpoint(brk);
+	__set_breakpoint(0, brk);
 	preempt_enable();
 }
 
@@ -800,13 +800,13 @@ static inline int set_breakpoint_8xx(struct arch_hw_breakpoint *brk)
 	return 0;
 }
 
-void __set_breakpoint(struct arch_hw_breakpoint *brk)
+void __set_breakpoint(int nr, struct arch_hw_breakpoint *brk)
 {
-	memcpy(this_cpu_ptr(&current_brk), brk, sizeof(*brk));
+	memcpy(this_cpu_ptr(&current_brk[nr]), brk, sizeof(*brk));
 
 	if (dawr_enabled())
 		// Power8 or later
-		set_dawr(0, brk);
+		set_dawr(nr, brk);
 	else if (IS_ENABLED(CONFIG_PPC_8xx))
 		set_breakpoint_8xx(brk);
 	else if (!cpu_has_feature(CPU_FTR_ARCH_207S))
@@ -1174,8 +1174,8 @@ struct task_struct *__switch_to(struct task_struct *prev,
  * schedule DABR
  */
 #ifndef CONFIG_HAVE_HW_BREAKPOINT
-	if (unlikely(!hw_brk_match(this_cpu_ptr(&current_brk), &new->thread.hw_brk)))
-		__set_breakpoint(&new->thread.hw_brk);
+	if (unlikely(!hw_brk_match(this_cpu_ptr(&current_brk[0]), &new->thread.hw_brk)))
+		__set_breakpoint(0, &new->thread.hw_brk);
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 #endif
 
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index a46c3fdb6853..8e29138a344a 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -272,7 +272,7 @@ static void do_signal(struct task_struct *tsk)
 	 * triggered inside the kernel.
 	 */
 	if (tsk->thread.hw_brk.address && tsk->thread.hw_brk.type)
-		__set_breakpoint(&tsk->thread.hw_brk);
+		__set_breakpoint(0, &tsk->thread.hw_brk);
 #endif
 	/* Re-enable the breakpoints for the signal stack */
 	thread_change_pc(tsk, tsk->thread.regs);
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index effb10c2e32f..30b3e3d99c0d 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -954,7 +954,7 @@ static void insert_cpu_bpts(void)
 		brk.address = dabr.address;
 		brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
 		brk.len = DABR_MAX_LEN;
-		__set_breakpoint(&brk);
+		__set_breakpoint(0, &brk);
 	}
 
 	if (iabr)
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 05/16] powerpc/watchpoint: Provide DAWR number to set_dawr
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

Introduce new parameter 'nr' to set_dawr() which indicates which DAWR
should be programed.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/include/asm/hw_breakpoint.h |  4 ++--
 arch/powerpc/kernel/dawr.c               | 15 ++++++++++-----
 arch/powerpc/kernel/process.c            |  2 +-
 3 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index 518b41eef924..5b3b02834e0b 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -104,10 +104,10 @@ static inline bool dawr_enabled(void)
 {
 	return dawr_force_enable;
 }
-int set_dawr(struct arch_hw_breakpoint *brk);
+int set_dawr(int nr, struct arch_hw_breakpoint *brk);
 #else
 static inline bool dawr_enabled(void) { return false; }
-static inline int set_dawr(struct arch_hw_breakpoint *brk) { return -1; }
+static inline int set_dawr(int nr, struct arch_hw_breakpoint *brk) { return -1; }
 #endif
 
 #endif	/* __KERNEL__ */
diff --git a/arch/powerpc/kernel/dawr.c b/arch/powerpc/kernel/dawr.c
index e91b613bf137..8114ad3a8574 100644
--- a/arch/powerpc/kernel/dawr.c
+++ b/arch/powerpc/kernel/dawr.c
@@ -16,7 +16,7 @@
 bool dawr_force_enable;
 EXPORT_SYMBOL_GPL(dawr_force_enable);
 
-int set_dawr(struct arch_hw_breakpoint *brk)
+int set_dawr(int nr, struct arch_hw_breakpoint *brk)
 {
 	unsigned long dawr, dawrx, mrd;
 
@@ -39,15 +39,20 @@ int set_dawr(struct arch_hw_breakpoint *brk)
 	if (ppc_md.set_dawr)
 		return ppc_md.set_dawr(dawr, dawrx);
 
-	mtspr(SPRN_DAWR0, dawr);
-	mtspr(SPRN_DAWRX0, dawrx);
+	if (nr == 0) {
+		mtspr(SPRN_DAWR0, dawr);
+		mtspr(SPRN_DAWRX0, dawrx);
+	} else {
+		mtspr(SPRN_DAWR1, dawr);
+		mtspr(SPRN_DAWRX1, dawrx);
+	}
 
 	return 0;
 }
 
 static void set_dawr_cb(void *info)
 {
-	set_dawr(info);
+	set_dawr(0, info);
 }
 
 static ssize_t dawr_write_file_bool(struct file *file,
@@ -60,7 +65,7 @@ static ssize_t dawr_write_file_bool(struct file *file,
 	/* Send error to user if they hypervisor won't allow us to write DAWR */
 	if (!dawr_force_enable &&
 	    firmware_has_feature(FW_FEATURE_LPAR) &&
-	    set_dawr(&null_brk) != H_SUCCESS)
+	    set_dawr(0, &null_brk) != H_SUCCESS)
 		return -ENODEV;
 
 	rc = debugfs_write_file_bool(file, user_buf, count, ppos);
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index db766252238f..dc161b0adc82 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -806,7 +806,7 @@ void __set_breakpoint(struct arch_hw_breakpoint *brk)
 
 	if (dawr_enabled())
 		// Power8 or later
-		set_dawr(brk);
+		set_dawr(0, brk);
 	else if (IS_ENABLED(CONFIG_PPC_8xx))
 		set_breakpoint_8xx(brk);
 	else if (!cpu_has_feature(CPU_FTR_ARCH_207S))
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 04/16] powerpc/watchpoint/ptrace: Return actual num of available watchpoints
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

User can ask for num of available watchpoints(dbginfo.num_data_bps)
using ptrace(PPC_PTRACE_GETHWDBGINFO). Return actual number of
available watchpoints on the machine rather than hardcoded 1.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/kernel/ptrace/ptrace-noadv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/kernel/ptrace/ptrace-noadv.c b/arch/powerpc/kernel/ptrace/ptrace-noadv.c
index f87e7c5c3bf3..12962302d6a4 100644
--- a/arch/powerpc/kernel/ptrace/ptrace-noadv.c
+++ b/arch/powerpc/kernel/ptrace/ptrace-noadv.c
@@ -44,7 +44,7 @@ void ppc_gethwdinfo(struct ppc_debug_info *dbginfo)
 	dbginfo->version = 1;
 	dbginfo->num_instruction_bps = 0;
 	if (ppc_breakpoint_available())
-		dbginfo->num_data_bps = 1;
+		dbginfo->num_data_bps = nr_wp_slots();
 	else
 		dbginfo->num_data_bps = 0;
 	dbginfo->num_condition_regs = 0;
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 03/16] powerpc/watchpoint: Introduce function to get nr watchpoints dynamically
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

So far we had only one watchpoint, so we have hardcoded HBP_NUM to 1.
But Power10 is introducing 2nd DAWR and thus kernel should be able to
dynamically find actual number of watchpoints supported by hw it's
running on. Introduce function for the same. Also convert HBP_NUM macro
to HBP_NUM_MAX, which will now represent maximum number of watchpoints
supported by Powerpc.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/include/asm/cputable.h      | 6 +++++-
 arch/powerpc/include/asm/hw_breakpoint.h | 5 +++++
 arch/powerpc/include/asm/processor.h     | 2 +-
 arch/powerpc/kernel/hw_breakpoint.c      | 2 +-
 4 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 40a4d3c6fd99..c67b94f3334c 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -614,7 +614,11 @@ enum {
 };
 #endif /* __powerpc64__ */
 
-#define HBP_NUM 1
+/*
+ * Maximum number of hw breakpoint supported on powerpc. Number of
+ * breakpoints supported by actual hw might be less than this.
+ */
+#define HBP_NUM_MAX	1
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index f2f8d8aa8e3b..518b41eef924 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -43,6 +43,11 @@ struct arch_hw_breakpoint {
 #define DABR_MAX_LEN	8
 #define DAWR_MAX_LEN	512
 
+static inline int nr_wp_slots(void)
+{
+	return HBP_NUM_MAX;
+}
+
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 #include <linux/kdebug.h>
 #include <asm/reg.h>
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 5ab202055d5a..f209c5703ee2 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -180,7 +180,7 @@ struct thread_struct {
 	int		fpexc_mode;	/* floating-point exception mode */
 	unsigned int	align_ctl;	/* alignment handling control */
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
-	struct perf_event *ptrace_bps[HBP_NUM];
+	struct perf_event *ptrace_bps[HBP_NUM_MAX];
 	/*
 	 * Helps identify source of single-step exception and subsequent
 	 * hw-breakpoint enablement
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index 423603c92c0f..01f07d91df70 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -39,7 +39,7 @@ static DEFINE_PER_CPU(struct perf_event *, bp_per_reg);
 int hw_breakpoint_slots(int type)
 {
 	if (type == TYPE_DATA)
-		return HBP_NUM;
+		return nr_wp_slots();
 	return 0;		/* no instruction breakpoints available */
 }
 
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 02/16] powerpc/watchpoint: Add SPRN macros for second DAWR
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

Power10 is introducing second DAWR. Add SPRN_ macros for the same.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/include/asm/reg.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 60a21b6b2057..054f8a71d686 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -284,6 +284,7 @@
 #define   CTRL_TE	0x00c00000	/* thread enable */
 #define   CTRL_RUNLATCH	0x1
 #define SPRN_DAWR0	0xB4
+#define SPRN_DAWR1	0xB5
 #define SPRN_RPR	0xBA	/* Relative Priority Register */
 #define SPRN_CIABR	0xBB
 #define   CIABR_PRIV		0x3
@@ -291,6 +292,7 @@
 #define   CIABR_PRIV_SUPER	2
 #define   CIABR_PRIV_HYPER	3
 #define SPRN_DAWRX0	0xBC
+#define SPRN_DAWRX1	0xBD
 #define   DAWRX_USER	__MASK(0)
 #define   DAWRX_KERNEL	__MASK(1)
 #define   DAWRX_HYP	__MASK(2)
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 01/16] powerpc/watchpoint: Rename current DAWR macros
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo
In-Reply-To: <20200514111741.97993-1-ravi.bangoria@linux.ibm.com>

Power10 is introducing second DAWR. Use real register names from ISA
for current macros:
  s/SPRN_DAWR/SPRN_DAWR0/
  s/SPRN_DAWRX/SPRN_DAWRX0/

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Michael Neuling <mikey@neuling.org>
---
 arch/powerpc/include/asm/reg.h          |  4 ++--
 arch/powerpc/kernel/dawr.c              |  4 ++--
 arch/powerpc/kvm/book3s_hv.c            | 12 ++++++------
 arch/powerpc/kvm/book3s_hv_rmhandlers.S | 18 +++++++++---------
 arch/powerpc/xmon/xmon.c                |  2 +-
 5 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index f95eb8f97756..60a21b6b2057 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -283,14 +283,14 @@
 #define   CTRL_CT1	0x40000000	/* thread 1 */
 #define   CTRL_TE	0x00c00000	/* thread enable */
 #define   CTRL_RUNLATCH	0x1
-#define SPRN_DAWR	0xB4
+#define SPRN_DAWR0	0xB4
 #define SPRN_RPR	0xBA	/* Relative Priority Register */
 #define SPRN_CIABR	0xBB
 #define   CIABR_PRIV		0x3
 #define   CIABR_PRIV_USER	1
 #define   CIABR_PRIV_SUPER	2
 #define   CIABR_PRIV_HYPER	3
-#define SPRN_DAWRX	0xBC
+#define SPRN_DAWRX0	0xBC
 #define   DAWRX_USER	__MASK(0)
 #define   DAWRX_KERNEL	__MASK(1)
 #define   DAWRX_HYP	__MASK(2)
diff --git a/arch/powerpc/kernel/dawr.c b/arch/powerpc/kernel/dawr.c
index cc14aa6c4a1b..e91b613bf137 100644
--- a/arch/powerpc/kernel/dawr.c
+++ b/arch/powerpc/kernel/dawr.c
@@ -39,8 +39,8 @@ int set_dawr(struct arch_hw_breakpoint *brk)
 	if (ppc_md.set_dawr)
 		return ppc_md.set_dawr(dawr, dawrx);
 
-	mtspr(SPRN_DAWR, dawr);
-	mtspr(SPRN_DAWRX, dawrx);
+	mtspr(SPRN_DAWR0, dawr);
+	mtspr(SPRN_DAWRX0, dawrx);
 
 	return 0;
 }
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 93493f0cbfe8..db07199f0977 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -3392,8 +3392,8 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
 	int trap;
 	unsigned long host_hfscr = mfspr(SPRN_HFSCR);
 	unsigned long host_ciabr = mfspr(SPRN_CIABR);
-	unsigned long host_dawr = mfspr(SPRN_DAWR);
-	unsigned long host_dawrx = mfspr(SPRN_DAWRX);
+	unsigned long host_dawr = mfspr(SPRN_DAWR0);
+	unsigned long host_dawrx = mfspr(SPRN_DAWRX0);
 	unsigned long host_psscr = mfspr(SPRN_PSSCR);
 	unsigned long host_pidr = mfspr(SPRN_PID);
 
@@ -3422,8 +3422,8 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
 	mtspr(SPRN_SPURR, vcpu->arch.spurr);
 
 	if (dawr_enabled()) {
-		mtspr(SPRN_DAWR, vcpu->arch.dawr);
-		mtspr(SPRN_DAWRX, vcpu->arch.dawrx);
+		mtspr(SPRN_DAWR0, vcpu->arch.dawr);
+		mtspr(SPRN_DAWRX0, vcpu->arch.dawrx);
 	}
 	mtspr(SPRN_CIABR, vcpu->arch.ciabr);
 	mtspr(SPRN_IC, vcpu->arch.ic);
@@ -3475,8 +3475,8 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
 	      (local_paca->kvm_hstate.fake_suspend << PSSCR_FAKE_SUSPEND_LG));
 	mtspr(SPRN_HFSCR, host_hfscr);
 	mtspr(SPRN_CIABR, host_ciabr);
-	mtspr(SPRN_DAWR, host_dawr);
-	mtspr(SPRN_DAWRX, host_dawrx);
+	mtspr(SPRN_DAWR0, host_dawr);
+	mtspr(SPRN_DAWRX0, host_dawrx);
 	mtspr(SPRN_PID, host_pidr);
 
 	/*
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 780a499c7114..70de3325d0e9 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -707,8 +707,8 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
 BEGIN_FTR_SECTION
 	mfspr	r5, SPRN_CIABR
-	mfspr	r6, SPRN_DAWR
-	mfspr	r7, SPRN_DAWRX
+	mfspr	r6, SPRN_DAWR0
+	mfspr	r7, SPRN_DAWRX0
 	mfspr	r8, SPRN_IAMR
 	std	r5, STACK_SLOT_CIABR(r1)
 	std	r6, STACK_SLOT_DAWR(r1)
@@ -803,8 +803,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
 	beq	1f
 	ld	r5, VCPU_DAWR(r4)
 	ld	r6, VCPU_DAWRX(r4)
-	mtspr	SPRN_DAWR, r5
-	mtspr	SPRN_DAWRX, r6
+	mtspr	SPRN_DAWR0, r5
+	mtspr	SPRN_DAWRX0, r6
 1:
 	ld	r7, VCPU_CIABR(r4)
 	ld	r8, VCPU_TAR(r4)
@@ -1766,8 +1766,8 @@ BEGIN_FTR_SECTION
 	 * If the DAWR doesn't work, it's ok to write these here as
 	 * this value should always be zero
 	*/
-	mtspr	SPRN_DAWR, r6
-	mtspr	SPRN_DAWRX, r7
+	mtspr	SPRN_DAWR0, r6
+	mtspr	SPRN_DAWRX0, r7
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 BEGIN_FTR_SECTION
 	ld	r5, STACK_SLOT_TID(r1)
@@ -2577,8 +2577,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 	mfmsr	r6
 	andi.	r6, r6, MSR_DR		/* in real mode? */
 	bne	4f
-	mtspr	SPRN_DAWR, r4
-	mtspr	SPRN_DAWRX, r5
+	mtspr	SPRN_DAWR0, r4
+	mtspr	SPRN_DAWRX0, r5
 4:	li	r3, 0
 	blr
 
@@ -3329,7 +3329,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
 	mtspr	SPRN_AMR, r0
 	mtspr	SPRN_IAMR, r0
 	mtspr	SPRN_CIABR, r0
-	mtspr	SPRN_DAWRX, r0
+	mtspr	SPRN_DAWRX0, r0
 
 BEGIN_MMU_FTR_SECTION
 	b	4f
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index d1a79f9e0566..effb10c2e32f 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -1956,7 +1956,7 @@ static void dump_207_sprs(void)
 	printf("hfscr  = %.16lx  dhdes = %.16lx rpr    = %.16lx\n",
 		mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
 	printf("dawr   = %.16lx  dawrx = %.16lx ciabr  = %.16lx\n",
-		mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
+		mfspr(SPRN_DAWR0), mfspr(SPRN_DAWRX0), mfspr(SPRN_CIABR));
 #endif
 }
 
-- 
2.26.2


^ permalink raw reply related

* [PATCH v6 00/16] powerpc/watchpoint: Preparation for more than one watchpoint
From: Ravi Bangoria @ 2020-05-14 11:17 UTC (permalink / raw)
  To: mpe, mikey
  Cc: christophe.leroy, apopple, ravi.bangoria, peterz, fweisbec, oleg,
	npiggin, linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev,
	mingo

So far, powerpc Book3S code has been written with an assumption of
only one watchpoint. But Power10[1] is introducing second watchpoint
register (DAWR). Even though this patchset does not enable 2nd DAWR,
it makes the infrastructure ready so that enabling 2nd DAWR should
just be a matter of changing count.

Existing functionality works fine with the patchset. I've tested it
with perf, ptrace(gdb), xmon. All hw-breakpoint selftests are passing
as well. And I've build tested for 8xx and 'AMCC 44x, 46x or 47x'.

Note: kvm or PowerVM guest is not enabled yet.

v5: https://lore.kernel.org/linuxppc-dev/20200511025911.212827-1-ravi.bangoria@linux.ibm.com 

v5->v6:
 - Rebased to powerpc/next-test which has prefix-instruction support
 - Adopt 'struct ppc_inst' in hw-breakpoint code as well

[1]: https://www-355.ibm.com/systems/power/openpower/

Ravi Bangoria (16):
  powerpc/watchpoint: Rename current DAWR macros
  powerpc/watchpoint: Add SPRN macros for second DAWR
  powerpc/watchpoint: Introduce function to get nr watchpoints
    dynamically
  powerpc/watchpoint/ptrace: Return actual num of available watchpoints
  powerpc/watchpoint: Provide DAWR number to set_dawr
  powerpc/watchpoint: Provide DAWR number to __set_breakpoint
  powerpc/watchpoint: Get watchpoint count dynamically while disabling
    them
  powerpc/watchpoint: Disable all available watchpoints when
    !dawr_force_enable
  powerpc/watchpoint: Convert thread_struct->hw_brk to an array
  powerpc/watchpoint: Use loop for thread_struct->ptrace_bps
  powerpc/watchpoint: Introduce is_ptrace_bp() function
  powerpc/watchpoint: Use builtin ALIGN*() macros
  powerpc/watchpoint: Prepare handler to handle more than one
    watcnhpoint
  powerpc/watchpoint: Don't allow concurrent perf and ptrace events
  powerpc/watchpoint/xmon: Don't allow breakpoint overwriting
  powerpc/watchpoint/xmon: Support 2nd DAWR

 arch/powerpc/include/asm/cputable.h       |   6 +-
 arch/powerpc/include/asm/debug.h          |   2 +-
 arch/powerpc/include/asm/hw_breakpoint.h  |  32 +-
 arch/powerpc/include/asm/processor.h      |   6 +-
 arch/powerpc/include/asm/reg.h            |   6 +-
 arch/powerpc/include/asm/sstep.h          |   2 +
 arch/powerpc/kernel/dawr.c                |  23 +-
 arch/powerpc/kernel/hw_breakpoint.c       | 642 ++++++++++++++++++----
 arch/powerpc/kernel/process.c             |  85 +--
 arch/powerpc/kernel/ptrace/ptrace-noadv.c |  72 ++-
 arch/powerpc/kernel/ptrace/ptrace32.c     |   4 +-
 arch/powerpc/kernel/signal.c              |  13 +-
 arch/powerpc/kvm/book3s_hv.c              |  12 +-
 arch/powerpc/kvm/book3s_hv_rmhandlers.S   |  18 +-
 arch/powerpc/xmon/xmon.c                  |  99 +++-
 kernel/events/hw_breakpoint.c             |  16 +
 16 files changed, 811 insertions(+), 227 deletions(-)

-- 
2.26.2


^ permalink raw reply

* Re: [PATCH v8 00/30] Initial Prefixed Instruction support
From: Jordan Niethe @ 2020-05-14 10:33 UTC (permalink / raw)
  To: Christophe Leroy
  Cc: Alistair Popple, Nicholas Piggin, Balamuruhan S, naveen.n.rao,
	linuxppc-dev, Daniel Axtens
In-Reply-To: <d5d59817-6e90-5643-6405-2b2794348684@csgroup.eu>

On Thu, May 14, 2020 at 3:31 PM Christophe Leroy
<christophe.leroy@csgroup.eu> wrote:
>
>
>
> Le 06/05/2020 à 05:40, Jordan Niethe a écrit :
> > A future revision of the ISA will introduce prefixed instructions. A
> > prefixed instruction is composed of a 4-byte prefix followed by a
> > 4-byte suffix.
> >
> > All prefixes have the major opcode 1. A prefix will never be a valid
> > word instruction. A suffix may be an existing word instruction or a
> > new instruction.
> >
> > This series enables prefixed instructions and extends the instruction
> > emulation to support them. Then the places where prefixed instructions
> > might need to be emulated are updated.
> >
> > v8 incorporates feedback from Alistair Popple and Balamuruhan Suriyakumar.
> > The major changes:
> >      - Fix some style issues
> >      - Fix __patch_instruction() on big endian
> >      - Reintroduce v3's forbidding breakpoints on second word of prefix
> >        instructions for kprobes and xmon. Missed this when changing to
> >        using a data type.
> >      - Use the data type in some places that were missed.
>
> Checkpatch seems to report the following warnings for pmac32_defconfig,
> are they harmless ?
>
> +arch/powerpc/kernel/align.c:307:13: warning: cast removes address space
> '<asn:1>' of expression
> +arch/powerpc/kernel/align.c:307:13: warning: cast removes address space
> '<asn:1>' of expression
> +arch/powerpc/kernel/align.c:307:13: warning: cast removes address space
> '<asn:1>' of expression
> +arch/powerpc/kernel/align.c:307:13: warning: cast removes address space
> '<asn:1>' of expression
> +arch/powerpc/kernel/align.c:307:13: warning: cast removes address space
> '<asn:1>' of expression
> +arch/powerpc/kernel/align.c:307:13: warning: incorrect type in argument
> 1 (different address spaces) expected void const volatile [noderef]
> <asn:1> * got unsigned int [usertype] *
> +arch/powerpc/kernel/align.c:307:13: warning: incorrect type in
> initializer (different address spaces) expected unsigned int [noderef]
> <asn:1> *__gu_addr got unsigned int [usertype] *
> +arch/powerpc/kernel/hw_breakpoint.c:XX:13: warning: cast removes
> address space '<asn:1>' of expression
> +arch/powerpc/kernel/hw_breakpoint.c:XX:13: warning: cast removes
> address space '<asn:1>' of expression
> +arch/powerpc/kernel/hw_breakpoint.c:XX:13: warning: cast removes
> address space '<asn:1>' of expression
> +arch/powerpc/kernel/hw_breakpoint.c:XX:13: warning: cast removes
> address space '<asn:1>' of expression
> +arch/powerpc/kernel/hw_breakpoint.c:XX:13: warning: cast removes
> address space '<asn:1>' of expression
> -arch/powerpc/kernel/hw_breakpoint.c:XX:13: warning: incorrect type in
> argument 1 (different address spaces) expected void const volatile
> [noderef] <asn:1> * got unsigned int *
> +arch/powerpc/kernel/hw_breakpoint.c:XX:13: warning: incorrect type in
> argument 1 (different address spaces) expected void const volatile
> [noderef] <asn:1> * got unsigned int [usertype] *
> -arch/powerpc/kernel/hw_breakpoint.c:XX:13: warning: incorrect type in
> initializer (different address spaces) expected unsigned int [noderef]
> <asn:1> *__gu_addr got unsigned int *
> +arch/powerpc/kernel/hw_breakpoint.c:XX:13: warning: incorrect type in
> initializer (different address spaces) expected unsigned int [noderef]
> <asn:1> *__gu_addr got unsigned int [usertype] *
> +arch/powerpc/kernel/vecemu.c:269:13: warning: cast removes address
> space '<asn:1>' of expression
> +arch/powerpc/kernel/vecemu.c:269:13: warning: cast removes address
> space '<asn:1>' of expression
> +arch/powerpc/kernel/vecemu.c:269:13: warning: cast removes address
> space '<asn:1>' of expression
> +arch/powerpc/kernel/vecemu.c:269:13: warning: cast removes address
> space '<asn:1>' of expression
> +arch/powerpc/kernel/vecemu.c:269:13: warning: cast removes address
> space '<asn:1>' of expression
> +arch/powerpc/kernel/vecemu.c:269:13: warning: incorrect type in
> argument 1 (different address spaces) expected void const volatile
> [noderef] <asn:1> * got unsigned int [usertype] *
> +arch/powerpc/kernel/vecemu.c:269:13: warning: incorrect type in
> initializer (different address spaces) expected unsigned int [noderef]
> <asn:1> *__gu_addr got unsigned int [usertype] *
> +arch/powerpc/lib/inst.c:55:37: warning: incorrect type in argument 2
> (different address spaces) expected void const [noderef] <asn:1> *src
> got struct ppc_inst *nip
> +arch/powerpc/mm/fault.c:284:59: warning: incorrect type in argument 2
> (different address spaces) expected struct ppc_inst *nip got struct
> ppc_inst [noderef] <asn:1> *
Thanks, I was missing some __user.
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -106,10 +106,10 @@ static inline int __access_ok(unsigned long
addr, unsigned long size,
        __put_user_nosleep((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))

 #define __get_user_instr(x, ptr) \
-       __get_user_nocheck((x).val, (u32 *)(ptr), sizeof(u32), true)
+       __get_user_nocheck((x).val, (u32 __user *)(ptr), sizeof(u32), true)

 #define __get_user_instr_inatomic(x, ptr) \
-       __get_user_nosleep((x).val, (u32 *)(ptr), sizeof(u32))
+       __get_user_nosleep((x).val, (u32 __user *)(ptr), sizeof(u32))
 extern long __put_user_bad(void);

 /*

--- a/arch/powerpc/include/asm/inst.h
+++ b/arch/powerpc/include/asm/inst.h
@@ -38,6 +38,6 @@ static inline bool ppc_inst_equal(struct ppc_inst x,
struct ppc_inst y)
 }

 int probe_user_read_inst(struct ppc_inst *inst,
-                        struct ppc_inst *nip);
+                        struct ppc_inst __user *nip);

 #endif /* _ASM_INST_H */
diff --git a/arch/powerpc/lib/inst.c b/arch/powerpc/lib/inst.c
index eaf786afad2b..c15611086d26 100644
--- a/arch/powerpc/lib/inst.c
+++ b/arch/powerpc/lib/inst.c
@@ -7,7 +7,7 @@
 #include <asm/inst.h>

 int probe_user_read_inst(struct ppc_inst *inst,
-                        struct ppc_inst *nip)
+                        struct ppc_inst __user *nip)
 {
        unsigned int val;
        int err;


>
> Christophe
>
> >
> > v7 fixes compilation issues for some configs reported by Alistair
> > Popple.
> >
> > v6 is based on feedback from Balamuruhan Suriyakumar, Alistair Popple,
> > Christophe Leroy and Segher Boessenkool.
> > The major changes:
> >      - Use the instruction type in more places that had been missed before
> >      - Fix issues with ppc32
> >      - Introduce new self tests for code patching and feature fixups
> >
> > v5 is based on feedback from Nick Piggins, Michael Ellerman, Balamuruhan
> > Suriyakumar and Alistair Popple.
> > The major changes:
> >      - The ppc instruction type is now a struct
> >      - Series now just based on next
> >      - ppc_inst_masked() dropped
> >      - Space for xmon breakpoints allocated in an assembly file
> >      - "Add prefixed instructions to instruction data type" patch seperated in
> >        to smaller patches
> >      - Calling convention for create_branch() is changed
> >      - Some places which had not been updated to use the data type are now updated
> >
> > v4 is based on feedback from Nick Piggins, Christophe Leroy and Daniel Axtens.
> > The major changes:
> >      - Move xmon breakpoints from data section to text section
> >      - Introduce a data type for instructions on powerpc
> >
> > v3 is based on feedback from Christophe Leroy. The major changes:
> >      - Completely replacing store_inst() with patch_instruction() in
> >        xmon
> >      - Improve implementation of mread_instr() to not use mread().
> >      - Base the series on top of
> >        https://patchwork.ozlabs.org/patch/1232619/ as this will effect
> >        kprobes.
> >      - Some renaming and simplification of conditionals.
> >
> > v2 incorporates feedback from Daniel Axtens and and Balamuruhan
> > S. The major changes are:
> >      - Squashing together all commits about SRR1 bits
> >      - Squashing all commits for supporting prefixed load stores
> >      - Changing abbreviated references to sufx/prfx -> suffix/prefix
> >      - Introducing macros for returning the length of an instruction
> >      - Removing sign extension flag from pstd/pld in sstep.c
> >      - Dropping patch  "powerpc/fault: Use analyse_instr() to check for
> >        store with updates to sp" from the series, it did not really fit
> >        with prefixed enablement in the first place and as reported by Greg
> >        Kurz did not work correctly.
> >
> >
> > Alistair Popple (1):
> >    powerpc: Enable Prefixed Instructions
> >
> > Jordan Niethe (29):
> >    powerpc/xmon: Remove store_inst() for patch_instruction()
> >    powerpc/xmon: Move breakpoint instructions to own array
> >    powerpc/xmon: Move breakpoints to text section
> >    powerpc/xmon: Use bitwise calculations in_breakpoint_table()
> >    powerpc: Change calling convention for create_branch() et. al.
> >    powerpc: Use a macro for creating instructions from u32s
> >    powerpc: Use an accessor for instructions
> >    powerpc: Use a function for getting the instruction op code
> >    powerpc: Use a function for byte swapping instructions
> >    powerpc: Introduce functions for instruction equality
> >    powerpc: Use a datatype for instructions
> >    powerpc: Use a function for reading instructions
> >    powerpc: Add a probe_user_read_inst() function
> >    powerpc: Add a probe_kernel_read_inst() function
> >    powerpc/kprobes: Use patch_instruction()
> >    powerpc: Define and use __get_user_instr{,inatomic}()
> >    powerpc: Introduce a function for reporting instruction length
> >    powerpc/xmon: Use a function for reading instructions
> >    powerpc/xmon: Move insertion of breakpoint for xol'ing
> >    powerpc: Make test_translate_branch() independent of instruction
> >      length
> >    powerpc: Define new SRR1 bits for a future ISA version
> >    powerpc: Add prefixed instructions to instruction data type
> >    powerpc: Test prefixed code patching
> >    powerpc: Test prefixed instructions in feature fixups
> >    powerpc/xmon: Don't allow breakpoints on suffixes
> >    powerpc/kprobes: Don't allow breakpoints on suffixes
> >    powerpc: Support prefixed instructions in alignment handler
> >    powerpc sstep: Add support for prefixed load/stores
> >    powerpc sstep: Add support for prefixed fixed-point arithmetic
> >
> >   arch/powerpc/include/asm/code-patching.h  |  37 +-
> >   arch/powerpc/include/asm/inst.h           | 107 +++++
> >   arch/powerpc/include/asm/kprobes.h        |   2 +-
> >   arch/powerpc/include/asm/ppc-opcode.h     |   3 +
> >   arch/powerpc/include/asm/reg.h            |   7 +-
> >   arch/powerpc/include/asm/sstep.h          |  15 +-
> >   arch/powerpc/include/asm/uaccess.h        |  43 ++
> >   arch/powerpc/include/asm/uprobes.h        |   7 +-
> >   arch/powerpc/kernel/align.c               |  13 +-
> >   arch/powerpc/kernel/asm-offsets.c         |   8 +
> >   arch/powerpc/kernel/crash_dump.c          |   7 +-
> >   arch/powerpc/kernel/epapr_paravirt.c      |   7 +-
> >   arch/powerpc/kernel/hw_breakpoint.c       |   5 +-
> >   arch/powerpc/kernel/jump_label.c          |   5 +-
> >   arch/powerpc/kernel/kgdb.c                |   9 +-
> >   arch/powerpc/kernel/kprobes.c             |  37 +-
> >   arch/powerpc/kernel/mce_power.c           |   5 +-
> >   arch/powerpc/kernel/module_64.c           |   3 +-
> >   arch/powerpc/kernel/optprobes.c           | 102 +++--
> >   arch/powerpc/kernel/optprobes_head.S      |   3 +
> >   arch/powerpc/kernel/security.c            |  12 +-
> >   arch/powerpc/kernel/setup_32.c            |   8 +-
> >   arch/powerpc/kernel/trace/ftrace.c        | 168 ++++----
> >   arch/powerpc/kernel/traps.c               |  20 +-
> >   arch/powerpc/kernel/uprobes.c             |   5 +-
> >   arch/powerpc/kernel/vecemu.c              |  20 +-
> >   arch/powerpc/kvm/book3s_hv_nested.c       |   2 +-
> >   arch/powerpc/kvm/book3s_hv_rm_mmu.c       |   2 +-
> >   arch/powerpc/kvm/emulate_loadstore.c      |   2 +-
> >   arch/powerpc/lib/Makefile                 |   2 +-
> >   arch/powerpc/lib/code-patching.c          | 319 +++++++++------
> >   arch/powerpc/lib/feature-fixups-test.S    |  69 ++++
> >   arch/powerpc/lib/feature-fixups.c         | 160 ++++++--
> >   arch/powerpc/lib/inst.c                   |  70 ++++
> >   arch/powerpc/lib/sstep.c                  | 459 +++++++++++++++-------
> >   arch/powerpc/lib/test_code-patching.S     |  20 +
> >   arch/powerpc/lib/test_emulate_step.c      |  56 +--
> >   arch/powerpc/mm/fault.c                   |  15 +-
> >   arch/powerpc/mm/nohash/8xx.c              |   5 +-
> >   arch/powerpc/perf/8xx-pmu.c               |   9 +-
> >   arch/powerpc/perf/core-book3s.c           |   4 +-
> >   arch/powerpc/platforms/86xx/mpc86xx_smp.c |   5 +-
> >   arch/powerpc/platforms/powermac/smp.c     |   5 +-
> >   arch/powerpc/xmon/Makefile                |   2 +-
> >   arch/powerpc/xmon/xmon.c                  | 122 ++++--
> >   arch/powerpc/xmon/xmon_bpts.S             |  11 +
> >   arch/powerpc/xmon/xmon_bpts.h             |  14 +
> >   47 files changed, 1409 insertions(+), 602 deletions(-)
> >   create mode 100644 arch/powerpc/include/asm/inst.h
> >   create mode 100644 arch/powerpc/lib/inst.c
> >   create mode 100644 arch/powerpc/lib/test_code-patching.S
> >   create mode 100644 arch/powerpc/xmon/xmon_bpts.S
> >   create mode 100644 arch/powerpc/xmon/xmon_bpts.h
> >

^ permalink raw reply related

* Re: [PATCH RFC 1/4] powerpc/radix: Fix compilation for radix with CONFIG_SMP=n
From: Joel Stanley @ 2020-05-14  8:26 UTC (permalink / raw)
  To: Nicholas Piggin; +Cc: linuxppc-dev, Michael Neuling, Benjamin Herrenschmidt
In-Reply-To: <1589010661.v7yharjogg.astroid@bobo.none>

On Sat, 9 May 2020 at 07:52, Nicholas Piggin <npiggin@gmail.com> wrote:
>
> Excerpts from Paul Mackerras's message of May 9, 2020 3:02 pm:
> > This fixes the compile errors we currently get with CONFIG_SMP=n and
> > CONFIG_PPC_RADIX_MMU=y.
>
> Did I already fix this, or does it keep getting broken?! :(
>
> Anyway fine by me if it's required.

You're right, your fix was merged in 5.7-rc1.

Cheers,

Joel

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox