Commit 8813ff49 authored by Ananth N Mavinakayanahalli's avatar Ananth N Mavinakayanahalli Committed by Michael Ellerman
Browse files

powerpc/sstep: Check instruction validity against ISA version before emulation



We currently unconditionally try to emulate newer instructions on older
Power versions that could cause issues. Gate it.

Fixes: 350779a2 ("powerpc: Handle most loads and stores in instruction emulation code")
Signed-off-by: default avatarAnanth N Mavinakayanahalli <ananth@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/161157995977.64773.13794501093457185080.stgit@thinktux.local
parent 4eeef098
Loading
Loading
Loading
Loading
+62 −16
Original line number Diff line number Diff line
@@ -1304,9 +1304,11 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
		if ((word & 0xfe2) == 2)
			op->type = SYSCALL;
		else if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) &&
				(word & 0xfe3) == 1)
				(word & 0xfe3) == 1) {	/* scv */
			op->type = SYSCALL_VECTORED_0;
		else
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
		} else
			op->type = UNKNOWN;
		return 0;
#endif
@@ -1410,7 +1412,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
#ifdef __powerpc64__
	case 1:
		if (!cpu_has_feature(CPU_FTR_ARCH_31))
			return -1;
			goto unknown_opcode;

		prefix_r = GET_PREFIX_R(word);
		ra = GET_PREFIX_RA(suffix);
@@ -1444,7 +1446,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
#ifdef __powerpc64__
	case 4:
		if (!cpu_has_feature(CPU_FTR_ARCH_300))
			return -1;
			goto unknown_opcode;

		switch (word & 0x3f) {
		case 48:	/* maddhd */
@@ -1530,6 +1532,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
	case 19:
		if (((word >> 1) & 0x1f) == 2) {
			/* addpcis */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			imm = (short) (word & 0xffc1);	/* d0 + d2 fields */
			imm |= (word >> 15) & 0x3e;	/* d1 field */
			op->val = regs->nip + (imm << 16) + 4;
@@ -1842,7 +1846,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
#ifdef __powerpc64__
		case 265:	/* modud */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				return -1;
				goto unknown_opcode;
			op->val = regs->gpr[ra] % regs->gpr[rb];
			goto compute_done;
#endif
@@ -1852,7 +1856,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,

		case 267:	/* moduw */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				return -1;
				goto unknown_opcode;
			op->val = (unsigned int) regs->gpr[ra] %
				(unsigned int) regs->gpr[rb];
			goto compute_done;
@@ -1889,7 +1893,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
#endif
		case 755:	/* darn */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				return -1;
				goto unknown_opcode;
			switch (ra & 0x3) {
			case 0:
				/* 32-bit conditioned */
@@ -1911,14 +1915,14 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
#ifdef __powerpc64__
		case 777:	/* modsd */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				return -1;
				goto unknown_opcode;
			op->val = (long int) regs->gpr[ra] %
				(long int) regs->gpr[rb];
			goto compute_done;
#endif
		case 779:	/* modsw */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				return -1;
				goto unknown_opcode;
			op->val = (int) regs->gpr[ra] %
				(int) regs->gpr[rb];
			goto compute_done;
@@ -1995,14 +1999,14 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
#endif
		case 538:	/* cnttzw */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				return -1;
				goto unknown_opcode;
			val = (unsigned int) regs->gpr[rd];
			op->val = (val ? __builtin_ctz(val) : 32);
			goto logical_done;
#ifdef __powerpc64__
		case 570:	/* cnttzd */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				return -1;
				goto unknown_opcode;
			val = regs->gpr[rd];
			op->val = (val ? __builtin_ctzl(val) : 64);
			goto logical_done;
@@ -2112,7 +2116,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
		case 890:	/* extswsli with sh_5 = 0 */
		case 891:	/* extswsli with sh_5 = 1 */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				return -1;
				goto unknown_opcode;
			op->type = COMPUTE + SETREG;
			sh = rb | ((word & 2) << 4);
			val = (signed int) regs->gpr[rd];
@@ -2439,6 +2443,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			break;

		case 268:	/* lxvx */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->type = MKOP(LOAD_VSX, 0, 16);
			op->element_size = 16;
@@ -2448,6 +2454,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
		case 269:	/* lxvl */
		case 301: {	/* lxvll */
			int nb;
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->ea = ra ? regs->gpr[ra] : 0;
			nb = regs->gpr[rb] & 0xff;
@@ -2468,13 +2476,15 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,

		case 333:       /* lxvpx */
			if (!cpu_has_feature(CPU_FTR_ARCH_31))
				return -1;
				goto unknown_opcode;
			op->reg = VSX_REGISTER_XTP(rd);
			op->type = MKOP(LOAD_VSX, 0, 32);
			op->element_size = 32;
			break;

		case 364:	/* lxvwsx */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->type = MKOP(LOAD_VSX, 0, 4);
			op->element_size = 4;
@@ -2482,6 +2492,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			break;

		case 396:	/* stxvx */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->type = MKOP(STORE_VSX, 0, 16);
			op->element_size = 16;
@@ -2491,6 +2503,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
		case 397:	/* stxvl */
		case 429: {	/* stxvll */
			int nb;
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->ea = ra ? regs->gpr[ra] : 0;
			nb = regs->gpr[rb] & 0xff;
@@ -2504,7 +2518,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
		}
		case 461:       /* stxvpx */
			if (!cpu_has_feature(CPU_FTR_ARCH_31))
				return -1;
				goto unknown_opcode;
			op->reg = VSX_REGISTER_XTP(rd);
			op->type = MKOP(STORE_VSX, 0, 32);
			op->element_size = 32;
@@ -2542,6 +2556,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			break;

		case 781:	/* lxsibzx */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->type = MKOP(LOAD_VSX, 0, 1);
			op->element_size = 8;
@@ -2549,6 +2565,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			break;

		case 812:	/* lxvh8x */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->type = MKOP(LOAD_VSX, 0, 16);
			op->element_size = 2;
@@ -2556,6 +2574,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			break;

		case 813:	/* lxsihzx */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->type = MKOP(LOAD_VSX, 0, 2);
			op->element_size = 8;
@@ -2569,6 +2589,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			break;

		case 876:	/* lxvb16x */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->type = MKOP(LOAD_VSX, 0, 16);
			op->element_size = 1;
@@ -2582,6 +2604,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			break;

		case 909:	/* stxsibx */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->type = MKOP(STORE_VSX, 0, 1);
			op->element_size = 8;
@@ -2589,6 +2613,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			break;

		case 940:	/* stxvh8x */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->type = MKOP(STORE_VSX, 0, 16);
			op->element_size = 2;
@@ -2596,6 +2622,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			break;

		case 941:	/* stxsihx */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->type = MKOP(STORE_VSX, 0, 2);
			op->element_size = 8;
@@ -2609,6 +2637,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			break;

		case 1004:	/* stxvb16x */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd | ((word & 1) << 5);
			op->type = MKOP(STORE_VSX, 0, 16);
			op->element_size = 1;
@@ -2717,12 +2747,16 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			op->type = MKOP(LOAD_FP, 0, 16);
			break;
		case 2:		/* lxsd */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd + 32;
			op->type = MKOP(LOAD_VSX, 0, 8);
			op->element_size = 8;
			op->vsx_flags = VSX_CHECK_VEC;
			break;
		case 3:		/* lxssp */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->reg = rd + 32;
			op->type = MKOP(LOAD_VSX, 0, 4);
			op->element_size = 8;
@@ -2752,7 +2786,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
#ifdef CONFIG_VSX
	case 6:
		if (!cpu_has_feature(CPU_FTR_ARCH_31))
			return -1;
			goto unknown_opcode;
		op->ea = dqform_ea(word, regs);
		op->reg = VSX_REGISTER_XTP(rd);
		op->element_size = 32;
@@ -2775,6 +2809,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			break;

		case 1:		/* lxv */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->ea = dqform_ea(word, regs);
			if (word & 8)
				op->reg = rd + 32;
@@ -2785,6 +2821,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,

		case 2:		/* stxsd with LSB of DS field = 0 */
		case 6:		/* stxsd with LSB of DS field = 1 */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->ea = dsform_ea(word, regs);
			op->reg = rd + 32;
			op->type = MKOP(STORE_VSX, 0, 8);
@@ -2794,6 +2832,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,

		case 3:		/* stxssp with LSB of DS field = 0 */
		case 7:		/* stxssp with LSB of DS field = 1 */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->ea = dsform_ea(word, regs);
			op->reg = rd + 32;
			op->type = MKOP(STORE_VSX, 0, 4);
@@ -2802,6 +2842,8 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			break;

		case 5:		/* stxv */
			if (!cpu_has_feature(CPU_FTR_ARCH_300))
				goto unknown_opcode;
			op->ea = dqform_ea(word, regs);
			if (word & 8)
				op->reg = rd + 32;
@@ -2831,7 +2873,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
		break;
	case 1: /* Prefixed instructions */
		if (!cpu_has_feature(CPU_FTR_ARCH_31))
			return -1;
			goto unknown_opcode;

		prefix_r = GET_PREFIX_R(word);
		ra = GET_PREFIX_RA(suffix);
@@ -2980,6 +3022,10 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,

	return 0;

 unknown_opcode:
	op->type = UNKNOWN;
	return 0;

 logical_done:
	if (word & 1)
		set_cr0(regs, op);