Tiejun Chen wrote:
> When kprobe these operations such as store-and-update-word for SP(r1),
> 
> stwu r1, -A(r1)
> 
> The program exception is triggered, and PPC always allocate an exception frame
> as shown as the follows:
> 
> old r1 ----------
>          ...
>          nip
>          gpr[2] ~ gpr[31]
>          gpr[1] <--------- old r1 is stored.
>          gpr[0]
>        -------- <--------- pr_regs @offset 16 bytes
>        padding
>        STACK_FRAME_REGS_MARKER
>        LR
>        back chain
> new r1 ----------
> Then emulate_step() will emulate this instruction, 'stwu'. Actually its
> equivalent to:
> 1> Update pr_regs->gpr[1] = mem[old r1 + (-A)]
> 2> stw [old r1], mem[old r1 + (-A)]
> 
> Please notice the stack based on new r1 may be covered with mem[old r1
> +(-A)] when addr[old r1 + (-A)] < addr[old r1 + sizeof(an exception frame0].
> So the above 2# operation will overwirte something to break this exception
> frame then unexpected kernel problem will be issued.
> 
> So looks we have to implement independed interrupt stack for PPC program
> exception when CONFIG_BOOKE is enabled. Here we can use
> EXC_LEVEL_EXCEPTION_PROLOG to replace original NORMAL_EXCEPTION_PROLOG
> for program exception if CONFIG_BOOKE. Then its always safe for kprobe
> with independed exc stack from one pre-allocated and dedicated thread_info.
> Actually this is just waht we did for critical/machine check exceptions
> on PPC.
> 
> Signed-off-by: Tiejun Chen <tiejun.c...@windriver.com>
> ---
>  arch/powerpc/include/asm/irq.h   |    3 +++
>  arch/powerpc/include/asm/reg.h   |    4 ++++
>  arch/powerpc/kernel/entry_32.S   |   15 +++++++++++++++
>  arch/powerpc/kernel/head_booke.h |   15 +++++++++++++--
>  arch/powerpc/kernel/irq.c        |   11 +++++++++++
>  arch/powerpc/kernel/setup_32.c   |    4 ++++
>  6 files changed, 50 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
> index 1bff591..6d12169 100644
> --- a/arch/powerpc/include/asm/irq.h
> +++ b/arch/powerpc/include/asm/irq.h
> @@ -313,6 +313,9 @@ struct pt_regs;
>  extern struct thread_info *critirq_ctx[NR_CPUS];
>  extern struct thread_info *dbgirq_ctx[NR_CPUS];
>  extern struct thread_info *mcheckirq_ctx[NR_CPUS];
> +#if defined(CONFIG_KPROBES) && defined(CONFIG_BOOKE)
> +extern struct thread_info *pgirq_ctx[NR_CPUS];
> +#endif
>  extern void exc_lvl_ctx_init(void);
>  #else
>  #define exc_lvl_ctx_init()
> diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
> index c5cae0d..34d6178 100644
> --- a/arch/powerpc/include/asm/reg.h
> +++ b/arch/powerpc/include/asm/reg.h
> @@ -885,6 +885,10 @@
>  #endif
>  #define SPRN_SPRG_RVCPU              SPRN_SPRG1
>  #define SPRN_SPRG_WVCPU              SPRN_SPRG1
> +#ifdef       CONFIG_KPROBES
> +#define      SPRN_SPRG_RSCRATCH_PG   SPRN_SPRG0
> +#define      SPRN_SPRG_WSCRATCH_PG   SPRN_SPRG0
> +#endif
>  #endif
>  
>  #ifdef CONFIG_8xx
> diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
> index 56212bc..a99e209 100644
> --- a/arch/powerpc/kernel/entry_32.S
> +++ b/arch/powerpc/kernel/entry_32.S
> @@ -1122,6 +1122,21 @@ ret_from_mcheck_exc:
>       RESTORE_xSRR(DSRR0,DSRR1);
>       RESTORE_MMU_REGS;
>       RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, PPC_RFMCI)
> +
> +     .globl  ret_from_prog_exc
> +ret_from_prog_exc:
> +     mfspr   r9,SPRN_SPRG_THREAD
> +     lwz     r10,SAVED_KSP_LIMIT(r1)
> +     stw     r10,KSP_LIMIT(r9)
> +     lwz     r9,THREAD_INFO-THREAD(r9)
> +     rlwinm  r10,r1,0,0,(31-THREAD_SHIFT)
> +     lwz     r10,TI_PREEMPT(r10)
> +     stw     r10,TI_PREEMPT(r9)
> +     RESTORE_xSRR(SRR0,SRR1);
> +     RESTORE_xSRR(CSRR0,CSRR1);
> +     RESTORE_xSRR(DSRR0,DSRR1);
> +     RESTORE_MMU_REGS;
> +     RET_FROM_EXC_LEVEL(SPRN_SRR0, SPRN_SRR1, rfi)
>  #endif /* CONFIG_BOOKE */

After a further consideration, to improve the above code fragment with the 
following
------
+
+       .globl  ret_from_prog_exc
+ret_from_prog_exc:
+#ifdef CONFIG_KPROBES
+       mfspr   r9,SPRN_SPRG_THREAD
+       lwz     r9,THREAD_INFO-THREAD(r9)
+       rlwinm  r10,r1,0,0,(31-THREAD_SHIFT)
+       lwz     r10,TI_PREEMPT(r10)
+       stw     r10,TI_PREEMPT(r9)
+       RET_FROM_EXC_LEVEL(SPRN_SRR0, SPRN_SRR1, rfi)
+#else
+       b       ret_from_except_full
+#endif

Here remove unnecessary restore, and also make sure its still same as normal
program exception when !CONFIG_KPROBES.

Tiejun

>  
>  /*
> diff --git a/arch/powerpc/kernel/head_booke.h 
> b/arch/powerpc/kernel/head_booke.h
> index a0bf158..941be40 100644
> --- a/arch/powerpc/kernel/head_booke.h
> +++ b/arch/powerpc/kernel/head_booke.h
> @@ -79,6 +79,10 @@
>  /* only on e500mc/e200 */
>  #define DBG_STACK_BASE               dbgirq_ctx
>  
> +#if defined(CONFIG_KPROBES)
> +#define PG_STACK_BASE                pgirq_ctx
> +#endif
> +
>  #define EXC_LVL_FRAME_OVERHEAD       (THREAD_SIZE - INT_FRAME_SIZE - 
> EXC_LVL_SIZE)
>  
>  #ifdef CONFIG_SMP
> @@ -158,6 +162,12 @@
>               EXC_LEVEL_EXCEPTION_PROLOG(DBG, SPRN_DSRR0, SPRN_DSRR1)
>  #define MCHECK_EXCEPTION_PROLOG \
>               EXC_LEVEL_EXCEPTION_PROLOG(MC, SPRN_MCSRR0, SPRN_MCSRR1)
> +#if defined(CONFIG_KPROBES)
> +#define      PROGRAM_EXCEPTION_PROLOG \
> +             EXC_LEVEL_EXCEPTION_PROLOG(PG, SPRN_SRR0, SPRN_SRR1)
> +#else
> +#define      PROGRAM_EXCEPTION_PROLOG        NORMAL_EXCEPTION_PROLOG
> +#endif
>  
>  /*
>   * Exception vectors.
> @@ -370,11 +380,12 @@ label:
>  
>  #define PROGRAM_EXCEPTION                                                  \
>       START_EXCEPTION(Program)                                              \
> -     NORMAL_EXCEPTION_PROLOG;                                              \
> +     PROGRAM_EXCEPTION_PROLOG;                                             \
>       mfspr   r4,SPRN_ESR;            /* Grab the ESR and save it */        \
>       stw     r4,_ESR(r11);                                                 \
>       addi    r3,r1,STACK_FRAME_OVERHEAD;                                   \
> -     EXC_XFER_STD(0x0700, program_check_exception)
> +     EXC_XFER_TEMPLATE(program_check_exception, 0x0700, MSR_KERNEL, NOCOPY,\
> +             transfer_to_handler_full, ret_from_prog_exc)
>  
>  #define DECREMENTER_EXCEPTION                                                
>       \
>       START_EXCEPTION(Decrementer)                                          \
> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
> index 5b428e3..ff5b8dd 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -397,6 +397,10 @@ struct thread_info   *critirq_ctx[NR_CPUS] __read_mostly;
>  struct thread_info    *dbgirq_ctx[NR_CPUS] __read_mostly;
>  struct thread_info *mcheckirq_ctx[NR_CPUS] __read_mostly;
>  
> +#if defined(CONFIG_KPROBES) && defined(CONFIG_BOOKE)
> +struct thread_info    *pgirq_ctx[NR_CPUS] __read_mostly;
> +#endif
> +
>  void exc_lvl_ctx_init(void)
>  {
>       struct thread_info *tp;
> @@ -423,6 +427,13 @@ void exc_lvl_ctx_init(void)
>               tp = mcheckirq_ctx[cpu_nr];
>               tp->cpu = cpu_nr;
>               tp->preempt_count = HARDIRQ_OFFSET;
> +
> +#if defined(CONFIG_KPROBES)
> +             memset((void *)pgirq_ctx[i], 0, THREAD_SIZE);
> +             tp = pgirq_ctx[i];
> +             tp->cpu = i;
> +             tp->preempt_count = 0;
> +#endif
>  #endif
>       }
>  }
> diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
> index 620d792..b872564 100644
> --- a/arch/powerpc/kernel/setup_32.c
> +++ b/arch/powerpc/kernel/setup_32.c
> @@ -272,6 +272,10 @@ static void __init exc_lvl_early_init(void)
>                       __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
>               mcheckirq_ctx[hw_cpu] = (struct thread_info *)
>                       __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
> +#ifdef CONFIG_KPROBES
> +             pgirq_ctx[hw_cpu] = (struct thread_info *)
> +                     __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
> +#endif
>  #endif
>       }
>  }

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to