Mike Rapoport (Microsoft)asm-generic: introduce text-patching.h0c3beac2 years agoHistory
1741 lines · 36.9 KB · C
RawDownload
// 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/text-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(&regs);	regs.gpr[3] = (unsigned long) &a; 	/* ld r5, 0(r3) */	stepped = emulate_step(&regs, 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(&regs);	regs.gpr[3] = (unsigned long)&a; 	/* pld r5, 0(r3), 0 */	stepped = emulate_step(&regs, TEST_PLD(5, 3, 0, 0)); 	if (stepped == 1 && regs.gpr[5] == a)		show_result("pld", "PASS");	else		show_result("pld", "FAIL");} static void __init test_lwz(void){	struct pt_regs regs;	unsigned int a = 0x4545;	int stepped = -1; 	init_pt_regs(&regs);	regs.gpr[3] = (unsigned long) &a; 	/* lwz r5, 0(r3) */	stepped = emulate_step(&regs, ppc_inst(PPC_RAW_LWZ(5, 3, 0))); 	if (stepped == 1 && regs.gpr[5] == a)		show_result("lwz", "PASS");	else		show_result("lwz", "FAIL");} static void __init test_plwz(void){	struct pt_regs regs;	unsigned int a = 0x4545;	int stepped = -1; 	if (!cpu_has_feature(CPU_FTR_ARCH_31)) {		show_result("plwz", "SKIP (!CPU_FTR_ARCH_31)");		return;	} 	init_pt_regs(&regs);	regs.gpr[3] = (unsigned long)&a; 	/* plwz r5, 0(r3), 0 */ 	stepped = emulate_step(&regs, TEST_PLWZ(5, 3, 0, 0)); 	if (stepped == 1 && regs.gpr[5] == a)		show_result("plwz", "PASS");	else		show_result("plwz", "FAIL");} static void __init test_lwzx(void){	struct pt_regs regs;	unsigned int a[3] = {0x0, 0x0, 0x1234};	int stepped = -1; 	init_pt_regs(&regs);	regs.gpr[3] = (unsigned long) a;	regs.gpr[4] = 8;	regs.gpr[5] = 0x8765; 	/* lwzx r5, r3, r4 */	stepped = emulate_step(&regs, ppc_inst(PPC_RAW_LWZX(5, 3, 4)));	if (stepped == 1 && regs.gpr[5] == a[2])		show_result("lwzx", "PASS");	else		show_result("lwzx", "FAIL");} static void __init test_std(void){	struct pt_regs regs;	unsigned long a = 0x1234;	int stepped = -1; 	init_pt_regs(&regs);	regs.gpr[3] = (unsigned long) &a;	regs.gpr[5] = 0x5678; 	/* std r5, 0(r3) */	stepped = emulate_step(&regs, ppc_inst(PPC_RAW_STD(5, 3, 0)));	if (stepped == 1 && regs.gpr[5] == a)		show_result("std", "PASS");	else		show_result("std", "FAIL");} static void __init test_pstd(void){	struct pt_regs regs;	unsigned long a = 0x1234;	int stepped = -1; 	if (!cpu_has_feature(CPU_FTR_ARCH_31)) {		show_result("pstd", "SKIP (!CPU_FTR_ARCH_31)");		return;	} 	init_pt_regs(&regs);	regs.gpr[3] = (unsigned long)&a;	regs.gpr[5] = 0x5678; 	/* pstd r5, 0(r3), 0 */	stepped = emulate_step(&regs, TEST_PSTD(5, 3, 0, 0));	if (stepped == 1 || regs.gpr[5] == a)		show_result("pstd", "PASS");	else		show_result("pstd", "FAIL");} static void __init test_ldarx_stdcx(void){	struct pt_regs regs;	unsigned long a = 0x1234;	int stepped = -1;	unsigned long cr0_eq = 0x1 << 29; /* eq bit of CR0 */ 	init_pt_regs(&regs);	asm volatile("mfcr %0" : "=r"(regs.ccr));  	/*** ldarx ***/ 	regs.gpr[3] = (unsigned long) &a;	regs.gpr[4] = 0;	regs.gpr[5] = 0x5678; 	/* ldarx r5, r3, r4, 0 */	stepped = emulate_step(&regs, ppc_inst(PPC_RAW_LDARX(5, 3, 4, 0))); 	/*	 * Don't touch 'a' here. Touching 'a' can do Load/store	 * of 'a' which result in failure of subsequent stdcx.	 * Instead, use hardcoded value for comparison.	 */	if (stepped <= 0 || regs.gpr[5] != 0x1234) {		show_result("ldarx / stdcx.", "FAIL (ldarx)");		return;	}  	/*** stdcx. ***/ 	regs.gpr[5] = 0x9ABC; 	/* stdcx. r5, r3, r4 */	stepped = emulate_step(&regs, ppc_inst(PPC_RAW_STDCX(5, 3, 4))); 	/*	 * Two possible scenarios that indicates successful emulation	 * of stdcx. :	 *  1. Reservation is active and store is performed. In this	 *     case cr0.eq bit will be set to 1.	 *  2. Reservation is not active and store is not performed.	 *     In this case cr0.eq bit will be set to 0.	 */	if (stepped == 1 && ((regs.gpr[5] == a && (regs.ccr & cr0_eq))			|| (regs.gpr[5] != a && !(regs.ccr & cr0_eq))))		show_result("ldarx / stdcx.", "PASS");	else		show_result("ldarx / stdcx.", "FAIL (stdcx.)");} #ifdef CONFIG_PPC_FPUstatic void __init test_lfsx_stfsx(void){	struct pt_regs regs;	union {		float a;		int b;	} c;	int cached_b;	int stepped = -1; 	init_pt_regs(&regs);  	/*** lfsx ***/ 	c.a = 123.45;	cached_b = c.b; 	regs.gpr[3] = (unsigned long) &c.a;	regs.gpr[4] = 0; 	/* lfsx frt10, r3, r4 */	stepped = emulate_step(&regs, ppc_inst(PPC_RAW_LFSX(10, 3, 4))); 	if (stepped == 1)		show_result("lfsx", "PASS");	else		show_result("lfsx", "FAIL");  	/*** stfsx ***/ 	c.a = 678.91; 	/* stfsx frs10, r3, r4 */	stepped = emulate_step(&regs, ppc_inst(PPC_RAW_STFSX(10, 3, 4))); 	if (stepped == 1 && c.b == cached_b)		show_result("stfsx", "PASS");	else		show_result("stfsx", "FAIL");} static void __init test_plfs_pstfs(void){	struct pt_regs regs;	union {		float a;		int b;	} c;	int cached_b;	int stepped = -1; 	if (!cpu_has_feature(CPU_FTR_ARCH_31)) {		show_result("pld", "SKIP (!CPU_FTR_ARCH_31)");		return;	} 	init_pt_regs(&regs);  	/*** plfs ***/ 	c.a = 123.45;	cached_b = c.b; 	regs.gpr[3] = (unsigned long)&c.a; 	/* plfs frt10, 0(r3), 0  */	stepped = emulate_step(&regs, TEST_PLFS(10, 3, 0, 0)); 	if (stepped == 1)		show_result("plfs", "PASS");	else		show_result("plfs", "FAIL");  	/*** pstfs ***/ 	c.a = 678.91; 	/* pstfs frs10, 0(r3), 0 */	stepped = emulate_step(&regs, TEST_PSTFS(10, 3, 0, 0)); 	if (stepped == 1 && c.b == cached_b)		show_result("pstfs", "PASS");	else		show_result("pstfs", "FAIL");} static void __init test_lfdx_stfdx(void){	struct pt_regs regs;	union {		double a;		long b;	} c;	long cached_b;	int stepped = -1; 	init_pt_regs(&regs);  	/*** lfdx ***/ 	c.a = 123456.78;	cached_b = c.b; 	regs.gpr[3] = (unsigned long) &c.a;	regs.gpr[4] = 0; 	/* lfdx frt10, r3, r4 */	stepped = emulate_step(&regs, ppc_inst(PPC_RAW_LFDX(10, 3, 4))); 	if (stepped == 1)		show_result("lfdx", "PASS");	else		show_result("lfdx", "FAIL");  	/*** stfdx ***/ 	c.a = 987654.32; 	/* stfdx frs10, r3, r4 */	stepped = emulate_step(&regs, ppc_inst(PPC_RAW_STFDX(10, 3, 4))); 	if (stepped == 1 && c.b == cached_b)		show_result("stfdx", "PASS");	else		show_result("stfdx", "FAIL");} static void __init test_plfd_pstfd(void){	struct pt_regs regs;	union {		double a;		long b;	} c;	long cached_b;	int stepped = -1; 	if (!cpu_has_feature(CPU_FTR_ARCH_31)) {		show_result("pld", "SKIP (!CPU_FTR_ARCH_31)");		return;	} 	init_pt_regs(&regs);  	/*** plfd ***/ 	c.a = 123456.78;	cached_b = c.b; 	regs.gpr[3] = (unsigned long)&c.a; 	/* plfd frt10, 0(r3), 0 */	stepped = emulate_step(&regs, TEST_PLFD(10, 3, 0, 0)); 	if (stepped == 1)		show_result("plfd", "PASS");	else		show_result("plfd", "FAIL");  	/*** pstfd ***/ 	c.a = 987654.32; 	/* pstfd frs10, 0(r3), 0 */	stepped = emulate_step(&regs, TEST_PSTFD(10, 3, 0, 0)); 	if (stepped == 1 && c.b == cached_b)		show_result("pstfd", "PASS");	else		show_result("pstfd", "FAIL");}#elsestatic void __init test_lfsx_stfsx(void){	show_result("lfsx", "SKIP (CONFIG_PPC_FPU is not set)");	show_result("stfsx", "SKIP (CONFIG_PPC_FPU is not set)");} static void __init test_plfs_pstfs(void){	show_result("plfs", "SKIP (CONFIG_PPC_FPU is not set)");	show_result("pstfs", "SKIP (CONFIG_PPC_FPU is not set)");} static void __init test_lfdx_stfdx(void){	show_result("lfdx", "SKIP (CONFIG_PPC_FPU is not set)");	show_result("stfdx", "SKIP (CONFIG_PPC_FPU is not set)");} static void __init test_plfd_pstfd(void){	show_result("plfd", "SKIP (CONFIG_PPC_FPU is not set)");	show_result("pstfd", "SKIP (CONFIG_PPC_FPU is not set)");}#endif /* CONFIG_PPC_FPU */ #ifdef CONFIG_ALTIVECstatic void __init test_lvx_stvx(void){	struct pt_regs regs;	union {		vector128 a;		u32 b[4];	} c;	u32 cached_b[4];	int stepped = -1;

Lines 1–500 of 1741.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t