Re: [PATCH 3/3] powerpc: emulate_step test for load/store instructions

From: Naveen N. Rao
Date: Wed Nov 02 2016 - 06:47:52 EST


On 2016/11/02 02:23PM, Ravi Bangoria wrote:
> Add new selftest that test emulate_step for Normal, Floating Point,
> Vector and Vector Scalar - load/store instructions. Test should run
> at boot time if CONFIG_KPROBES_SANITY_TEST and CONFIG_PPC64 is set.
>
> Sample log:
>
> [ 0.762063] emulate_step smoke test: start.
> [ 0.762219] emulate_step smoke test: ld : PASS
> [ 0.762434] emulate_step smoke test: lwz : PASS
> [ 0.762653] emulate_step smoke test: lwzx : PASS
> [ 0.762867] emulate_step smoke test: std : PASS
> [ 0.763082] emulate_step smoke test: ldarx / stdcx. : PASS
> [ 0.763302] emulate_step smoke test: lfsx : PASS
> [ 0.763514] emulate_step smoke test: stfsx : PASS
> [ 0.763727] emulate_step smoke test: lfdx : PASS
> [ 0.763942] emulate_step smoke test: stfdx : PASS
> [ 0.764134] emulate_step smoke test: lvx : PASS
> [ 0.764349] emulate_step smoke test: stvx : PASS
> [ 0.764575] emulate_step smoke test: lxvd2x : PASS
> [ 0.764788] emulate_step smoke test: stxvd2x : PASS
> [ 0.764997] emulate_step smoke test: complete.
>
> Signed-off-by: Ravi Bangoria <ravi.bangoria@xxxxxxxxxxxxxxxxxx>
> ---
> arch/powerpc/include/asm/sstep.h | 8 +
> arch/powerpc/kernel/kprobes.c | 2 +
> arch/powerpc/lib/Makefile | 4 +
> arch/powerpc/lib/test_emulate_step.c | 439 +++++++++++++++++++++++++++++++++++
> 4 files changed, 453 insertions(+)
> create mode 100644 arch/powerpc/lib/test_emulate_step.c
>
> diff --git a/arch/powerpc/include/asm/sstep.h b/arch/powerpc/include/asm/sstep.h
> index d3a42cc..d6d3630 100644
> --- a/arch/powerpc/include/asm/sstep.h
> +++ b/arch/powerpc/include/asm/sstep.h
> @@ -87,3 +87,11 @@ struct instruction_op {
>
> extern int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
> unsigned int instr);
> +
> +#if defined(CONFIG_KPROBES_SANITY_TEST) && defined(CONFIG_PPC64)
> +void test_emulate_step(void);
> +#else
> +static inline void test_emulate_step(void)
> +{
> +}
> +#endif
> diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
> index e785cc9..01d8002 100644
> --- a/arch/powerpc/kernel/kprobes.c
> +++ b/arch/powerpc/kernel/kprobes.c
> @@ -544,6 +544,8 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
>
> int __init arch_init_kprobes(void)
> {
> + test_emulate_step();
> +
> return register_kprobe(&trampoline_p);
> }
>
> diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
> index 309361e8..7d046ca 100644
> --- a/arch/powerpc/lib/Makefile
> +++ b/arch/powerpc/lib/Makefile
> @@ -35,3 +35,7 @@ obj-$(CONFIG_ALTIVEC) += xor_vmx.o
> CFLAGS_xor_vmx.o += -maltivec $(call cc-option,-mabi=altivec)
>
> obj-$(CONFIG_PPC64) += $(obj64-y)
> +
> +ifeq ($(CONFIG_PPC64), y)
> +obj-$(CONFIG_KPROBES_SANITY_TEST) += test_emulate_step.o
> +endif
> diff --git a/arch/powerpc/lib/test_emulate_step.c b/arch/powerpc/lib/test_emulate_step.c
> new file mode 100644
> index 0000000..887d1db
> --- /dev/null
> +++ b/arch/powerpc/lib/test_emulate_step.c
> @@ -0,0 +1,439 @@
> +/*
> + * test_emulate_step.c - simple sanity test for emulate_step load/store
> + * instructions
> + *
> + * Copyright IBM Corp. 2016
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it would be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
> + * the GNU General Public License for more details.
> + */
> +
> +#define pr_fmt(fmt) "emulate_step smoke test: " fmt
> +
> +#include <linux/ptrace.h>
> +#include <asm/sstep.h>
> +#include <asm/ppc-opcode.h>
> +
> +#define IMM_L(i) ((uintptr_t)(i) & 0xffff)
> +
> +/*
> + * Defined with TEST_ prefix so it does not conflict with other
> + * definitions.
> + */
> +#define TEST_LD(r, base, i) (PPC_INST_LD | ___PPC_RT(r) | \
> + ___PPC_RA(base) | IMM_L(i))
> +#define TEST_LWZ(r, base, i) (PPC_INST_LWZ | ___PPC_RT(r) | \
> + ___PPC_RA(base) | IMM_L(i))
> +#define TEST_LWZX(t, a, b) (PPC_INST_LWZX | ___PPC_RT(t) | \
> + ___PPC_RA(a) | ___PPC_RB(b))
> +#define TEST_STD(r, base, i) (PPC_INST_STD | ___PPC_RS(r) | \
> + ___PPC_RA(base) | ((i) & 0xfffc))
> +#define TEST_LDARX(t, a, b, eh) (PPC_INST_LDARX | ___PPC_RT(t) | \
> + ___PPC_RA(a) | ___PPC_RB(b) | \
> + __PPC_EH(eh))
> +#define TEST_STDCX(s, a, b) (PPC_INST_STDCX | ___PPC_RS(s) | \
> + ___PPC_RA(a) | ___PPC_RB(b))
> +#define TEST_LFSX(t, a, b) (PPC_INST_LFSX | ___PPC_RT(t) | \
> + ___PPC_RA(a) | ___PPC_RB(b))
> +#define TEST_STFSX(s, a, b) (PPC_INST_STFSX | ___PPC_RS(s) | \
> + ___PPC_RA(a) | ___PPC_RB(b))
> +#define TEST_LFDX(t, a, b) (PPC_INST_LFDX | ___PPC_RT(t) | \
> + ___PPC_RA(a) | ___PPC_RB(b))
> +#define TEST_STFDX(s, a, b) (PPC_INST_STFDX | ___PPC_RS(s) | \
> + ___PPC_RA(a) | ___PPC_RB(b))
> +#define TEST_LVX(t, a, b) (PPC_INST_LVX | ___PPC_RT(t) | \
> + ___PPC_RA(a) | ___PPC_RB(b))
> +#define TEST_STVX(s, a, b) (PPC_INST_STVX | ___PPC_RS(s) | \
> + ___PPC_RA(a) | ___PPC_RB(b))
> +#define TEST_LXVD2X(s, a, b) (PPC_INST_LXVD2X | VSX_XX1((s), R##a,
> R##b))
> +#define TEST_STXVD2X(s, a, b) (PPC_INST_STXVD2X | VSX_XX1((s), R##a, R##b))

It will be good to get some of these macros into some generic headers at
some point...

> +
> +
> +static void init_pt_regs(struct pt_regs *regs)
> +{
> + static unsigned long msr;
> + static bool msr_cached;
> +
> + memset(regs, 0, sizeof(struct pt_regs));
> +
> + if (likely(msr_cached)) {

Why not just check 'msr' itself here?

- Naveen