Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/xmon: Fix disassembly CPU feature checks

In the xmon disassembly code there are several CPU feature checks to
determine what dialects should be passed to the disassembler. The
dialect controls which instructions the disassembler will recognise.

Unfortunately the checks are incorrect, because instead of passing a
single CPU feature they are passing a mask of feature bits.

For example the code:

if (cpu_has_feature(CPU_FTRS_POWER5))
dialect |= PPC_OPCODE_POWER5;

Is trying to check if the system is running on a Power5 CPU. But
CPU_FTRS_POWER5 is a mask of *all* the feature bits that are enabled on
a Power5.

In practice the test will always return true for any 64-bit CPU, because
at least one bit in the mask will be present in the CPU_FTRS_ALWAYS
mask.

Similarly for all the other checks against CPU_FTRS_xx masks.

Rather than trying to match the disassembly behaviour exactly to the
current CPU, just differentiate between 32-bit and 64-bit, and Altivec,
VSX and HTM.

That will cause some instructions to be shown in disassembly even
on a CPU that doesn't support them, but that's OK, objdump -d output
has the same behaviour, and if anything it's less confusing than some
instructions not being disassembled.

Fixes: 897f112bb42e ("[POWERPC] Import updated version of ppc disassembly code for xmon")
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240509121248.270878-2-mpe@ellerman.id.au

+11 -22
+11 -22
arch/powerpc/xmon/ppc-dis.c
··· 122 122 bool insn_is_short; 123 123 ppc_cpu_t dialect; 124 124 125 - dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON 126 - | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC; 125 + dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON; 127 126 128 - if (cpu_has_feature(CPU_FTRS_POWER5)) 129 - dialect |= PPC_OPCODE_POWER5; 127 + if (IS_ENABLED(CONFIG_PPC64)) 128 + dialect |= PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | 129 + PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | 130 + PPC_OPCODE_POWER9; 130 131 131 - if (cpu_has_feature(CPU_FTRS_CELL)) 132 - dialect |= (PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC); 132 + if (cpu_has_feature(CPU_FTR_TM)) 133 + dialect |= PPC_OPCODE_HTM; 133 134 134 - if (cpu_has_feature(CPU_FTRS_POWER6)) 135 - dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC); 135 + if (cpu_has_feature(CPU_FTR_ALTIVEC)) 136 + dialect |= PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2; 136 137 137 - if (cpu_has_feature(CPU_FTRS_POWER7)) 138 - dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 139 - | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX); 140 - 141 - if (cpu_has_feature(CPU_FTRS_POWER8)) 142 - dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 143 - | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM 144 - | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX); 145 - 146 - if (cpu_has_feature(CPU_FTRS_POWER9)) 147 - dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 148 - | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 | PPC_OPCODE_HTM 149 - | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 150 - | PPC_OPCODE_VSX | PPC_OPCODE_VSX3); 138 + if (cpu_has_feature(CPU_FTR_VSX)) 139 + dialect |= PPC_OPCODE_VSX | PPC_OPCODE_VSX3; 151 140 152 141 /* Get the major opcode of the insn. */ 153 142 opcode = NULL;