xref: /openbmc/linux/arch/powerpc/lib/test_emulate_step.c (revision 84022ac17327c5383917f46c162fd943cf79583f)
14ceae137SRavi Bangoria /*
2*84022ac1SSandipan Das  * Simple sanity tests for instruction emulation infrastructure.
34ceae137SRavi Bangoria  *
44ceae137SRavi Bangoria  * Copyright IBM Corp. 2016
54ceae137SRavi Bangoria  *
64ceae137SRavi Bangoria  * This program is free software;  you can redistribute it and/or modify
74ceae137SRavi Bangoria  * it under the terms of the GNU General Public License as published by
84ceae137SRavi Bangoria  * the Free Software Foundation; either version 2 of the License, or
94ceae137SRavi Bangoria  * (at your option) any later version.
104ceae137SRavi Bangoria  */
114ceae137SRavi Bangoria 
124ceae137SRavi Bangoria #define pr_fmt(fmt) "emulate_step_test: " fmt
134ceae137SRavi Bangoria 
144ceae137SRavi Bangoria #include <linux/ptrace.h>
154ceae137SRavi Bangoria #include <asm/sstep.h>
164ceae137SRavi Bangoria #include <asm/ppc-opcode.h>
17*84022ac1SSandipan Das #include <asm/code-patching.h>
184ceae137SRavi Bangoria 
194ceae137SRavi Bangoria #define IMM_L(i)		((uintptr_t)(i) & 0xffff)
204ceae137SRavi Bangoria 
214ceae137SRavi Bangoria /*
224ceae137SRavi Bangoria  * Defined with TEST_ prefix so it does not conflict with other
234ceae137SRavi Bangoria  * definitions.
244ceae137SRavi Bangoria  */
254ceae137SRavi Bangoria #define TEST_LD(r, base, i)	(PPC_INST_LD | ___PPC_RT(r) |		\
264ceae137SRavi Bangoria 					___PPC_RA(base) | IMM_L(i))
274ceae137SRavi Bangoria #define TEST_LWZ(r, base, i)	(PPC_INST_LWZ | ___PPC_RT(r) |		\
284ceae137SRavi Bangoria 					___PPC_RA(base) | IMM_L(i))
294ceae137SRavi Bangoria #define TEST_LWZX(t, a, b)	(PPC_INST_LWZX | ___PPC_RT(t) |		\
304ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
314ceae137SRavi Bangoria #define TEST_STD(r, base, i)	(PPC_INST_STD | ___PPC_RS(r) |		\
324ceae137SRavi Bangoria 					___PPC_RA(base) | ((i) & 0xfffc))
334ceae137SRavi Bangoria #define TEST_LDARX(t, a, b, eh)	(PPC_INST_LDARX | ___PPC_RT(t) |	\
344ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b) |	\
354ceae137SRavi Bangoria 					__PPC_EH(eh))
364ceae137SRavi Bangoria #define TEST_STDCX(s, a, b)	(PPC_INST_STDCX | ___PPC_RS(s) |	\
374ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
384ceae137SRavi Bangoria #define TEST_LFSX(t, a, b)	(PPC_INST_LFSX | ___PPC_RT(t) |		\
394ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
404ceae137SRavi Bangoria #define TEST_STFSX(s, a, b)	(PPC_INST_STFSX | ___PPC_RS(s) |	\
414ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
424ceae137SRavi Bangoria #define TEST_LFDX(t, a, b)	(PPC_INST_LFDX | ___PPC_RT(t) |		\
434ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
444ceae137SRavi Bangoria #define TEST_STFDX(s, a, b)	(PPC_INST_STFDX | ___PPC_RS(s) |	\
454ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
464ceae137SRavi Bangoria #define TEST_LVX(t, a, b)	(PPC_INST_LVX | ___PPC_RT(t) |		\
474ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
484ceae137SRavi Bangoria #define TEST_STVX(s, a, b)	(PPC_INST_STVX | ___PPC_RS(s) |		\
494ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
504ceae137SRavi Bangoria #define TEST_LXVD2X(s, a, b)	(PPC_INST_LXVD2X | VSX_XX1((s), R##a, R##b))
514ceae137SRavi Bangoria #define TEST_STXVD2X(s, a, b)	(PPC_INST_STXVD2X | VSX_XX1((s), R##a, R##b))
524ceae137SRavi Bangoria 
53*84022ac1SSandipan Das #define MAX_SUBTESTS	16
54*84022ac1SSandipan Das 
55*84022ac1SSandipan Das #define IGNORE_GPR(n)	(0x1UL << (n))
56*84022ac1SSandipan Das #define IGNORE_XER	(0x1UL << 32)
57*84022ac1SSandipan Das #define IGNORE_CCR	(0x1UL << 33)
584ceae137SRavi Bangoria 
594ceae137SRavi Bangoria static void __init init_pt_regs(struct pt_regs *regs)
604ceae137SRavi Bangoria {
614ceae137SRavi Bangoria 	static unsigned long msr;
624ceae137SRavi Bangoria 	static bool msr_cached;
634ceae137SRavi Bangoria 
644ceae137SRavi Bangoria 	memset(regs, 0, sizeof(struct pt_regs));
654ceae137SRavi Bangoria 
664ceae137SRavi Bangoria 	if (likely(msr_cached)) {
674ceae137SRavi Bangoria 		regs->msr = msr;
684ceae137SRavi Bangoria 		return;
694ceae137SRavi Bangoria 	}
704ceae137SRavi Bangoria 
714ceae137SRavi Bangoria 	asm volatile("mfmsr %0" : "=r"(regs->msr));
724ceae137SRavi Bangoria 
734ceae137SRavi Bangoria 	regs->msr |= MSR_FP;
744ceae137SRavi Bangoria 	regs->msr |= MSR_VEC;
754ceae137SRavi Bangoria 	regs->msr |= MSR_VSX;
764ceae137SRavi Bangoria 
774ceae137SRavi Bangoria 	msr = regs->msr;
784ceae137SRavi Bangoria 	msr_cached = true;
794ceae137SRavi Bangoria }
804ceae137SRavi Bangoria 
81*84022ac1SSandipan Das static void __init show_result(char *mnemonic, char *result)
824ceae137SRavi Bangoria {
83*84022ac1SSandipan Das 	pr_info("%-14s : %s\n", mnemonic, result);
84*84022ac1SSandipan Das }
85*84022ac1SSandipan Das 
86*84022ac1SSandipan Das static void __init show_result_with_descr(char *mnemonic, char *descr,
87*84022ac1SSandipan Das 					  char *result)
88*84022ac1SSandipan Das {
89*84022ac1SSandipan Das 	pr_info("%-14s : %-50s %s\n", mnemonic, descr, result);
904ceae137SRavi Bangoria }
914ceae137SRavi Bangoria 
924ceae137SRavi Bangoria static void __init test_ld(void)
934ceae137SRavi Bangoria {
944ceae137SRavi Bangoria 	struct pt_regs regs;
954ceae137SRavi Bangoria 	unsigned long a = 0x23;
964ceae137SRavi Bangoria 	int stepped = -1;
974ceae137SRavi Bangoria 
984ceae137SRavi Bangoria 	init_pt_regs(&regs);
994ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &a;
1004ceae137SRavi Bangoria 
1014ceae137SRavi Bangoria 	/* ld r5, 0(r3) */
1024ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LD(5, 3, 0));
1034ceae137SRavi Bangoria 
1044ceae137SRavi Bangoria 	if (stepped == 1 && regs.gpr[5] == a)
1054ceae137SRavi Bangoria 		show_result("ld", "PASS");
1064ceae137SRavi Bangoria 	else
1074ceae137SRavi Bangoria 		show_result("ld", "FAIL");
1084ceae137SRavi Bangoria }
1094ceae137SRavi Bangoria 
1104ceae137SRavi Bangoria static void __init test_lwz(void)
1114ceae137SRavi Bangoria {
1124ceae137SRavi Bangoria 	struct pt_regs regs;
1134ceae137SRavi Bangoria 	unsigned int a = 0x4545;
1144ceae137SRavi Bangoria 	int stepped = -1;
1154ceae137SRavi Bangoria 
1164ceae137SRavi Bangoria 	init_pt_regs(&regs);
1174ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &a;
1184ceae137SRavi Bangoria 
1194ceae137SRavi Bangoria 	/* lwz r5, 0(r3) */
1204ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LWZ(5, 3, 0));
1214ceae137SRavi Bangoria 
1224ceae137SRavi Bangoria 	if (stepped == 1 && regs.gpr[5] == a)
1234ceae137SRavi Bangoria 		show_result("lwz", "PASS");
1244ceae137SRavi Bangoria 	else
1254ceae137SRavi Bangoria 		show_result("lwz", "FAIL");
1264ceae137SRavi Bangoria }
1274ceae137SRavi Bangoria 
1284ceae137SRavi Bangoria static void __init test_lwzx(void)
1294ceae137SRavi Bangoria {
1304ceae137SRavi Bangoria 	struct pt_regs regs;
1314ceae137SRavi Bangoria 	unsigned int a[3] = {0x0, 0x0, 0x1234};
1324ceae137SRavi Bangoria 	int stepped = -1;
1334ceae137SRavi Bangoria 
1344ceae137SRavi Bangoria 	init_pt_regs(&regs);
1354ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) a;
1364ceae137SRavi Bangoria 	regs.gpr[4] = 8;
1374ceae137SRavi Bangoria 	regs.gpr[5] = 0x8765;
1384ceae137SRavi Bangoria 
1394ceae137SRavi Bangoria 	/* lwzx r5, r3, r4 */
1404ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LWZX(5, 3, 4));
1414ceae137SRavi Bangoria 	if (stepped == 1 && regs.gpr[5] == a[2])
1424ceae137SRavi Bangoria 		show_result("lwzx", "PASS");
1434ceae137SRavi Bangoria 	else
1444ceae137SRavi Bangoria 		show_result("lwzx", "FAIL");
1454ceae137SRavi Bangoria }
1464ceae137SRavi Bangoria 
1474ceae137SRavi Bangoria static void __init test_std(void)
1484ceae137SRavi Bangoria {
1494ceae137SRavi Bangoria 	struct pt_regs regs;
1504ceae137SRavi Bangoria 	unsigned long a = 0x1234;
1514ceae137SRavi Bangoria 	int stepped = -1;
1524ceae137SRavi Bangoria 
1534ceae137SRavi Bangoria 	init_pt_regs(&regs);
1544ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &a;
1554ceae137SRavi Bangoria 	regs.gpr[5] = 0x5678;
1564ceae137SRavi Bangoria 
1574ceae137SRavi Bangoria 	/* std r5, 0(r3) */
1584ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_STD(5, 3, 0));
1594ceae137SRavi Bangoria 	if (stepped == 1 || regs.gpr[5] == a)
1604ceae137SRavi Bangoria 		show_result("std", "PASS");
1614ceae137SRavi Bangoria 	else
1624ceae137SRavi Bangoria 		show_result("std", "FAIL");
1634ceae137SRavi Bangoria }
1644ceae137SRavi Bangoria 
1654ceae137SRavi Bangoria static void __init test_ldarx_stdcx(void)
1664ceae137SRavi Bangoria {
1674ceae137SRavi Bangoria 	struct pt_regs regs;
1684ceae137SRavi Bangoria 	unsigned long a = 0x1234;
1694ceae137SRavi Bangoria 	int stepped = -1;
1704ceae137SRavi Bangoria 	unsigned long cr0_eq = 0x1 << 29; /* eq bit of CR0 */
1714ceae137SRavi Bangoria 
1724ceae137SRavi Bangoria 	init_pt_regs(&regs);
1734ceae137SRavi Bangoria 	asm volatile("mfcr %0" : "=r"(regs.ccr));
1744ceae137SRavi Bangoria 
1754ceae137SRavi Bangoria 
1764ceae137SRavi Bangoria 	/*** ldarx ***/
1774ceae137SRavi Bangoria 
1784ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &a;
1794ceae137SRavi Bangoria 	regs.gpr[4] = 0;
1804ceae137SRavi Bangoria 	regs.gpr[5] = 0x5678;
1814ceae137SRavi Bangoria 
1824ceae137SRavi Bangoria 	/* ldarx r5, r3, r4, 0 */
1834ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LDARX(5, 3, 4, 0));
1844ceae137SRavi Bangoria 
1854ceae137SRavi Bangoria 	/*
1864ceae137SRavi Bangoria 	 * Don't touch 'a' here. Touching 'a' can do Load/store
1874ceae137SRavi Bangoria 	 * of 'a' which result in failure of subsequent stdcx.
1884ceae137SRavi Bangoria 	 * Instead, use hardcoded value for comparison.
1894ceae137SRavi Bangoria 	 */
1904ceae137SRavi Bangoria 	if (stepped <= 0 || regs.gpr[5] != 0x1234) {
1914ceae137SRavi Bangoria 		show_result("ldarx / stdcx.", "FAIL (ldarx)");
1924ceae137SRavi Bangoria 		return;
1934ceae137SRavi Bangoria 	}
1944ceae137SRavi Bangoria 
1954ceae137SRavi Bangoria 
1964ceae137SRavi Bangoria 	/*** stdcx. ***/
1974ceae137SRavi Bangoria 
1984ceae137SRavi Bangoria 	regs.gpr[5] = 0x9ABC;
1994ceae137SRavi Bangoria 
2004ceae137SRavi Bangoria 	/* stdcx. r5, r3, r4 */
2014ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_STDCX(5, 3, 4));
2024ceae137SRavi Bangoria 
2034ceae137SRavi Bangoria 	/*
2044ceae137SRavi Bangoria 	 * Two possible scenarios that indicates successful emulation
2054ceae137SRavi Bangoria 	 * of stdcx. :
2064ceae137SRavi Bangoria 	 *  1. Reservation is active and store is performed. In this
2074ceae137SRavi Bangoria 	 *     case cr0.eq bit will be set to 1.
2084ceae137SRavi Bangoria 	 *  2. Reservation is not active and store is not performed.
2094ceae137SRavi Bangoria 	 *     In this case cr0.eq bit will be set to 0.
2104ceae137SRavi Bangoria 	 */
2114ceae137SRavi Bangoria 	if (stepped == 1 && ((regs.gpr[5] == a && (regs.ccr & cr0_eq))
2124ceae137SRavi Bangoria 			|| (regs.gpr[5] != a && !(regs.ccr & cr0_eq))))
2134ceae137SRavi Bangoria 		show_result("ldarx / stdcx.", "PASS");
2144ceae137SRavi Bangoria 	else
2154ceae137SRavi Bangoria 		show_result("ldarx / stdcx.", "FAIL (stdcx.)");
2164ceae137SRavi Bangoria }
2174ceae137SRavi Bangoria 
2184ceae137SRavi Bangoria #ifdef CONFIG_PPC_FPU
2194ceae137SRavi Bangoria static void __init test_lfsx_stfsx(void)
2204ceae137SRavi Bangoria {
2214ceae137SRavi Bangoria 	struct pt_regs regs;
2224ceae137SRavi Bangoria 	union {
2234ceae137SRavi Bangoria 		float a;
2244ceae137SRavi Bangoria 		int b;
2254ceae137SRavi Bangoria 	} c;
2264ceae137SRavi Bangoria 	int cached_b;
2274ceae137SRavi Bangoria 	int stepped = -1;
2284ceae137SRavi Bangoria 
2294ceae137SRavi Bangoria 	init_pt_regs(&regs);
2304ceae137SRavi Bangoria 
2314ceae137SRavi Bangoria 
2324ceae137SRavi Bangoria 	/*** lfsx ***/
2334ceae137SRavi Bangoria 
2344ceae137SRavi Bangoria 	c.a = 123.45;
2354ceae137SRavi Bangoria 	cached_b = c.b;
2364ceae137SRavi Bangoria 
2374ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &c.a;
2384ceae137SRavi Bangoria 	regs.gpr[4] = 0;
2394ceae137SRavi Bangoria 
2404ceae137SRavi Bangoria 	/* lfsx frt10, r3, r4 */
2414ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LFSX(10, 3, 4));
2424ceae137SRavi Bangoria 
2434ceae137SRavi Bangoria 	if (stepped == 1)
2444ceae137SRavi Bangoria 		show_result("lfsx", "PASS");
2454ceae137SRavi Bangoria 	else
2464ceae137SRavi Bangoria 		show_result("lfsx", "FAIL");
2474ceae137SRavi Bangoria 
2484ceae137SRavi Bangoria 
2494ceae137SRavi Bangoria 	/*** stfsx ***/
2504ceae137SRavi Bangoria 
2514ceae137SRavi Bangoria 	c.a = 678.91;
2524ceae137SRavi Bangoria 
2534ceae137SRavi Bangoria 	/* stfsx frs10, r3, r4 */
2544ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_STFSX(10, 3, 4));
2554ceae137SRavi Bangoria 
2564ceae137SRavi Bangoria 	if (stepped == 1 && c.b == cached_b)
2574ceae137SRavi Bangoria 		show_result("stfsx", "PASS");
2584ceae137SRavi Bangoria 	else
2594ceae137SRavi Bangoria 		show_result("stfsx", "FAIL");
2604ceae137SRavi Bangoria }
2614ceae137SRavi Bangoria 
2624ceae137SRavi Bangoria static void __init test_lfdx_stfdx(void)
2634ceae137SRavi Bangoria {
2644ceae137SRavi Bangoria 	struct pt_regs regs;
2654ceae137SRavi Bangoria 	union {
2664ceae137SRavi Bangoria 		double a;
2674ceae137SRavi Bangoria 		long b;
2684ceae137SRavi Bangoria 	} c;
2694ceae137SRavi Bangoria 	long cached_b;
2704ceae137SRavi Bangoria 	int stepped = -1;
2714ceae137SRavi Bangoria 
2724ceae137SRavi Bangoria 	init_pt_regs(&regs);
2734ceae137SRavi Bangoria 
2744ceae137SRavi Bangoria 
2754ceae137SRavi Bangoria 	/*** lfdx ***/
2764ceae137SRavi Bangoria 
2774ceae137SRavi Bangoria 	c.a = 123456.78;
2784ceae137SRavi Bangoria 	cached_b = c.b;
2794ceae137SRavi Bangoria 
2804ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &c.a;
2814ceae137SRavi Bangoria 	regs.gpr[4] = 0;
2824ceae137SRavi Bangoria 
2834ceae137SRavi Bangoria 	/* lfdx frt10, r3, r4 */
2844ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LFDX(10, 3, 4));
2854ceae137SRavi Bangoria 
2864ceae137SRavi Bangoria 	if (stepped == 1)
2874ceae137SRavi Bangoria 		show_result("lfdx", "PASS");
2884ceae137SRavi Bangoria 	else
2894ceae137SRavi Bangoria 		show_result("lfdx", "FAIL");
2904ceae137SRavi Bangoria 
2914ceae137SRavi Bangoria 
2924ceae137SRavi Bangoria 	/*** stfdx ***/
2934ceae137SRavi Bangoria 
2944ceae137SRavi Bangoria 	c.a = 987654.32;
2954ceae137SRavi Bangoria 
2964ceae137SRavi Bangoria 	/* stfdx frs10, r3, r4 */
2974ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_STFDX(10, 3, 4));
2984ceae137SRavi Bangoria 
2994ceae137SRavi Bangoria 	if (stepped == 1 && c.b == cached_b)
3004ceae137SRavi Bangoria 		show_result("stfdx", "PASS");
3014ceae137SRavi Bangoria 	else
3024ceae137SRavi Bangoria 		show_result("stfdx", "FAIL");
3034ceae137SRavi Bangoria }
3044ceae137SRavi Bangoria #else
3054ceae137SRavi Bangoria static void __init test_lfsx_stfsx(void)
3064ceae137SRavi Bangoria {
3074ceae137SRavi Bangoria 	show_result("lfsx", "SKIP (CONFIG_PPC_FPU is not set)");
3084ceae137SRavi Bangoria 	show_result("stfsx", "SKIP (CONFIG_PPC_FPU is not set)");
3094ceae137SRavi Bangoria }
3104ceae137SRavi Bangoria 
3114ceae137SRavi Bangoria static void __init test_lfdx_stfdx(void)
3124ceae137SRavi Bangoria {
3134ceae137SRavi Bangoria 	show_result("lfdx", "SKIP (CONFIG_PPC_FPU is not set)");
3144ceae137SRavi Bangoria 	show_result("stfdx", "SKIP (CONFIG_PPC_FPU is not set)");
3154ceae137SRavi Bangoria }
3164ceae137SRavi Bangoria #endif /* CONFIG_PPC_FPU */
3174ceae137SRavi Bangoria 
3184ceae137SRavi Bangoria #ifdef CONFIG_ALTIVEC
3194ceae137SRavi Bangoria static void __init test_lvx_stvx(void)
3204ceae137SRavi Bangoria {
3214ceae137SRavi Bangoria 	struct pt_regs regs;
3224ceae137SRavi Bangoria 	union {
3234ceae137SRavi Bangoria 		vector128 a;
3244ceae137SRavi Bangoria 		u32 b[4];
3254ceae137SRavi Bangoria 	} c;
3264ceae137SRavi Bangoria 	u32 cached_b[4];
3274ceae137SRavi Bangoria 	int stepped = -1;
3284ceae137SRavi Bangoria 
3294ceae137SRavi Bangoria 	init_pt_regs(&regs);
3304ceae137SRavi Bangoria 
3314ceae137SRavi Bangoria 
3324ceae137SRavi Bangoria 	/*** lvx ***/
3334ceae137SRavi Bangoria 
3344ceae137SRavi Bangoria 	cached_b[0] = c.b[0] = 923745;
3354ceae137SRavi Bangoria 	cached_b[1] = c.b[1] = 2139478;
3364ceae137SRavi Bangoria 	cached_b[2] = c.b[2] = 9012;
3374ceae137SRavi Bangoria 	cached_b[3] = c.b[3] = 982134;
3384ceae137SRavi Bangoria 
3394ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &c.a;
3404ceae137SRavi Bangoria 	regs.gpr[4] = 0;
3414ceae137SRavi Bangoria 
3424ceae137SRavi Bangoria 	/* lvx vrt10, r3, r4 */
3434ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LVX(10, 3, 4));
3444ceae137SRavi Bangoria 
3454ceae137SRavi Bangoria 	if (stepped == 1)
3464ceae137SRavi Bangoria 		show_result("lvx", "PASS");
3474ceae137SRavi Bangoria 	else
3484ceae137SRavi Bangoria 		show_result("lvx", "FAIL");
3494ceae137SRavi Bangoria 
3504ceae137SRavi Bangoria 
3514ceae137SRavi Bangoria 	/*** stvx ***/
3524ceae137SRavi Bangoria 
3534ceae137SRavi Bangoria 	c.b[0] = 4987513;
3544ceae137SRavi Bangoria 	c.b[1] = 84313948;
3554ceae137SRavi Bangoria 	c.b[2] = 71;
3564ceae137SRavi Bangoria 	c.b[3] = 498532;
3574ceae137SRavi Bangoria 
3584ceae137SRavi Bangoria 	/* stvx vrs10, r3, r4 */
3594ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_STVX(10, 3, 4));
3604ceae137SRavi Bangoria 
3614ceae137SRavi Bangoria 	if (stepped == 1 && cached_b[0] == c.b[0] && cached_b[1] == c.b[1] &&
3624ceae137SRavi Bangoria 	    cached_b[2] == c.b[2] && cached_b[3] == c.b[3])
3634ceae137SRavi Bangoria 		show_result("stvx", "PASS");
3644ceae137SRavi Bangoria 	else
3654ceae137SRavi Bangoria 		show_result("stvx", "FAIL");
3664ceae137SRavi Bangoria }
3674ceae137SRavi Bangoria #else
3684ceae137SRavi Bangoria static void __init test_lvx_stvx(void)
3694ceae137SRavi Bangoria {
3704ceae137SRavi Bangoria 	show_result("lvx", "SKIP (CONFIG_ALTIVEC is not set)");
3714ceae137SRavi Bangoria 	show_result("stvx", "SKIP (CONFIG_ALTIVEC is not set)");
3724ceae137SRavi Bangoria }
3734ceae137SRavi Bangoria #endif /* CONFIG_ALTIVEC */
3744ceae137SRavi Bangoria 
3754ceae137SRavi Bangoria #ifdef CONFIG_VSX
3764ceae137SRavi Bangoria static void __init test_lxvd2x_stxvd2x(void)
3774ceae137SRavi Bangoria {
3784ceae137SRavi Bangoria 	struct pt_regs regs;
3794ceae137SRavi Bangoria 	union {
3804ceae137SRavi Bangoria 		vector128 a;
3814ceae137SRavi Bangoria 		u32 b[4];
3824ceae137SRavi Bangoria 	} c;
3834ceae137SRavi Bangoria 	u32 cached_b[4];
3844ceae137SRavi Bangoria 	int stepped = -1;
3854ceae137SRavi Bangoria 
3864ceae137SRavi Bangoria 	init_pt_regs(&regs);
3874ceae137SRavi Bangoria 
3884ceae137SRavi Bangoria 
3894ceae137SRavi Bangoria 	/*** lxvd2x ***/
3904ceae137SRavi Bangoria 
3914ceae137SRavi Bangoria 	cached_b[0] = c.b[0] = 18233;
3924ceae137SRavi Bangoria 	cached_b[1] = c.b[1] = 34863571;
3934ceae137SRavi Bangoria 	cached_b[2] = c.b[2] = 834;
3944ceae137SRavi Bangoria 	cached_b[3] = c.b[3] = 6138911;
3954ceae137SRavi Bangoria 
3964ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &c.a;
3974ceae137SRavi Bangoria 	regs.gpr[4] = 0;
3984ceae137SRavi Bangoria 
3994ceae137SRavi Bangoria 	/* lxvd2x vsr39, r3, r4 */
4004ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LXVD2X(39, 3, 4));
4014ceae137SRavi Bangoria 
4025a61640eSRavi Bangoria 	if (stepped == 1 && cpu_has_feature(CPU_FTR_VSX)) {
4034ceae137SRavi Bangoria 		show_result("lxvd2x", "PASS");
4045a61640eSRavi Bangoria 	} else {
4055a61640eSRavi Bangoria 		if (!cpu_has_feature(CPU_FTR_VSX))
4065a61640eSRavi Bangoria 			show_result("lxvd2x", "PASS (!CPU_FTR_VSX)");
4074ceae137SRavi Bangoria 		else
4084ceae137SRavi Bangoria 			show_result("lxvd2x", "FAIL");
4095a61640eSRavi Bangoria 	}
4104ceae137SRavi Bangoria 
4114ceae137SRavi Bangoria 
4124ceae137SRavi Bangoria 	/*** stxvd2x ***/
4134ceae137SRavi Bangoria 
4144ceae137SRavi Bangoria 	c.b[0] = 21379463;
4154ceae137SRavi Bangoria 	c.b[1] = 87;
4164ceae137SRavi Bangoria 	c.b[2] = 374234;
4174ceae137SRavi Bangoria 	c.b[3] = 4;
4184ceae137SRavi Bangoria 
4194ceae137SRavi Bangoria 	/* stxvd2x vsr39, r3, r4 */
4204ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_STXVD2X(39, 3, 4));
4214ceae137SRavi Bangoria 
4224ceae137SRavi Bangoria 	if (stepped == 1 && cached_b[0] == c.b[0] && cached_b[1] == c.b[1] &&
4235a61640eSRavi Bangoria 	    cached_b[2] == c.b[2] && cached_b[3] == c.b[3] &&
4245a61640eSRavi Bangoria 	    cpu_has_feature(CPU_FTR_VSX)) {
4254ceae137SRavi Bangoria 		show_result("stxvd2x", "PASS");
4265a61640eSRavi Bangoria 	} else {
4275a61640eSRavi Bangoria 		if (!cpu_has_feature(CPU_FTR_VSX))
4285a61640eSRavi Bangoria 			show_result("stxvd2x", "PASS (!CPU_FTR_VSX)");
4294ceae137SRavi Bangoria 		else
4304ceae137SRavi Bangoria 			show_result("stxvd2x", "FAIL");
4314ceae137SRavi Bangoria 	}
4325a61640eSRavi Bangoria }
4334ceae137SRavi Bangoria #else
4344ceae137SRavi Bangoria static void __init test_lxvd2x_stxvd2x(void)
4354ceae137SRavi Bangoria {
4364ceae137SRavi Bangoria 	show_result("lxvd2x", "SKIP (CONFIG_VSX is not set)");
4374ceae137SRavi Bangoria 	show_result("stxvd2x", "SKIP (CONFIG_VSX is not set)");
4384ceae137SRavi Bangoria }
4394ceae137SRavi Bangoria #endif /* CONFIG_VSX */
4404ceae137SRavi Bangoria 
441*84022ac1SSandipan Das static void __init run_tests_load_store(void)
4424ceae137SRavi Bangoria {
4434ceae137SRavi Bangoria 	test_ld();
4444ceae137SRavi Bangoria 	test_lwz();
4454ceae137SRavi Bangoria 	test_lwzx();
4464ceae137SRavi Bangoria 	test_std();
4474ceae137SRavi Bangoria 	test_ldarx_stdcx();
4484ceae137SRavi Bangoria 	test_lfsx_stfsx();
4494ceae137SRavi Bangoria 	test_lfdx_stfdx();
4504ceae137SRavi Bangoria 	test_lvx_stvx();
4514ceae137SRavi Bangoria 	test_lxvd2x_stxvd2x();
452*84022ac1SSandipan Das }
453*84022ac1SSandipan Das 
454*84022ac1SSandipan Das struct compute_test {
455*84022ac1SSandipan Das 	char *mnemonic;
456*84022ac1SSandipan Das 	struct {
457*84022ac1SSandipan Das 		char *descr;
458*84022ac1SSandipan Das 		unsigned long flags;
459*84022ac1SSandipan Das 		unsigned int instr;
460*84022ac1SSandipan Das 		struct pt_regs regs;
461*84022ac1SSandipan Das 	} subtests[MAX_SUBTESTS + 1];
462*84022ac1SSandipan Das };
463*84022ac1SSandipan Das 
464*84022ac1SSandipan Das static struct compute_test compute_tests[] = {
465*84022ac1SSandipan Das 	{
466*84022ac1SSandipan Das 		.mnemonic = "nop",
467*84022ac1SSandipan Das 		.subtests = {
468*84022ac1SSandipan Das 			{
469*84022ac1SSandipan Das 				.descr = "R0 = LONG_MAX",
470*84022ac1SSandipan Das 				.instr = PPC_INST_NOP,
471*84022ac1SSandipan Das 				.regs = {
472*84022ac1SSandipan Das 					.gpr[0] = LONG_MAX,
473*84022ac1SSandipan Das 				}
474*84022ac1SSandipan Das 			}
475*84022ac1SSandipan Das 		}
476*84022ac1SSandipan Das 	}
477*84022ac1SSandipan Das };
478*84022ac1SSandipan Das 
479*84022ac1SSandipan Das static int __init emulate_compute_instr(struct pt_regs *regs,
480*84022ac1SSandipan Das 					unsigned int instr)
481*84022ac1SSandipan Das {
482*84022ac1SSandipan Das 	struct instruction_op op;
483*84022ac1SSandipan Das 
484*84022ac1SSandipan Das 	if (!regs || !instr)
485*84022ac1SSandipan Das 		return -EINVAL;
486*84022ac1SSandipan Das 
487*84022ac1SSandipan Das 	if (analyse_instr(&op, regs, instr) != 1 ||
488*84022ac1SSandipan Das 	    GETTYPE(op.type) != COMPUTE) {
489*84022ac1SSandipan Das 		pr_info("emulation failed, instruction = 0x%08x\n", instr);
490*84022ac1SSandipan Das 		return -EFAULT;
491*84022ac1SSandipan Das 	}
492*84022ac1SSandipan Das 
493*84022ac1SSandipan Das 	emulate_update_regs(regs, &op);
494*84022ac1SSandipan Das 	return 0;
495*84022ac1SSandipan Das }
496*84022ac1SSandipan Das 
497*84022ac1SSandipan Das static int __init execute_compute_instr(struct pt_regs *regs,
498*84022ac1SSandipan Das 					unsigned int instr)
499*84022ac1SSandipan Das {
500*84022ac1SSandipan Das 	extern int exec_instr(struct pt_regs *regs);
501*84022ac1SSandipan Das 	extern s32 patch__exec_instr;
502*84022ac1SSandipan Das 
503*84022ac1SSandipan Das 	if (!regs || !instr)
504*84022ac1SSandipan Das 		return -EINVAL;
505*84022ac1SSandipan Das 
506*84022ac1SSandipan Das 	/* Patch the NOP with the actual instruction */
507*84022ac1SSandipan Das 	patch_instruction_site(&patch__exec_instr, instr);
508*84022ac1SSandipan Das 	if (exec_instr(regs)) {
509*84022ac1SSandipan Das 		pr_info("execution failed, instruction = 0x%08x\n", instr);
510*84022ac1SSandipan Das 		return -EFAULT;
511*84022ac1SSandipan Das 	}
512*84022ac1SSandipan Das 
513*84022ac1SSandipan Das 	return 0;
514*84022ac1SSandipan Das }
515*84022ac1SSandipan Das 
516*84022ac1SSandipan Das #define gpr_mismatch(gprn, exp, got)	\
517*84022ac1SSandipan Das 	pr_info("GPR%u mismatch, exp = 0x%016lx, got = 0x%016lx\n",	\
518*84022ac1SSandipan Das 		gprn, exp, got)
519*84022ac1SSandipan Das 
520*84022ac1SSandipan Das #define reg_mismatch(name, exp, got)	\
521*84022ac1SSandipan Das 	pr_info("%s mismatch, exp = 0x%016lx, got = 0x%016lx\n",	\
522*84022ac1SSandipan Das 		name, exp, got)
523*84022ac1SSandipan Das 
524*84022ac1SSandipan Das static void __init run_tests_compute(void)
525*84022ac1SSandipan Das {
526*84022ac1SSandipan Das 	unsigned long flags;
527*84022ac1SSandipan Das 	struct compute_test *test;
528*84022ac1SSandipan Das 	struct pt_regs *regs, exp, got;
529*84022ac1SSandipan Das 	unsigned int i, j, k, instr;
530*84022ac1SSandipan Das 	bool ignore_gpr, ignore_xer, ignore_ccr, passed;
531*84022ac1SSandipan Das 
532*84022ac1SSandipan Das 	for (i = 0; i < ARRAY_SIZE(compute_tests); i++) {
533*84022ac1SSandipan Das 		test = &compute_tests[i];
534*84022ac1SSandipan Das 
535*84022ac1SSandipan Das 		for (j = 0; j < MAX_SUBTESTS && test->subtests[j].descr; j++) {
536*84022ac1SSandipan Das 			instr = test->subtests[j].instr;
537*84022ac1SSandipan Das 			flags = test->subtests[j].flags;
538*84022ac1SSandipan Das 			regs = &test->subtests[j].regs;
539*84022ac1SSandipan Das 			ignore_xer = flags & IGNORE_XER;
540*84022ac1SSandipan Das 			ignore_ccr = flags & IGNORE_CCR;
541*84022ac1SSandipan Das 			passed = true;
542*84022ac1SSandipan Das 
543*84022ac1SSandipan Das 			memcpy(&exp, regs, sizeof(struct pt_regs));
544*84022ac1SSandipan Das 			memcpy(&got, regs, sizeof(struct pt_regs));
545*84022ac1SSandipan Das 
546*84022ac1SSandipan Das 			/*
547*84022ac1SSandipan Das 			 * Set a compatible MSR value explicitly to ensure
548*84022ac1SSandipan Das 			 * that XER and CR bits are updated appropriately
549*84022ac1SSandipan Das 			 */
550*84022ac1SSandipan Das 			exp.msr = MSR_KERNEL;
551*84022ac1SSandipan Das 			got.msr = MSR_KERNEL;
552*84022ac1SSandipan Das 
553*84022ac1SSandipan Das 			if (emulate_compute_instr(&got, instr) ||
554*84022ac1SSandipan Das 			    execute_compute_instr(&exp, instr)) {
555*84022ac1SSandipan Das 				passed = false;
556*84022ac1SSandipan Das 				goto print;
557*84022ac1SSandipan Das 			}
558*84022ac1SSandipan Das 
559*84022ac1SSandipan Das 			/* Verify GPR values */
560*84022ac1SSandipan Das 			for (k = 0; k < 32; k++) {
561*84022ac1SSandipan Das 				ignore_gpr = flags & IGNORE_GPR(k);
562*84022ac1SSandipan Das 				if (!ignore_gpr && exp.gpr[k] != got.gpr[k]) {
563*84022ac1SSandipan Das 					passed = false;
564*84022ac1SSandipan Das 					gpr_mismatch(k, exp.gpr[k], got.gpr[k]);
565*84022ac1SSandipan Das 				}
566*84022ac1SSandipan Das 			}
567*84022ac1SSandipan Das 
568*84022ac1SSandipan Das 			/* Verify LR value */
569*84022ac1SSandipan Das 			if (exp.link != got.link) {
570*84022ac1SSandipan Das 				passed = false;
571*84022ac1SSandipan Das 				reg_mismatch("LR", exp.link, got.link);
572*84022ac1SSandipan Das 			}
573*84022ac1SSandipan Das 
574*84022ac1SSandipan Das 			/* Verify XER value */
575*84022ac1SSandipan Das 			if (!ignore_xer && exp.xer != got.xer) {
576*84022ac1SSandipan Das 				passed = false;
577*84022ac1SSandipan Das 				reg_mismatch("XER", exp.xer, got.xer);
578*84022ac1SSandipan Das 			}
579*84022ac1SSandipan Das 
580*84022ac1SSandipan Das 			/* Verify CR value */
581*84022ac1SSandipan Das 			if (!ignore_ccr && exp.ccr != got.ccr) {
582*84022ac1SSandipan Das 				passed = false;
583*84022ac1SSandipan Das 				reg_mismatch("CR", exp.ccr, got.ccr);
584*84022ac1SSandipan Das 			}
585*84022ac1SSandipan Das 
586*84022ac1SSandipan Das print:
587*84022ac1SSandipan Das 			show_result_with_descr(test->mnemonic,
588*84022ac1SSandipan Das 					       test->subtests[j].descr,
589*84022ac1SSandipan Das 					       passed ? "PASS" : "FAIL");
590*84022ac1SSandipan Das 		}
591*84022ac1SSandipan Das 	}
592*84022ac1SSandipan Das }
593*84022ac1SSandipan Das 
594*84022ac1SSandipan Das static int __init test_emulate_step(void)
595*84022ac1SSandipan Das {
596*84022ac1SSandipan Das 	printk(KERN_INFO "Running instruction emulation self-tests ...\n");
597*84022ac1SSandipan Das 	run_tests_load_store();
598*84022ac1SSandipan Das 	run_tests_compute();
5994ceae137SRavi Bangoria 
6004ceae137SRavi Bangoria 	return 0;
6014ceae137SRavi Bangoria }
6024ceae137SRavi Bangoria late_initcall(test_emulate_step);
603