Skip to content

Commit

Permalink
powerpc/sstep: Check instruction validity against ISA version before …
Browse files Browse the repository at this point in the history
…emulation

commit 8813ff4 upstream.

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

Fixes: 350779a ("powerpc: Handle most loads and stores in instruction emulation code")
Signed-off-by: Ananth N Mavinakayanahalli <ananth@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/161157995977.64773.13794501093457185080.stgit@thinktux.local
[Dropped a few missing hunks for the backport to v5.10]
Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Ananth N Mavinakayanahalli authored and gregkh committed Mar 7, 2021
1 parent 04b049a commit 20d323c
Showing 1 changed file with 59 additions and 13 deletions.
72 changes: 59 additions & 13 deletions arch/powerpc/lib/sstep.c
Expand Up @@ -1241,9 +1241,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
Expand Down Expand Up @@ -1347,7 +1349,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);
Expand Down Expand Up @@ -1381,7 +1383,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 */
Expand Down Expand Up @@ -1467,6 +1469,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;
Expand Down Expand Up @@ -1779,7 +1783,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
Expand All @@ -1789,7 +1793,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;
Expand Down Expand Up @@ -1826,7 +1830,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 */
Expand All @@ -1848,14 +1852,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;
Expand Down Expand Up @@ -1932,14 +1936,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;
Expand Down Expand Up @@ -2049,7 +2053,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];
Expand Down Expand Up @@ -2376,6 +2380,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;
Expand All @@ -2385,6 +2391,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;
Expand All @@ -2404,13 +2412,17 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
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;
op->vsx_flags = VSX_SPLAT | VSX_CHECK_VEC;
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;
Expand All @@ -2420,6 +2432,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;
Expand Down Expand Up @@ -2464,20 +2478,26 @@ 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;
op->vsx_flags = VSX_CHECK_VEC;
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;
op->vsx_flags = VSX_CHECK_VEC;
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;
Expand All @@ -2491,6 +2511,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;
Expand All @@ -2504,20 +2526,26 @@ 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;
op->vsx_flags = VSX_CHECK_VEC;
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;
op->vsx_flags = VSX_CHECK_VEC;
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;
Expand All @@ -2531,6 +2559,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;
Expand Down Expand Up @@ -2639,12 +2669,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;
Expand Down Expand Up @@ -2681,6 +2715,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;
Expand All @@ -2691,6 +2727,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);
Expand All @@ -2700,6 +2738,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);
Expand All @@ -2708,6 +2748,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;
Expand Down Expand Up @@ -2737,7 +2779,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);
Expand Down Expand Up @@ -2872,6 +2914,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);
Expand Down

0 comments on commit 20d323c

Please sign in to comment.