xref: /openbmc/linux/arch/powerpc/lib/test_emulate_step.c (revision 94afd069d937d84fb4f696eb9a78db4084e43d21)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24ceae137SRavi Bangoria /*
384022ac1SSandipan Das  * Simple sanity tests for instruction emulation infrastructure.
44ceae137SRavi Bangoria  *
54ceae137SRavi Bangoria  * Copyright IBM Corp. 2016
64ceae137SRavi Bangoria  */
74ceae137SRavi Bangoria 
84ceae137SRavi Bangoria #define pr_fmt(fmt) "emulate_step_test: " fmt
94ceae137SRavi Bangoria 
104ceae137SRavi Bangoria #include <linux/ptrace.h>
114ceae137SRavi Bangoria #include <asm/sstep.h>
124ceae137SRavi Bangoria #include <asm/ppc-opcode.h>
1384022ac1SSandipan Das #include <asm/code-patching.h>
1475346251SJordan Niethe #include <asm/inst.h>
154ceae137SRavi Bangoria 
164ceae137SRavi Bangoria #define IMM_L(i)		((uintptr_t)(i) & 0xffff)
173e74a0e1SBalamuruhan S #define IMM_DS(i)		((uintptr_t)(i) & 0xfffc)
184ceae137SRavi Bangoria 
194ceae137SRavi Bangoria /*
204ceae137SRavi Bangoria  * Defined with TEST_ prefix so it does not conflict with other
214ceae137SRavi Bangoria  * definitions.
224ceae137SRavi Bangoria  */
2375346251SJordan Niethe #define TEST_LD(r, base, i)	ppc_inst(PPC_INST_LD | ___PPC_RT(r) |		\
243e74a0e1SBalamuruhan S 					___PPC_RA(base) | IMM_DS(i))
2575346251SJordan Niethe #define TEST_LWZ(r, base, i)	ppc_inst(PPC_INST_LWZ | ___PPC_RT(r) |		\
264ceae137SRavi Bangoria 					___PPC_RA(base) | IMM_L(i))
2775346251SJordan Niethe #define TEST_LWZX(t, a, b)	ppc_inst(PPC_INST_LWZX | ___PPC_RT(t) |		\
284ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
2975346251SJordan Niethe #define TEST_STD(r, base, i)	ppc_inst(PPC_INST_STD | ___PPC_RS(r) |		\
303e74a0e1SBalamuruhan S 					___PPC_RA(base) | IMM_DS(i))
3175346251SJordan Niethe #define TEST_LDARX(t, a, b, eh)	ppc_inst(PPC_INST_LDARX | ___PPC_RT(t) |	\
324ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b) |	\
334ceae137SRavi Bangoria 					__PPC_EH(eh))
3475346251SJordan Niethe #define TEST_STDCX(s, a, b)	ppc_inst(PPC_INST_STDCX | ___PPC_RS(s) |	\
354ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
3675346251SJordan Niethe #define TEST_LFSX(t, a, b)	ppc_inst(PPC_INST_LFSX | ___PPC_RT(t) |		\
374ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
3875346251SJordan Niethe #define TEST_STFSX(s, a, b)	ppc_inst(PPC_INST_STFSX | ___PPC_RS(s) |	\
394ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
4075346251SJordan Niethe #define TEST_LFDX(t, a, b)	ppc_inst(PPC_INST_LFDX | ___PPC_RT(t) |		\
414ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
4275346251SJordan Niethe #define TEST_STFDX(s, a, b)	ppc_inst(PPC_INST_STFDX | ___PPC_RS(s) |	\
434ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
4475346251SJordan Niethe #define TEST_LVX(t, a, b)	ppc_inst(PPC_INST_LVX | ___PPC_RT(t) |		\
454ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
4675346251SJordan Niethe #define TEST_STVX(s, a, b)	ppc_inst(PPC_INST_STVX | ___PPC_RS(s) |		\
474ceae137SRavi Bangoria 					___PPC_RA(a) | ___PPC_RB(b))
4875346251SJordan Niethe #define TEST_LXVD2X(s, a, b)	ppc_inst(PPC_INST_LXVD2X | VSX_XX1((s), R##a, R##b))
4975346251SJordan Niethe #define TEST_STXVD2X(s, a, b)	ppc_inst(PPC_INST_STXVD2X | VSX_XX1((s), R##a, R##b))
5075346251SJordan Niethe #define TEST_ADD(t, a, b)	ppc_inst(PPC_INST_ADD | ___PPC_RT(t) |		\
5144dea178SSandipan Das 					___PPC_RA(a) | ___PPC_RB(b))
5275346251SJordan Niethe #define TEST_ADD_DOT(t, a, b)	ppc_inst(PPC_INST_ADD | ___PPC_RT(t) |		\
5344dea178SSandipan Das 					___PPC_RA(a) | ___PPC_RB(b) | 0x1)
5475346251SJordan Niethe #define TEST_ADDC(t, a, b)	ppc_inst(PPC_INST_ADDC | ___PPC_RT(t) |		\
5578a8da06SSandipan Das 					___PPC_RA(a) | ___PPC_RB(b))
5675346251SJordan Niethe #define TEST_ADDC_DOT(t, a, b)	ppc_inst(PPC_INST_ADDC | ___PPC_RT(t) |		\
5778a8da06SSandipan Das 					___PPC_RA(a) | ___PPC_RB(b) | 0x1)
584ceae137SRavi Bangoria 
5984022ac1SSandipan Das #define MAX_SUBTESTS	16
6084022ac1SSandipan Das 
6184022ac1SSandipan Das #define IGNORE_GPR(n)	(0x1UL << (n))
6284022ac1SSandipan Das #define IGNORE_XER	(0x1UL << 32)
6384022ac1SSandipan Das #define IGNORE_CCR	(0x1UL << 33)
644ceae137SRavi Bangoria 
654ceae137SRavi Bangoria static void __init init_pt_regs(struct pt_regs *regs)
664ceae137SRavi Bangoria {
674ceae137SRavi Bangoria 	static unsigned long msr;
684ceae137SRavi Bangoria 	static bool msr_cached;
694ceae137SRavi Bangoria 
704ceae137SRavi Bangoria 	memset(regs, 0, sizeof(struct pt_regs));
714ceae137SRavi Bangoria 
724ceae137SRavi Bangoria 	if (likely(msr_cached)) {
734ceae137SRavi Bangoria 		regs->msr = msr;
744ceae137SRavi Bangoria 		return;
754ceae137SRavi Bangoria 	}
764ceae137SRavi Bangoria 
774ceae137SRavi Bangoria 	asm volatile("mfmsr %0" : "=r"(regs->msr));
784ceae137SRavi Bangoria 
794ceae137SRavi Bangoria 	regs->msr |= MSR_FP;
804ceae137SRavi Bangoria 	regs->msr |= MSR_VEC;
814ceae137SRavi Bangoria 	regs->msr |= MSR_VSX;
824ceae137SRavi Bangoria 
834ceae137SRavi Bangoria 	msr = regs->msr;
844ceae137SRavi Bangoria 	msr_cached = true;
854ceae137SRavi Bangoria }
864ceae137SRavi Bangoria 
8784022ac1SSandipan Das static void __init show_result(char *mnemonic, char *result)
884ceae137SRavi Bangoria {
8984022ac1SSandipan Das 	pr_info("%-14s : %s\n", mnemonic, result);
9084022ac1SSandipan Das }
9184022ac1SSandipan Das 
9284022ac1SSandipan Das static void __init show_result_with_descr(char *mnemonic, char *descr,
9384022ac1SSandipan Das 					  char *result)
9484022ac1SSandipan Das {
9584022ac1SSandipan Das 	pr_info("%-14s : %-50s %s\n", mnemonic, descr, result);
964ceae137SRavi Bangoria }
974ceae137SRavi Bangoria 
984ceae137SRavi Bangoria static void __init test_ld(void)
994ceae137SRavi Bangoria {
1004ceae137SRavi Bangoria 	struct pt_regs regs;
1014ceae137SRavi Bangoria 	unsigned long a = 0x23;
1024ceae137SRavi Bangoria 	int stepped = -1;
1034ceae137SRavi Bangoria 
1044ceae137SRavi Bangoria 	init_pt_regs(&regs);
1054ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &a;
1064ceae137SRavi Bangoria 
1074ceae137SRavi Bangoria 	/* ld r5, 0(r3) */
1084ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LD(5, 3, 0));
1094ceae137SRavi Bangoria 
1104ceae137SRavi Bangoria 	if (stepped == 1 && regs.gpr[5] == a)
1114ceae137SRavi Bangoria 		show_result("ld", "PASS");
1124ceae137SRavi Bangoria 	else
1134ceae137SRavi Bangoria 		show_result("ld", "FAIL");
1144ceae137SRavi Bangoria }
1154ceae137SRavi Bangoria 
1164ceae137SRavi Bangoria static void __init test_lwz(void)
1174ceae137SRavi Bangoria {
1184ceae137SRavi Bangoria 	struct pt_regs regs;
1194ceae137SRavi Bangoria 	unsigned int a = 0x4545;
1204ceae137SRavi Bangoria 	int stepped = -1;
1214ceae137SRavi Bangoria 
1224ceae137SRavi Bangoria 	init_pt_regs(&regs);
1234ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &a;
1244ceae137SRavi Bangoria 
1254ceae137SRavi Bangoria 	/* lwz r5, 0(r3) */
1264ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LWZ(5, 3, 0));
1274ceae137SRavi Bangoria 
1284ceae137SRavi Bangoria 	if (stepped == 1 && regs.gpr[5] == a)
1294ceae137SRavi Bangoria 		show_result("lwz", "PASS");
1304ceae137SRavi Bangoria 	else
1314ceae137SRavi Bangoria 		show_result("lwz", "FAIL");
1324ceae137SRavi Bangoria }
1334ceae137SRavi Bangoria 
1344ceae137SRavi Bangoria static void __init test_lwzx(void)
1354ceae137SRavi Bangoria {
1364ceae137SRavi Bangoria 	struct pt_regs regs;
1374ceae137SRavi Bangoria 	unsigned int a[3] = {0x0, 0x0, 0x1234};
1384ceae137SRavi Bangoria 	int stepped = -1;
1394ceae137SRavi Bangoria 
1404ceae137SRavi Bangoria 	init_pt_regs(&regs);
1414ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) a;
1424ceae137SRavi Bangoria 	regs.gpr[4] = 8;
1434ceae137SRavi Bangoria 	regs.gpr[5] = 0x8765;
1444ceae137SRavi Bangoria 
1454ceae137SRavi Bangoria 	/* lwzx r5, r3, r4 */
1464ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LWZX(5, 3, 4));
1474ceae137SRavi Bangoria 	if (stepped == 1 && regs.gpr[5] == a[2])
1484ceae137SRavi Bangoria 		show_result("lwzx", "PASS");
1494ceae137SRavi Bangoria 	else
1504ceae137SRavi Bangoria 		show_result("lwzx", "FAIL");
1514ceae137SRavi Bangoria }
1524ceae137SRavi Bangoria 
1534ceae137SRavi Bangoria static void __init test_std(void)
1544ceae137SRavi Bangoria {
1554ceae137SRavi Bangoria 	struct pt_regs regs;
1564ceae137SRavi Bangoria 	unsigned long a = 0x1234;
1574ceae137SRavi Bangoria 	int stepped = -1;
1584ceae137SRavi Bangoria 
1594ceae137SRavi Bangoria 	init_pt_regs(&regs);
1604ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &a;
1614ceae137SRavi Bangoria 	regs.gpr[5] = 0x5678;
1624ceae137SRavi Bangoria 
1634ceae137SRavi Bangoria 	/* std r5, 0(r3) */
1644ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_STD(5, 3, 0));
16559ed2adfSNicholas Piggin 	if (stepped == 1 && regs.gpr[5] == a)
1664ceae137SRavi Bangoria 		show_result("std", "PASS");
1674ceae137SRavi Bangoria 	else
1684ceae137SRavi Bangoria 		show_result("std", "FAIL");
1694ceae137SRavi Bangoria }
1704ceae137SRavi Bangoria 
1714ceae137SRavi Bangoria static void __init test_ldarx_stdcx(void)
1724ceae137SRavi Bangoria {
1734ceae137SRavi Bangoria 	struct pt_regs regs;
1744ceae137SRavi Bangoria 	unsigned long a = 0x1234;
1754ceae137SRavi Bangoria 	int stepped = -1;
1764ceae137SRavi Bangoria 	unsigned long cr0_eq = 0x1 << 29; /* eq bit of CR0 */
1774ceae137SRavi Bangoria 
1784ceae137SRavi Bangoria 	init_pt_regs(&regs);
1794ceae137SRavi Bangoria 	asm volatile("mfcr %0" : "=r"(regs.ccr));
1804ceae137SRavi Bangoria 
1814ceae137SRavi Bangoria 
1824ceae137SRavi Bangoria 	/*** ldarx ***/
1834ceae137SRavi Bangoria 
1844ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &a;
1854ceae137SRavi Bangoria 	regs.gpr[4] = 0;
1864ceae137SRavi Bangoria 	regs.gpr[5] = 0x5678;
1874ceae137SRavi Bangoria 
1884ceae137SRavi Bangoria 	/* ldarx r5, r3, r4, 0 */
1894ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LDARX(5, 3, 4, 0));
1904ceae137SRavi Bangoria 
1914ceae137SRavi Bangoria 	/*
1924ceae137SRavi Bangoria 	 * Don't touch 'a' here. Touching 'a' can do Load/store
1934ceae137SRavi Bangoria 	 * of 'a' which result in failure of subsequent stdcx.
1944ceae137SRavi Bangoria 	 * Instead, use hardcoded value for comparison.
1954ceae137SRavi Bangoria 	 */
1964ceae137SRavi Bangoria 	if (stepped <= 0 || regs.gpr[5] != 0x1234) {
1974ceae137SRavi Bangoria 		show_result("ldarx / stdcx.", "FAIL (ldarx)");
1984ceae137SRavi Bangoria 		return;
1994ceae137SRavi Bangoria 	}
2004ceae137SRavi Bangoria 
2014ceae137SRavi Bangoria 
2024ceae137SRavi Bangoria 	/*** stdcx. ***/
2034ceae137SRavi Bangoria 
2044ceae137SRavi Bangoria 	regs.gpr[5] = 0x9ABC;
2054ceae137SRavi Bangoria 
2064ceae137SRavi Bangoria 	/* stdcx. r5, r3, r4 */
2074ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_STDCX(5, 3, 4));
2084ceae137SRavi Bangoria 
2094ceae137SRavi Bangoria 	/*
2104ceae137SRavi Bangoria 	 * Two possible scenarios that indicates successful emulation
2114ceae137SRavi Bangoria 	 * of stdcx. :
2124ceae137SRavi Bangoria 	 *  1. Reservation is active and store is performed. In this
2134ceae137SRavi Bangoria 	 *     case cr0.eq bit will be set to 1.
2144ceae137SRavi Bangoria 	 *  2. Reservation is not active and store is not performed.
2154ceae137SRavi Bangoria 	 *     In this case cr0.eq bit will be set to 0.
2164ceae137SRavi Bangoria 	 */
2174ceae137SRavi Bangoria 	if (stepped == 1 && ((regs.gpr[5] == a && (regs.ccr & cr0_eq))
2184ceae137SRavi Bangoria 			|| (regs.gpr[5] != a && !(regs.ccr & cr0_eq))))
2194ceae137SRavi Bangoria 		show_result("ldarx / stdcx.", "PASS");
2204ceae137SRavi Bangoria 	else
2214ceae137SRavi Bangoria 		show_result("ldarx / stdcx.", "FAIL (stdcx.)");
2224ceae137SRavi Bangoria }
2234ceae137SRavi Bangoria 
2244ceae137SRavi Bangoria #ifdef CONFIG_PPC_FPU
2254ceae137SRavi Bangoria static void __init test_lfsx_stfsx(void)
2264ceae137SRavi Bangoria {
2274ceae137SRavi Bangoria 	struct pt_regs regs;
2284ceae137SRavi Bangoria 	union {
2294ceae137SRavi Bangoria 		float a;
2304ceae137SRavi Bangoria 		int b;
2314ceae137SRavi Bangoria 	} c;
2324ceae137SRavi Bangoria 	int cached_b;
2334ceae137SRavi Bangoria 	int stepped = -1;
2344ceae137SRavi Bangoria 
2354ceae137SRavi Bangoria 	init_pt_regs(&regs);
2364ceae137SRavi Bangoria 
2374ceae137SRavi Bangoria 
2384ceae137SRavi Bangoria 	/*** lfsx ***/
2394ceae137SRavi Bangoria 
2404ceae137SRavi Bangoria 	c.a = 123.45;
2414ceae137SRavi Bangoria 	cached_b = c.b;
2424ceae137SRavi Bangoria 
2434ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &c.a;
2444ceae137SRavi Bangoria 	regs.gpr[4] = 0;
2454ceae137SRavi Bangoria 
2464ceae137SRavi Bangoria 	/* lfsx frt10, r3, r4 */
2474ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LFSX(10, 3, 4));
2484ceae137SRavi Bangoria 
2494ceae137SRavi Bangoria 	if (stepped == 1)
2504ceae137SRavi Bangoria 		show_result("lfsx", "PASS");
2514ceae137SRavi Bangoria 	else
2524ceae137SRavi Bangoria 		show_result("lfsx", "FAIL");
2534ceae137SRavi Bangoria 
2544ceae137SRavi Bangoria 
2554ceae137SRavi Bangoria 	/*** stfsx ***/
2564ceae137SRavi Bangoria 
2574ceae137SRavi Bangoria 	c.a = 678.91;
2584ceae137SRavi Bangoria 
2594ceae137SRavi Bangoria 	/* stfsx frs10, r3, r4 */
2604ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_STFSX(10, 3, 4));
2614ceae137SRavi Bangoria 
2624ceae137SRavi Bangoria 	if (stepped == 1 && c.b == cached_b)
2634ceae137SRavi Bangoria 		show_result("stfsx", "PASS");
2644ceae137SRavi Bangoria 	else
2654ceae137SRavi Bangoria 		show_result("stfsx", "FAIL");
2664ceae137SRavi Bangoria }
2674ceae137SRavi Bangoria 
2684ceae137SRavi Bangoria static void __init test_lfdx_stfdx(void)
2694ceae137SRavi Bangoria {
2704ceae137SRavi Bangoria 	struct pt_regs regs;
2714ceae137SRavi Bangoria 	union {
2724ceae137SRavi Bangoria 		double a;
2734ceae137SRavi Bangoria 		long b;
2744ceae137SRavi Bangoria 	} c;
2754ceae137SRavi Bangoria 	long cached_b;
2764ceae137SRavi Bangoria 	int stepped = -1;
2774ceae137SRavi Bangoria 
2784ceae137SRavi Bangoria 	init_pt_regs(&regs);
2794ceae137SRavi Bangoria 
2804ceae137SRavi Bangoria 
2814ceae137SRavi Bangoria 	/*** lfdx ***/
2824ceae137SRavi Bangoria 
2834ceae137SRavi Bangoria 	c.a = 123456.78;
2844ceae137SRavi Bangoria 	cached_b = c.b;
2854ceae137SRavi Bangoria 
2864ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &c.a;
2874ceae137SRavi Bangoria 	regs.gpr[4] = 0;
2884ceae137SRavi Bangoria 
2894ceae137SRavi Bangoria 	/* lfdx frt10, r3, r4 */
2904ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LFDX(10, 3, 4));
2914ceae137SRavi Bangoria 
2924ceae137SRavi Bangoria 	if (stepped == 1)
2934ceae137SRavi Bangoria 		show_result("lfdx", "PASS");
2944ceae137SRavi Bangoria 	else
2954ceae137SRavi Bangoria 		show_result("lfdx", "FAIL");
2964ceae137SRavi Bangoria 
2974ceae137SRavi Bangoria 
2984ceae137SRavi Bangoria 	/*** stfdx ***/
2994ceae137SRavi Bangoria 
3004ceae137SRavi Bangoria 	c.a = 987654.32;
3014ceae137SRavi Bangoria 
3024ceae137SRavi Bangoria 	/* stfdx frs10, r3, r4 */
3034ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_STFDX(10, 3, 4));
3044ceae137SRavi Bangoria 
3054ceae137SRavi Bangoria 	if (stepped == 1 && c.b == cached_b)
3064ceae137SRavi Bangoria 		show_result("stfdx", "PASS");
3074ceae137SRavi Bangoria 	else
3084ceae137SRavi Bangoria 		show_result("stfdx", "FAIL");
3094ceae137SRavi Bangoria }
3104ceae137SRavi Bangoria #else
3114ceae137SRavi Bangoria static void __init test_lfsx_stfsx(void)
3124ceae137SRavi Bangoria {
3134ceae137SRavi Bangoria 	show_result("lfsx", "SKIP (CONFIG_PPC_FPU is not set)");
3144ceae137SRavi Bangoria 	show_result("stfsx", "SKIP (CONFIG_PPC_FPU is not set)");
3154ceae137SRavi Bangoria }
3164ceae137SRavi Bangoria 
3174ceae137SRavi Bangoria static void __init test_lfdx_stfdx(void)
3184ceae137SRavi Bangoria {
3194ceae137SRavi Bangoria 	show_result("lfdx", "SKIP (CONFIG_PPC_FPU is not set)");
3204ceae137SRavi Bangoria 	show_result("stfdx", "SKIP (CONFIG_PPC_FPU is not set)");
3214ceae137SRavi Bangoria }
3224ceae137SRavi Bangoria #endif /* CONFIG_PPC_FPU */
3234ceae137SRavi Bangoria 
3244ceae137SRavi Bangoria #ifdef CONFIG_ALTIVEC
3254ceae137SRavi Bangoria static void __init test_lvx_stvx(void)
3264ceae137SRavi Bangoria {
3274ceae137SRavi Bangoria 	struct pt_regs regs;
3284ceae137SRavi Bangoria 	union {
3294ceae137SRavi Bangoria 		vector128 a;
3304ceae137SRavi Bangoria 		u32 b[4];
3314ceae137SRavi Bangoria 	} c;
3324ceae137SRavi Bangoria 	u32 cached_b[4];
3334ceae137SRavi Bangoria 	int stepped = -1;
3344ceae137SRavi Bangoria 
3354ceae137SRavi Bangoria 	init_pt_regs(&regs);
3364ceae137SRavi Bangoria 
3374ceae137SRavi Bangoria 
3384ceae137SRavi Bangoria 	/*** lvx ***/
3394ceae137SRavi Bangoria 
3404ceae137SRavi Bangoria 	cached_b[0] = c.b[0] = 923745;
3414ceae137SRavi Bangoria 	cached_b[1] = c.b[1] = 2139478;
3424ceae137SRavi Bangoria 	cached_b[2] = c.b[2] = 9012;
3434ceae137SRavi Bangoria 	cached_b[3] = c.b[3] = 982134;
3444ceae137SRavi Bangoria 
3454ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &c.a;
3464ceae137SRavi Bangoria 	regs.gpr[4] = 0;
3474ceae137SRavi Bangoria 
3484ceae137SRavi Bangoria 	/* lvx vrt10, r3, r4 */
3494ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LVX(10, 3, 4));
3504ceae137SRavi Bangoria 
3514ceae137SRavi Bangoria 	if (stepped == 1)
3524ceae137SRavi Bangoria 		show_result("lvx", "PASS");
3534ceae137SRavi Bangoria 	else
3544ceae137SRavi Bangoria 		show_result("lvx", "FAIL");
3554ceae137SRavi Bangoria 
3564ceae137SRavi Bangoria 
3574ceae137SRavi Bangoria 	/*** stvx ***/
3584ceae137SRavi Bangoria 
3594ceae137SRavi Bangoria 	c.b[0] = 4987513;
3604ceae137SRavi Bangoria 	c.b[1] = 84313948;
3614ceae137SRavi Bangoria 	c.b[2] = 71;
3624ceae137SRavi Bangoria 	c.b[3] = 498532;
3634ceae137SRavi Bangoria 
3644ceae137SRavi Bangoria 	/* stvx vrs10, r3, r4 */
3654ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_STVX(10, 3, 4));
3664ceae137SRavi Bangoria 
3674ceae137SRavi Bangoria 	if (stepped == 1 && cached_b[0] == c.b[0] && cached_b[1] == c.b[1] &&
3684ceae137SRavi Bangoria 	    cached_b[2] == c.b[2] && cached_b[3] == c.b[3])
3694ceae137SRavi Bangoria 		show_result("stvx", "PASS");
3704ceae137SRavi Bangoria 	else
3714ceae137SRavi Bangoria 		show_result("stvx", "FAIL");
3724ceae137SRavi Bangoria }
3734ceae137SRavi Bangoria #else
3744ceae137SRavi Bangoria static void __init test_lvx_stvx(void)
3754ceae137SRavi Bangoria {
3764ceae137SRavi Bangoria 	show_result("lvx", "SKIP (CONFIG_ALTIVEC is not set)");
3774ceae137SRavi Bangoria 	show_result("stvx", "SKIP (CONFIG_ALTIVEC is not set)");
3784ceae137SRavi Bangoria }
3794ceae137SRavi Bangoria #endif /* CONFIG_ALTIVEC */
3804ceae137SRavi Bangoria 
3814ceae137SRavi Bangoria #ifdef CONFIG_VSX
3824ceae137SRavi Bangoria static void __init test_lxvd2x_stxvd2x(void)
3834ceae137SRavi Bangoria {
3844ceae137SRavi Bangoria 	struct pt_regs regs;
3854ceae137SRavi Bangoria 	union {
3864ceae137SRavi Bangoria 		vector128 a;
3874ceae137SRavi Bangoria 		u32 b[4];
3884ceae137SRavi Bangoria 	} c;
3894ceae137SRavi Bangoria 	u32 cached_b[4];
3904ceae137SRavi Bangoria 	int stepped = -1;
3914ceae137SRavi Bangoria 
3924ceae137SRavi Bangoria 	init_pt_regs(&regs);
3934ceae137SRavi Bangoria 
3944ceae137SRavi Bangoria 
3954ceae137SRavi Bangoria 	/*** lxvd2x ***/
3964ceae137SRavi Bangoria 
3974ceae137SRavi Bangoria 	cached_b[0] = c.b[0] = 18233;
3984ceae137SRavi Bangoria 	cached_b[1] = c.b[1] = 34863571;
3994ceae137SRavi Bangoria 	cached_b[2] = c.b[2] = 834;
4004ceae137SRavi Bangoria 	cached_b[3] = c.b[3] = 6138911;
4014ceae137SRavi Bangoria 
4024ceae137SRavi Bangoria 	regs.gpr[3] = (unsigned long) &c.a;
4034ceae137SRavi Bangoria 	regs.gpr[4] = 0;
4044ceae137SRavi Bangoria 
4054ceae137SRavi Bangoria 	/* lxvd2x vsr39, r3, r4 */
4064ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_LXVD2X(39, 3, 4));
4074ceae137SRavi Bangoria 
4085a61640eSRavi Bangoria 	if (stepped == 1 && cpu_has_feature(CPU_FTR_VSX)) {
4094ceae137SRavi Bangoria 		show_result("lxvd2x", "PASS");
4105a61640eSRavi Bangoria 	} else {
4115a61640eSRavi Bangoria 		if (!cpu_has_feature(CPU_FTR_VSX))
4125a61640eSRavi Bangoria 			show_result("lxvd2x", "PASS (!CPU_FTR_VSX)");
4134ceae137SRavi Bangoria 		else
4144ceae137SRavi Bangoria 			show_result("lxvd2x", "FAIL");
4155a61640eSRavi Bangoria 	}
4164ceae137SRavi Bangoria 
4174ceae137SRavi Bangoria 
4184ceae137SRavi Bangoria 	/*** stxvd2x ***/
4194ceae137SRavi Bangoria 
4204ceae137SRavi Bangoria 	c.b[0] = 21379463;
4214ceae137SRavi Bangoria 	c.b[1] = 87;
4224ceae137SRavi Bangoria 	c.b[2] = 374234;
4234ceae137SRavi Bangoria 	c.b[3] = 4;
4244ceae137SRavi Bangoria 
4254ceae137SRavi Bangoria 	/* stxvd2x vsr39, r3, r4 */
4264ceae137SRavi Bangoria 	stepped = emulate_step(&regs, TEST_STXVD2X(39, 3, 4));
4274ceae137SRavi Bangoria 
4284ceae137SRavi Bangoria 	if (stepped == 1 && cached_b[0] == c.b[0] && cached_b[1] == c.b[1] &&
4295a61640eSRavi Bangoria 	    cached_b[2] == c.b[2] && cached_b[3] == c.b[3] &&
4305a61640eSRavi Bangoria 	    cpu_has_feature(CPU_FTR_VSX)) {
4314ceae137SRavi Bangoria 		show_result("stxvd2x", "PASS");
4325a61640eSRavi Bangoria 	} else {
4335a61640eSRavi Bangoria 		if (!cpu_has_feature(CPU_FTR_VSX))
4345a61640eSRavi Bangoria 			show_result("stxvd2x", "PASS (!CPU_FTR_VSX)");
4354ceae137SRavi Bangoria 		else
4364ceae137SRavi Bangoria 			show_result("stxvd2x", "FAIL");
4374ceae137SRavi Bangoria 	}
4385a61640eSRavi Bangoria }
4394ceae137SRavi Bangoria #else
4404ceae137SRavi Bangoria static void __init test_lxvd2x_stxvd2x(void)
4414ceae137SRavi Bangoria {
4424ceae137SRavi Bangoria 	show_result("lxvd2x", "SKIP (CONFIG_VSX is not set)");
4434ceae137SRavi Bangoria 	show_result("stxvd2x", "SKIP (CONFIG_VSX is not set)");
4444ceae137SRavi Bangoria }
4454ceae137SRavi Bangoria #endif /* CONFIG_VSX */
4464ceae137SRavi Bangoria 
44784022ac1SSandipan Das static void __init run_tests_load_store(void)
4484ceae137SRavi Bangoria {
4494ceae137SRavi Bangoria 	test_ld();
4504ceae137SRavi Bangoria 	test_lwz();
4514ceae137SRavi Bangoria 	test_lwzx();
4524ceae137SRavi Bangoria 	test_std();
4534ceae137SRavi Bangoria 	test_ldarx_stdcx();
4544ceae137SRavi Bangoria 	test_lfsx_stfsx();
4554ceae137SRavi Bangoria 	test_lfdx_stfdx();
4564ceae137SRavi Bangoria 	test_lvx_stvx();
4574ceae137SRavi Bangoria 	test_lxvd2x_stxvd2x();
45884022ac1SSandipan Das }
45984022ac1SSandipan Das 
46084022ac1SSandipan Das struct compute_test {
46184022ac1SSandipan Das 	char *mnemonic;
46284022ac1SSandipan Das 	struct {
46384022ac1SSandipan Das 		char *descr;
46484022ac1SSandipan Das 		unsigned long flags;
465*94afd069SJordan Niethe 		struct ppc_inst instr;
46684022ac1SSandipan Das 		struct pt_regs regs;
46784022ac1SSandipan Das 	} subtests[MAX_SUBTESTS + 1];
46884022ac1SSandipan Das };
46984022ac1SSandipan Das 
47084022ac1SSandipan Das static struct compute_test compute_tests[] = {
47184022ac1SSandipan Das 	{
47284022ac1SSandipan Das 		.mnemonic = "nop",
47384022ac1SSandipan Das 		.subtests = {
47484022ac1SSandipan Das 			{
47584022ac1SSandipan Das 				.descr = "R0 = LONG_MAX",
47675346251SJordan Niethe 				.instr = ppc_inst(PPC_INST_NOP),
47784022ac1SSandipan Das 				.regs = {
47884022ac1SSandipan Das 					.gpr[0] = LONG_MAX,
47984022ac1SSandipan Das 				}
48084022ac1SSandipan Das 			}
48184022ac1SSandipan Das 		}
48244dea178SSandipan Das 	},
48344dea178SSandipan Das 	{
48444dea178SSandipan Das 		.mnemonic = "add",
48544dea178SSandipan Das 		.subtests = {
48644dea178SSandipan Das 			{
48744dea178SSandipan Das 				.descr = "RA = LONG_MIN, RB = LONG_MIN",
48844dea178SSandipan Das 				.instr = TEST_ADD(20, 21, 22),
48944dea178SSandipan Das 				.regs = {
49044dea178SSandipan Das 					.gpr[21] = LONG_MIN,
49144dea178SSandipan Das 					.gpr[22] = LONG_MIN,
49244dea178SSandipan Das 				}
49344dea178SSandipan Das 			},
49444dea178SSandipan Das 			{
49544dea178SSandipan Das 				.descr = "RA = LONG_MIN, RB = LONG_MAX",
49644dea178SSandipan Das 				.instr = TEST_ADD(20, 21, 22),
49744dea178SSandipan Das 				.regs = {
49844dea178SSandipan Das 					.gpr[21] = LONG_MIN,
49944dea178SSandipan Das 					.gpr[22] = LONG_MAX,
50044dea178SSandipan Das 				}
50144dea178SSandipan Das 			},
50244dea178SSandipan Das 			{
50344dea178SSandipan Das 				.descr = "RA = LONG_MAX, RB = LONG_MAX",
50444dea178SSandipan Das 				.instr = TEST_ADD(20, 21, 22),
50544dea178SSandipan Das 				.regs = {
50644dea178SSandipan Das 					.gpr[21] = LONG_MAX,
50744dea178SSandipan Das 					.gpr[22] = LONG_MAX,
50844dea178SSandipan Das 				}
50944dea178SSandipan Das 			},
51044dea178SSandipan Das 			{
51144dea178SSandipan Das 				.descr = "RA = ULONG_MAX, RB = ULONG_MAX",
51244dea178SSandipan Das 				.instr = TEST_ADD(20, 21, 22),
51344dea178SSandipan Das 				.regs = {
51444dea178SSandipan Das 					.gpr[21] = ULONG_MAX,
51544dea178SSandipan Das 					.gpr[22] = ULONG_MAX,
51644dea178SSandipan Das 				}
51744dea178SSandipan Das 			},
51844dea178SSandipan Das 			{
51944dea178SSandipan Das 				.descr = "RA = ULONG_MAX, RB = 0x1",
52044dea178SSandipan Das 				.instr = TEST_ADD(20, 21, 22),
52144dea178SSandipan Das 				.regs = {
52244dea178SSandipan Das 					.gpr[21] = ULONG_MAX,
52344dea178SSandipan Das 					.gpr[22] = 0x1,
52444dea178SSandipan Das 				}
52544dea178SSandipan Das 			},
52644dea178SSandipan Das 			{
52744dea178SSandipan Das 				.descr = "RA = INT_MIN, RB = INT_MIN",
52844dea178SSandipan Das 				.instr = TEST_ADD(20, 21, 22),
52944dea178SSandipan Das 				.regs = {
53044dea178SSandipan Das 					.gpr[21] = INT_MIN,
53144dea178SSandipan Das 					.gpr[22] = INT_MIN,
53244dea178SSandipan Das 				}
53344dea178SSandipan Das 			},
53444dea178SSandipan Das 			{
53544dea178SSandipan Das 				.descr = "RA = INT_MIN, RB = INT_MAX",
53644dea178SSandipan Das 				.instr = TEST_ADD(20, 21, 22),
53744dea178SSandipan Das 				.regs = {
53844dea178SSandipan Das 					.gpr[21] = INT_MIN,
53944dea178SSandipan Das 					.gpr[22] = INT_MAX,
54044dea178SSandipan Das 				}
54144dea178SSandipan Das 			},
54244dea178SSandipan Das 			{
54344dea178SSandipan Das 				.descr = "RA = INT_MAX, RB = INT_MAX",
54444dea178SSandipan Das 				.instr = TEST_ADD(20, 21, 22),
54544dea178SSandipan Das 				.regs = {
54644dea178SSandipan Das 					.gpr[21] = INT_MAX,
54744dea178SSandipan Das 					.gpr[22] = INT_MAX,
54844dea178SSandipan Das 				}
54944dea178SSandipan Das 			},
55044dea178SSandipan Das 			{
55144dea178SSandipan Das 				.descr = "RA = UINT_MAX, RB = UINT_MAX",
55244dea178SSandipan Das 				.instr = TEST_ADD(20, 21, 22),
55344dea178SSandipan Das 				.regs = {
55444dea178SSandipan Das 					.gpr[21] = UINT_MAX,
55544dea178SSandipan Das 					.gpr[22] = UINT_MAX,
55644dea178SSandipan Das 				}
55744dea178SSandipan Das 			},
55844dea178SSandipan Das 			{
55944dea178SSandipan Das 				.descr = "RA = UINT_MAX, RB = 0x1",
56044dea178SSandipan Das 				.instr = TEST_ADD(20, 21, 22),
56144dea178SSandipan Das 				.regs = {
56244dea178SSandipan Das 					.gpr[21] = UINT_MAX,
56344dea178SSandipan Das 					.gpr[22] = 0x1,
56444dea178SSandipan Das 				}
56544dea178SSandipan Das 			}
56644dea178SSandipan Das 		}
56744dea178SSandipan Das 	},
56844dea178SSandipan Das 	{
56944dea178SSandipan Das 		.mnemonic = "add.",
57044dea178SSandipan Das 		.subtests = {
57144dea178SSandipan Das 			{
57244dea178SSandipan Das 				.descr = "RA = LONG_MIN, RB = LONG_MIN",
57344dea178SSandipan Das 				.flags = IGNORE_CCR,
57444dea178SSandipan Das 				.instr = TEST_ADD_DOT(20, 21, 22),
57544dea178SSandipan Das 				.regs = {
57644dea178SSandipan Das 					.gpr[21] = LONG_MIN,
57744dea178SSandipan Das 					.gpr[22] = LONG_MIN,
57844dea178SSandipan Das 				}
57944dea178SSandipan Das 			},
58044dea178SSandipan Das 			{
58144dea178SSandipan Das 				.descr = "RA = LONG_MIN, RB = LONG_MAX",
58244dea178SSandipan Das 				.instr = TEST_ADD_DOT(20, 21, 22),
58344dea178SSandipan Das 				.regs = {
58444dea178SSandipan Das 					.gpr[21] = LONG_MIN,
58544dea178SSandipan Das 					.gpr[22] = LONG_MAX,
58644dea178SSandipan Das 				}
58744dea178SSandipan Das 			},
58844dea178SSandipan Das 			{
58944dea178SSandipan Das 				.descr = "RA = LONG_MAX, RB = LONG_MAX",
59044dea178SSandipan Das 				.flags = IGNORE_CCR,
59144dea178SSandipan Das 				.instr = TEST_ADD_DOT(20, 21, 22),
59244dea178SSandipan Das 				.regs = {
59344dea178SSandipan Das 					.gpr[21] = LONG_MAX,
59444dea178SSandipan Das 					.gpr[22] = LONG_MAX,
59544dea178SSandipan Das 				}
59644dea178SSandipan Das 			},
59744dea178SSandipan Das 			{
59844dea178SSandipan Das 				.descr = "RA = ULONG_MAX, RB = ULONG_MAX",
59944dea178SSandipan Das 				.instr = TEST_ADD_DOT(20, 21, 22),
60044dea178SSandipan Das 				.regs = {
60144dea178SSandipan Das 					.gpr[21] = ULONG_MAX,
60244dea178SSandipan Das 					.gpr[22] = ULONG_MAX,
60344dea178SSandipan Das 				}
60444dea178SSandipan Das 			},
60544dea178SSandipan Das 			{
60644dea178SSandipan Das 				.descr = "RA = ULONG_MAX, RB = 0x1",
60744dea178SSandipan Das 				.instr = TEST_ADD_DOT(20, 21, 22),
60844dea178SSandipan Das 				.regs = {
60944dea178SSandipan Das 					.gpr[21] = ULONG_MAX,
61044dea178SSandipan Das 					.gpr[22] = 0x1,
61144dea178SSandipan Das 				}
61244dea178SSandipan Das 			},
61344dea178SSandipan Das 			{
61444dea178SSandipan Das 				.descr = "RA = INT_MIN, RB = INT_MIN",
61544dea178SSandipan Das 				.instr = TEST_ADD_DOT(20, 21, 22),
61644dea178SSandipan Das 				.regs = {
61744dea178SSandipan Das 					.gpr[21] = INT_MIN,
61844dea178SSandipan Das 					.gpr[22] = INT_MIN,
61944dea178SSandipan Das 				}
62044dea178SSandipan Das 			},
62144dea178SSandipan Das 			{
62244dea178SSandipan Das 				.descr = "RA = INT_MIN, RB = INT_MAX",
62344dea178SSandipan Das 				.instr = TEST_ADD_DOT(20, 21, 22),
62444dea178SSandipan Das 				.regs = {
62544dea178SSandipan Das 					.gpr[21] = INT_MIN,
62644dea178SSandipan Das 					.gpr[22] = INT_MAX,
62744dea178SSandipan Das 				}
62844dea178SSandipan Das 			},
62944dea178SSandipan Das 			{
63044dea178SSandipan Das 				.descr = "RA = INT_MAX, RB = INT_MAX",
63144dea178SSandipan Das 				.instr = TEST_ADD_DOT(20, 21, 22),
63244dea178SSandipan Das 				.regs = {
63344dea178SSandipan Das 					.gpr[21] = INT_MAX,
63444dea178SSandipan Das 					.gpr[22] = INT_MAX,
63544dea178SSandipan Das 				}
63644dea178SSandipan Das 			},
63744dea178SSandipan Das 			{
63844dea178SSandipan Das 				.descr = "RA = UINT_MAX, RB = UINT_MAX",
63944dea178SSandipan Das 				.instr = TEST_ADD_DOT(20, 21, 22),
64044dea178SSandipan Das 				.regs = {
64144dea178SSandipan Das 					.gpr[21] = UINT_MAX,
64244dea178SSandipan Das 					.gpr[22] = UINT_MAX,
64344dea178SSandipan Das 				}
64444dea178SSandipan Das 			},
64544dea178SSandipan Das 			{
64644dea178SSandipan Das 				.descr = "RA = UINT_MAX, RB = 0x1",
64744dea178SSandipan Das 				.instr = TEST_ADD_DOT(20, 21, 22),
64844dea178SSandipan Das 				.regs = {
64944dea178SSandipan Das 					.gpr[21] = UINT_MAX,
65044dea178SSandipan Das 					.gpr[22] = 0x1,
65144dea178SSandipan Das 				}
65244dea178SSandipan Das 			}
65344dea178SSandipan Das 		}
65478a8da06SSandipan Das 	},
65578a8da06SSandipan Das 	{
65678a8da06SSandipan Das 		.mnemonic = "addc",
65778a8da06SSandipan Das 		.subtests = {
65878a8da06SSandipan Das 			{
65978a8da06SSandipan Das 				.descr = "RA = LONG_MIN, RB = LONG_MIN",
66078a8da06SSandipan Das 				.instr = TEST_ADDC(20, 21, 22),
66178a8da06SSandipan Das 				.regs = {
66278a8da06SSandipan Das 					.gpr[21] = LONG_MIN,
66378a8da06SSandipan Das 					.gpr[22] = LONG_MIN,
66478a8da06SSandipan Das 				}
66578a8da06SSandipan Das 			},
66678a8da06SSandipan Das 			{
66778a8da06SSandipan Das 				.descr = "RA = LONG_MIN, RB = LONG_MAX",
66878a8da06SSandipan Das 				.instr = TEST_ADDC(20, 21, 22),
66978a8da06SSandipan Das 				.regs = {
67078a8da06SSandipan Das 					.gpr[21] = LONG_MIN,
67178a8da06SSandipan Das 					.gpr[22] = LONG_MAX,
67278a8da06SSandipan Das 				}
67378a8da06SSandipan Das 			},
67478a8da06SSandipan Das 			{
67578a8da06SSandipan Das 				.descr = "RA = LONG_MAX, RB = LONG_MAX",
67678a8da06SSandipan Das 				.instr = TEST_ADDC(20, 21, 22),
67778a8da06SSandipan Das 				.regs = {
67878a8da06SSandipan Das 					.gpr[21] = LONG_MAX,
67978a8da06SSandipan Das 					.gpr[22] = LONG_MAX,
68078a8da06SSandipan Das 				}
68178a8da06SSandipan Das 			},
68278a8da06SSandipan Das 			{
68378a8da06SSandipan Das 				.descr = "RA = ULONG_MAX, RB = ULONG_MAX",
68478a8da06SSandipan Das 				.instr = TEST_ADDC(20, 21, 22),
68578a8da06SSandipan Das 				.regs = {
68678a8da06SSandipan Das 					.gpr[21] = ULONG_MAX,
68778a8da06SSandipan Das 					.gpr[22] = ULONG_MAX,
68878a8da06SSandipan Das 				}
68978a8da06SSandipan Das 			},
69078a8da06SSandipan Das 			{
69178a8da06SSandipan Das 				.descr = "RA = ULONG_MAX, RB = 0x1",
69278a8da06SSandipan Das 				.instr = TEST_ADDC(20, 21, 22),
69378a8da06SSandipan Das 				.regs = {
69478a8da06SSandipan Das 					.gpr[21] = ULONG_MAX,
69578a8da06SSandipan Das 					.gpr[22] = 0x1,
69678a8da06SSandipan Das 				}
69778a8da06SSandipan Das 			},
69878a8da06SSandipan Das 			{
69978a8da06SSandipan Das 				.descr = "RA = INT_MIN, RB = INT_MIN",
70078a8da06SSandipan Das 				.instr = TEST_ADDC(20, 21, 22),
70178a8da06SSandipan Das 				.regs = {
70278a8da06SSandipan Das 					.gpr[21] = INT_MIN,
70378a8da06SSandipan Das 					.gpr[22] = INT_MIN,
70478a8da06SSandipan Das 				}
70578a8da06SSandipan Das 			},
70678a8da06SSandipan Das 			{
70778a8da06SSandipan Das 				.descr = "RA = INT_MIN, RB = INT_MAX",
70878a8da06SSandipan Das 				.instr = TEST_ADDC(20, 21, 22),
70978a8da06SSandipan Das 				.regs = {
71078a8da06SSandipan Das 					.gpr[21] = INT_MIN,
71178a8da06SSandipan Das 					.gpr[22] = INT_MAX,
71278a8da06SSandipan Das 				}
71378a8da06SSandipan Das 			},
71478a8da06SSandipan Das 			{
71578a8da06SSandipan Das 				.descr = "RA = INT_MAX, RB = INT_MAX",
71678a8da06SSandipan Das 				.instr = TEST_ADDC(20, 21, 22),
71778a8da06SSandipan Das 				.regs = {
71878a8da06SSandipan Das 					.gpr[21] = INT_MAX,
71978a8da06SSandipan Das 					.gpr[22] = INT_MAX,
72078a8da06SSandipan Das 				}
72178a8da06SSandipan Das 			},
72278a8da06SSandipan Das 			{
72378a8da06SSandipan Das 				.descr = "RA = UINT_MAX, RB = UINT_MAX",
72478a8da06SSandipan Das 				.instr = TEST_ADDC(20, 21, 22),
72578a8da06SSandipan Das 				.regs = {
72678a8da06SSandipan Das 					.gpr[21] = UINT_MAX,
72778a8da06SSandipan Das 					.gpr[22] = UINT_MAX,
72878a8da06SSandipan Das 				}
72978a8da06SSandipan Das 			},
73078a8da06SSandipan Das 			{
73178a8da06SSandipan Das 				.descr = "RA = UINT_MAX, RB = 0x1",
73278a8da06SSandipan Das 				.instr = TEST_ADDC(20, 21, 22),
73378a8da06SSandipan Das 				.regs = {
73478a8da06SSandipan Das 					.gpr[21] = UINT_MAX,
73578a8da06SSandipan Das 					.gpr[22] = 0x1,
73678a8da06SSandipan Das 				}
73778a8da06SSandipan Das 			},
73878a8da06SSandipan Das 			{
73978a8da06SSandipan Das 				.descr = "RA = LONG_MIN | INT_MIN, RB = LONG_MIN | INT_MIN",
74078a8da06SSandipan Das 				.instr = TEST_ADDC(20, 21, 22),
74178a8da06SSandipan Das 				.regs = {
74278a8da06SSandipan Das 					.gpr[21] = LONG_MIN | (uint)INT_MIN,
74378a8da06SSandipan Das 					.gpr[22] = LONG_MIN | (uint)INT_MIN,
74478a8da06SSandipan Das 				}
74578a8da06SSandipan Das 			}
74678a8da06SSandipan Das 		}
74778a8da06SSandipan Das 	},
74878a8da06SSandipan Das 	{
74978a8da06SSandipan Das 		.mnemonic = "addc.",
75078a8da06SSandipan Das 		.subtests = {
75178a8da06SSandipan Das 			{
75278a8da06SSandipan Das 				.descr = "RA = LONG_MIN, RB = LONG_MIN",
75378a8da06SSandipan Das 				.flags = IGNORE_CCR,
75478a8da06SSandipan Das 				.instr = TEST_ADDC_DOT(20, 21, 22),
75578a8da06SSandipan Das 				.regs = {
75678a8da06SSandipan Das 					.gpr[21] = LONG_MIN,
75778a8da06SSandipan Das 					.gpr[22] = LONG_MIN,
75878a8da06SSandipan Das 				}
75978a8da06SSandipan Das 			},
76078a8da06SSandipan Das 			{
76178a8da06SSandipan Das 				.descr = "RA = LONG_MIN, RB = LONG_MAX",
76278a8da06SSandipan Das 				.instr = TEST_ADDC_DOT(20, 21, 22),
76378a8da06SSandipan Das 				.regs = {
76478a8da06SSandipan Das 					.gpr[21] = LONG_MIN,
76578a8da06SSandipan Das 					.gpr[22] = LONG_MAX,
76678a8da06SSandipan Das 				}
76778a8da06SSandipan Das 			},
76878a8da06SSandipan Das 			{
76978a8da06SSandipan Das 				.descr = "RA = LONG_MAX, RB = LONG_MAX",
77078a8da06SSandipan Das 				.flags = IGNORE_CCR,
77178a8da06SSandipan Das 				.instr = TEST_ADDC_DOT(20, 21, 22),
77278a8da06SSandipan Das 				.regs = {
77378a8da06SSandipan Das 					.gpr[21] = LONG_MAX,
77478a8da06SSandipan Das 					.gpr[22] = LONG_MAX,
77578a8da06SSandipan Das 				}
77678a8da06SSandipan Das 			},
77778a8da06SSandipan Das 			{
77878a8da06SSandipan Das 				.descr = "RA = ULONG_MAX, RB = ULONG_MAX",
77978a8da06SSandipan Das 				.instr = TEST_ADDC_DOT(20, 21, 22),
78078a8da06SSandipan Das 				.regs = {
78178a8da06SSandipan Das 					.gpr[21] = ULONG_MAX,
78278a8da06SSandipan Das 					.gpr[22] = ULONG_MAX,
78378a8da06SSandipan Das 				}
78478a8da06SSandipan Das 			},
78578a8da06SSandipan Das 			{
78678a8da06SSandipan Das 				.descr = "RA = ULONG_MAX, RB = 0x1",
78778a8da06SSandipan Das 				.instr = TEST_ADDC_DOT(20, 21, 22),
78878a8da06SSandipan Das 				.regs = {
78978a8da06SSandipan Das 					.gpr[21] = ULONG_MAX,
79078a8da06SSandipan Das 					.gpr[22] = 0x1,
79178a8da06SSandipan Das 				}
79278a8da06SSandipan Das 			},
79378a8da06SSandipan Das 			{
79478a8da06SSandipan Das 				.descr = "RA = INT_MIN, RB = INT_MIN",
79578a8da06SSandipan Das 				.instr = TEST_ADDC_DOT(20, 21, 22),
79678a8da06SSandipan Das 				.regs = {
79778a8da06SSandipan Das 					.gpr[21] = INT_MIN,
79878a8da06SSandipan Das 					.gpr[22] = INT_MIN,
79978a8da06SSandipan Das 				}
80078a8da06SSandipan Das 			},
80178a8da06SSandipan Das 			{
80278a8da06SSandipan Das 				.descr = "RA = INT_MIN, RB = INT_MAX",
80378a8da06SSandipan Das 				.instr = TEST_ADDC_DOT(20, 21, 22),
80478a8da06SSandipan Das 				.regs = {
80578a8da06SSandipan Das 					.gpr[21] = INT_MIN,
80678a8da06SSandipan Das 					.gpr[22] = INT_MAX,
80778a8da06SSandipan Das 				}
80878a8da06SSandipan Das 			},
80978a8da06SSandipan Das 			{
81078a8da06SSandipan Das 				.descr = "RA = INT_MAX, RB = INT_MAX",
81178a8da06SSandipan Das 				.instr = TEST_ADDC_DOT(20, 21, 22),
81278a8da06SSandipan Das 				.regs = {
81378a8da06SSandipan Das 					.gpr[21] = INT_MAX,
81478a8da06SSandipan Das 					.gpr[22] = INT_MAX,
81578a8da06SSandipan Das 				}
81678a8da06SSandipan Das 			},
81778a8da06SSandipan Das 			{
81878a8da06SSandipan Das 				.descr = "RA = UINT_MAX, RB = UINT_MAX",
81978a8da06SSandipan Das 				.instr = TEST_ADDC_DOT(20, 21, 22),
82078a8da06SSandipan Das 				.regs = {
82178a8da06SSandipan Das 					.gpr[21] = UINT_MAX,
82278a8da06SSandipan Das 					.gpr[22] = UINT_MAX,
82378a8da06SSandipan Das 				}
82478a8da06SSandipan Das 			},
82578a8da06SSandipan Das 			{
82678a8da06SSandipan Das 				.descr = "RA = UINT_MAX, RB = 0x1",
82778a8da06SSandipan Das 				.instr = TEST_ADDC_DOT(20, 21, 22),
82878a8da06SSandipan Das 				.regs = {
82978a8da06SSandipan Das 					.gpr[21] = UINT_MAX,
83078a8da06SSandipan Das 					.gpr[22] = 0x1,
83178a8da06SSandipan Das 				}
83278a8da06SSandipan Das 			},
83378a8da06SSandipan Das 			{
83478a8da06SSandipan Das 				.descr = "RA = LONG_MIN | INT_MIN, RB = LONG_MIN | INT_MIN",
83578a8da06SSandipan Das 				.instr = TEST_ADDC_DOT(20, 21, 22),
83678a8da06SSandipan Das 				.regs = {
83778a8da06SSandipan Das 					.gpr[21] = LONG_MIN | (uint)INT_MIN,
83878a8da06SSandipan Das 					.gpr[22] = LONG_MIN | (uint)INT_MIN,
83978a8da06SSandipan Das 				}
84078a8da06SSandipan Das 			}
84178a8da06SSandipan Das 		}
84284022ac1SSandipan Das 	}
84384022ac1SSandipan Das };
84484022ac1SSandipan Das 
84584022ac1SSandipan Das static int __init emulate_compute_instr(struct pt_regs *regs,
846*94afd069SJordan Niethe 					struct ppc_inst instr)
84784022ac1SSandipan Das {
84884022ac1SSandipan Das 	struct instruction_op op;
84984022ac1SSandipan Das 
850777e26f0SJordan Niethe 	if (!regs || !ppc_inst_val(instr))
85184022ac1SSandipan Das 		return -EINVAL;
85284022ac1SSandipan Das 
85384022ac1SSandipan Das 	if (analyse_instr(&op, regs, instr) != 1 ||
85484022ac1SSandipan Das 	    GETTYPE(op.type) != COMPUTE) {
855777e26f0SJordan Niethe 		pr_info("emulation failed, instruction = 0x%08x\n", ppc_inst_val(instr));
85684022ac1SSandipan Das 		return -EFAULT;
85784022ac1SSandipan Das 	}
85884022ac1SSandipan Das 
85984022ac1SSandipan Das 	emulate_update_regs(regs, &op);
86084022ac1SSandipan Das 	return 0;
86184022ac1SSandipan Das }
86284022ac1SSandipan Das 
86384022ac1SSandipan Das static int __init execute_compute_instr(struct pt_regs *regs,
864*94afd069SJordan Niethe 					struct ppc_inst instr)
86584022ac1SSandipan Das {
86684022ac1SSandipan Das 	extern int exec_instr(struct pt_regs *regs);
86784022ac1SSandipan Das 	extern s32 patch__exec_instr;
86884022ac1SSandipan Das 
869777e26f0SJordan Niethe 	if (!regs || !ppc_inst_val(instr))
87084022ac1SSandipan Das 		return -EINVAL;
87184022ac1SSandipan Das 
87284022ac1SSandipan Das 	/* Patch the NOP with the actual instruction */
87384022ac1SSandipan Das 	patch_instruction_site(&patch__exec_instr, instr);
87484022ac1SSandipan Das 	if (exec_instr(regs)) {
875777e26f0SJordan Niethe 		pr_info("execution failed, instruction = 0x%08x\n", ppc_inst_val(instr));
87684022ac1SSandipan Das 		return -EFAULT;
87784022ac1SSandipan Das 	}
87884022ac1SSandipan Das 
87984022ac1SSandipan Das 	return 0;
88084022ac1SSandipan Das }
88184022ac1SSandipan Das 
88284022ac1SSandipan Das #define gpr_mismatch(gprn, exp, got)	\
88384022ac1SSandipan Das 	pr_info("GPR%u mismatch, exp = 0x%016lx, got = 0x%016lx\n",	\
88484022ac1SSandipan Das 		gprn, exp, got)
88584022ac1SSandipan Das 
88684022ac1SSandipan Das #define reg_mismatch(name, exp, got)	\
88784022ac1SSandipan Das 	pr_info("%s mismatch, exp = 0x%016lx, got = 0x%016lx\n",	\
88884022ac1SSandipan Das 		name, exp, got)
88984022ac1SSandipan Das 
89084022ac1SSandipan Das static void __init run_tests_compute(void)
89184022ac1SSandipan Das {
89284022ac1SSandipan Das 	unsigned long flags;
89384022ac1SSandipan Das 	struct compute_test *test;
89484022ac1SSandipan Das 	struct pt_regs *regs, exp, got;
895*94afd069SJordan Niethe 	unsigned int i, j, k;
896*94afd069SJordan Niethe 	struct ppc_inst instr;
89784022ac1SSandipan Das 	bool ignore_gpr, ignore_xer, ignore_ccr, passed;
89884022ac1SSandipan Das 
89984022ac1SSandipan Das 	for (i = 0; i < ARRAY_SIZE(compute_tests); i++) {
90084022ac1SSandipan Das 		test = &compute_tests[i];
90184022ac1SSandipan Das 
90284022ac1SSandipan Das 		for (j = 0; j < MAX_SUBTESTS && test->subtests[j].descr; j++) {
90384022ac1SSandipan Das 			instr = test->subtests[j].instr;
90484022ac1SSandipan Das 			flags = test->subtests[j].flags;
90584022ac1SSandipan Das 			regs = &test->subtests[j].regs;
90684022ac1SSandipan Das 			ignore_xer = flags & IGNORE_XER;
90784022ac1SSandipan Das 			ignore_ccr = flags & IGNORE_CCR;
90884022ac1SSandipan Das 			passed = true;
90984022ac1SSandipan Das 
91084022ac1SSandipan Das 			memcpy(&exp, regs, sizeof(struct pt_regs));
91184022ac1SSandipan Das 			memcpy(&got, regs, sizeof(struct pt_regs));
91284022ac1SSandipan Das 
91384022ac1SSandipan Das 			/*
91484022ac1SSandipan Das 			 * Set a compatible MSR value explicitly to ensure
91584022ac1SSandipan Das 			 * that XER and CR bits are updated appropriately
91684022ac1SSandipan Das 			 */
91784022ac1SSandipan Das 			exp.msr = MSR_KERNEL;
91884022ac1SSandipan Das 			got.msr = MSR_KERNEL;
91984022ac1SSandipan Das 
92084022ac1SSandipan Das 			if (emulate_compute_instr(&got, instr) ||
92184022ac1SSandipan Das 			    execute_compute_instr(&exp, instr)) {
92284022ac1SSandipan Das 				passed = false;
92384022ac1SSandipan Das 				goto print;
92484022ac1SSandipan Das 			}
92584022ac1SSandipan Das 
92684022ac1SSandipan Das 			/* Verify GPR values */
92784022ac1SSandipan Das 			for (k = 0; k < 32; k++) {
92884022ac1SSandipan Das 				ignore_gpr = flags & IGNORE_GPR(k);
92984022ac1SSandipan Das 				if (!ignore_gpr && exp.gpr[k] != got.gpr[k]) {
93084022ac1SSandipan Das 					passed = false;
93184022ac1SSandipan Das 					gpr_mismatch(k, exp.gpr[k], got.gpr[k]);
93284022ac1SSandipan Das 				}
93384022ac1SSandipan Das 			}
93484022ac1SSandipan Das 
93584022ac1SSandipan Das 			/* Verify LR value */
93684022ac1SSandipan Das 			if (exp.link != got.link) {
93784022ac1SSandipan Das 				passed = false;
93884022ac1SSandipan Das 				reg_mismatch("LR", exp.link, got.link);
93984022ac1SSandipan Das 			}
94084022ac1SSandipan Das 
94184022ac1SSandipan Das 			/* Verify XER value */
94284022ac1SSandipan Das 			if (!ignore_xer && exp.xer != got.xer) {
94384022ac1SSandipan Das 				passed = false;
94484022ac1SSandipan Das 				reg_mismatch("XER", exp.xer, got.xer);
94584022ac1SSandipan Das 			}
94684022ac1SSandipan Das 
94784022ac1SSandipan Das 			/* Verify CR value */
94884022ac1SSandipan Das 			if (!ignore_ccr && exp.ccr != got.ccr) {
94984022ac1SSandipan Das 				passed = false;
95084022ac1SSandipan Das 				reg_mismatch("CR", exp.ccr, got.ccr);
95184022ac1SSandipan Das 			}
95284022ac1SSandipan Das 
95384022ac1SSandipan Das print:
95484022ac1SSandipan Das 			show_result_with_descr(test->mnemonic,
95584022ac1SSandipan Das 					       test->subtests[j].descr,
95684022ac1SSandipan Das 					       passed ? "PASS" : "FAIL");
95784022ac1SSandipan Das 		}
95884022ac1SSandipan Das 	}
95984022ac1SSandipan Das }
96084022ac1SSandipan Das 
96184022ac1SSandipan Das static int __init test_emulate_step(void)
96284022ac1SSandipan Das {
96384022ac1SSandipan Das 	printk(KERN_INFO "Running instruction emulation self-tests ...\n");
96484022ac1SSandipan Das 	run_tests_load_store();
96584022ac1SSandipan Das 	run_tests_compute();
9664ceae137SRavi Bangoria 
9674ceae137SRavi Bangoria 	return 0;
9684ceae137SRavi Bangoria }
9694ceae137SRavi Bangoria late_initcall(test_emulate_step);
970