// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Simple sanity tests for instruction emulation infrastructure.
*
* Copyright IBM Corp. 2016
*/
#define pr_fmt(fmt) "emulate_step_test: " fmt
#include <linux/ptrace.h>
#include <asm/cpu_has_feature.h>
#include <asm/sstep.h>
#include <asm/ppc-opcode.h>
#include <asm/code-patching.h>
#include <asm/inst.h>
#define MAX_SUBTESTS 16
#define IGNORE_GPR(n) (0x1UL << (n))
#define IGNORE_XER (0x1UL << 32)
#define IGNORE_CCR (0x1UL << 33)
#define NEGATIVE_TEST (0x1UL << 63)
#define TEST_PLD(r, base, i, pr) \
ppc_inst_prefix(PPC_PREFIX_8LS | __PPC_PRFX_R(pr) | IMM_H(i), \
PPC_INST_PLD | ___PPC_RT(r) | ___PPC_RA(base) | IMM_L(i))
#define TEST_PLWZ(r, base, i, pr) \
ppc_inst_prefix(PPC_PREFIX_MLS | __PPC_PRFX_R(pr) | IMM_H(i), \
PPC_RAW_LWZ(r, base, i))
#define TEST_PSTD(r, base, i, pr) \
ppc_inst_prefix(PPC_PREFIX_8LS | __PPC_PRFX_R(pr) | IMM_H(i), \
PPC_INST_PSTD | ___PPC_RT(r) | ___PPC_RA(base) | IMM_L(i))
#define TEST_PLFS(r, base, i, pr) \
ppc_inst_prefix(PPC_PREFIX_MLS | __PPC_PRFX_R(pr) | IMM_H(i), \
PPC_INST_LFS | ___PPC_RT(r) | ___PPC_RA(base) | IMM_L(i))
#define TEST_PSTFS(r, base, i, pr) \
ppc_inst_prefix(PPC_PREFIX_MLS | __PPC_PRFX_R(pr) | IMM_H(i), \
PPC_INST_STFS | ___PPC_RT(r) | ___PPC_RA(base) | IMM_L(i))
#define TEST_PLFD(r, base, i, pr) \
ppc_inst_prefix(PPC_PREFIX_MLS | __PPC_PRFX_R(pr) | IMM_H(i), \
PPC_INST_LFD | ___PPC_RT(r) | ___PPC_RA(base) | IMM_L(i))
#define TEST_PSTFD(r, base, i, pr) \
ppc_inst_prefix(PPC_PREFIX_MLS | __PPC_PRFX_R(pr) | IMM_H(i), \
PPC_INST_STFD | ___PPC_RT(r) | ___PPC_RA(base) | IMM_L(i))
#define TEST_PADDI(t, a, i, pr) \
ppc_inst_prefix(PPC_PREFIX_MLS | __PPC_PRFX_R(pr) | IMM_H(i), \
PPC_RAW_ADDI(t, a, i))
static void __init 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)) {
regs->msr = msr;
return;
}
asm volatile("mfmsr %0" : "=r"(regs->msr));
regs->msr |= MSR_FP;
regs->msr |= MSR_VEC;
regs->msr |= MSR_VSX;
msr = regs->msr;
msr_cached = true;
}
static void __init show_result(char *mnemonic, char *result)
{
pr_info("%-14s : %s\n", mnemonic, result);
}
static void __init show_result_with_descr(char *mnemonic, char *descr,
char *result)
{
pr_info("%-14s : %-50s %s\n", mnemonic, descr, result);
}
static void __init test_ld(void)
{
struct pt_regs regs;
unsigned long a = 0x23;
int stepped = -1;
init_pt_regs(®s);
regs.gpr[3] = (unsigned long) &a;
/* ld r5, 0(r3) */
stepped = emulate_step(®s, ppc_inst(PPC_RAW_LD(5, 3, 0)));
if (stepped == 1 && regs.gpr[5] == a)
show_result("ld", "PASS");
else
show_result("ld", "FAIL");
}
static void __init test_pld(void)
{
struct pt_regs regs;
unsigned long a = 0x23;
int stepped = -1;
if (!cpu_has_feature(CPU_FTR_ARCH_31)) {
show_result("pld", "SKIP (!CPU_FTR_ARCH_31)");
return;
}
init_pt_regs(®s);
regs.gpr[3] = (unsigned long)&a;
/* pld r5, 0(r3), 0 */
stepped = emulate_step(®s, TEST_PLD(5