cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ppc-dis.c (8204B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* ppc-dis.c -- Disassemble PowerPC instructions
      3   Copyright (C) 1994-2016 Free Software Foundation, Inc.
      4   Written by Ian Lance Taylor, Cygnus Support
      5
      6This file is part of GDB, GAS, and the GNU binutils.
      7
      8 */
      9
     10#include <asm/cputable.h>
     11#include <asm/cpu_has_feature.h>
     12#include "nonstdio.h"
     13#include "ansidecl.h"
     14#include "ppc.h"
     15#include "dis-asm.h"
     16
     17/* This file provides several disassembler functions, all of which use
     18   the disassembler interface defined in dis-asm.h.  Several functions
     19   are provided because this file handles disassembly for the PowerPC
     20   in both big and little endian mode and also for the POWER (RS/6000)
     21   chip.  */
     22
     23/* Extract the operand value from the PowerPC or POWER instruction.  */
     24
     25static long
     26operand_value_powerpc (const struct powerpc_operand *operand,
     27		       unsigned long insn, ppc_cpu_t dialect)
     28{
     29  long value;
     30  int invalid;
     31  /* Extract the value from the instruction.  */
     32  if (operand->extract)
     33    value = (*operand->extract) (insn, dialect, &invalid);
     34  else
     35    {
     36      if (operand->shift >= 0)
     37	value = (insn >> operand->shift) & operand->bitm;
     38      else
     39	value = (insn << -operand->shift) & operand->bitm;
     40      if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
     41	{
     42	  /* BITM is always some number of zeros followed by some
     43	     number of ones, followed by some number of zeros.  */
     44	  unsigned long top = operand->bitm;
     45	  /* top & -top gives the rightmost 1 bit, so this
     46	     fills in any trailing zeros.  */
     47	  top |= (top & -top) - 1;
     48	  top &= ~(top >> 1);
     49	  value = (value ^ top) - top;
     50	}
     51    }
     52
     53  return value;
     54}
     55
     56/* Determine whether the optional operand(s) should be printed.  */
     57
     58static int
     59skip_optional_operands (const unsigned char *opindex,
     60			unsigned long insn, ppc_cpu_t dialect)
     61{
     62  const struct powerpc_operand *operand;
     63
     64  for (; *opindex != 0; opindex++)
     65    {
     66      operand = &powerpc_operands[*opindex];
     67      if ((operand->flags & PPC_OPERAND_NEXT) != 0
     68	  || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
     69	      && operand_value_powerpc (operand, insn, dialect) !=
     70		 ppc_optional_operand_value (operand)))
     71	return 0;
     72    }
     73
     74  return 1;
     75}
     76
     77/* Find a match for INSN in the opcode table, given machine DIALECT.
     78   A DIALECT of -1 is special, matching all machine opcode variations.  */
     79
     80static const struct powerpc_opcode *
     81lookup_powerpc (unsigned long insn, ppc_cpu_t dialect)
     82{
     83  const struct powerpc_opcode *opcode;
     84  const struct powerpc_opcode *opcode_end;
     85
     86  opcode_end = powerpc_opcodes + powerpc_num_opcodes;
     87  /* Find the first match in the opcode table for this major opcode.  */
     88  for (opcode = powerpc_opcodes; opcode < opcode_end; ++opcode)
     89    {
     90      const unsigned char *opindex;
     91      const struct powerpc_operand *operand;
     92      int invalid;
     93
     94      if ((insn & opcode->mask) != opcode->opcode
     95	  || (dialect != (ppc_cpu_t) -1
     96	      && ((opcode->flags & dialect) == 0
     97		  || (opcode->deprecated & dialect) != 0)))
     98	continue;
     99
    100      /* Check validity of operands.  */
    101      invalid = 0;
    102      for (opindex = opcode->operands; *opindex != 0; opindex++)
    103	{
    104	  operand = powerpc_operands + *opindex;
    105	  if (operand->extract)
    106	    (*operand->extract) (insn, dialect, &invalid);
    107	}
    108      if (invalid)
    109	continue;
    110
    111      return opcode;
    112    }
    113
    114  return NULL;
    115}
    116
    117/* Print a PowerPC or POWER instruction.  */
    118
    119int print_insn_powerpc (unsigned long insn, unsigned long memaddr)
    120{
    121  const struct powerpc_opcode *opcode;
    122  bool insn_is_short;
    123  ppc_cpu_t dialect;
    124
    125  dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON
    126            | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC;
    127
    128  if (cpu_has_feature(CPU_FTRS_POWER5))
    129    dialect |= PPC_OPCODE_POWER5;
    130
    131  if (cpu_has_feature(CPU_FTRS_CELL))
    132    dialect |= (PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC);
    133
    134  if (cpu_has_feature(CPU_FTRS_POWER6))
    135    dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC);
    136
    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);
    151
    152  /* Get the major opcode of the insn.  */
    153  opcode = NULL;
    154  insn_is_short = false;
    155
    156  if (opcode == NULL)
    157    opcode = lookup_powerpc (insn, dialect);
    158  if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
    159    opcode = lookup_powerpc (insn, (ppc_cpu_t) -1);
    160
    161  if (opcode != NULL)
    162    {
    163      const unsigned char *opindex;
    164      const struct powerpc_operand *operand;
    165      int need_comma;
    166      int need_paren;
    167      int skip_optional;
    168
    169      if (opcode->operands[0] != 0)
    170	printf("%-7s ", opcode->name);
    171      else
    172	printf("%s", opcode->name);
    173
    174      if (insn_is_short)
    175        /* The operands will be fetched out of the 16-bit instruction.  */
    176        insn >>= 16;
    177
    178      /* Now extract and print the operands.  */
    179      need_comma = 0;
    180      need_paren = 0;
    181      skip_optional = -1;
    182      for (opindex = opcode->operands; *opindex != 0; opindex++)
    183	{
    184	  long value;
    185
    186	  operand = powerpc_operands + *opindex;
    187
    188	  /* Operands that are marked FAKE are simply ignored.  We
    189	     already made sure that the extract function considered
    190	     the instruction to be valid.  */
    191	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
    192	    continue;
    193
    194	  /* If all of the optional operands have the value zero,
    195	     then don't print any of them.  */
    196	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
    197	    {
    198	      if (skip_optional < 0)
    199		skip_optional = skip_optional_operands (opindex, insn,
    200							dialect);
    201	      if (skip_optional)
    202		continue;
    203	    }
    204
    205	  value = operand_value_powerpc (operand, insn, dialect);
    206
    207	  if (need_comma)
    208	    {
    209	      printf(",");
    210	      need_comma = 0;
    211	    }
    212
    213	  /* Print the operand as directed by the flags.  */
    214	  if ((operand->flags & PPC_OPERAND_GPR) != 0
    215	      || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
    216	    printf("r%ld", value);
    217	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
    218	    printf("f%ld", value);
    219	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
    220	    printf("v%ld", value);
    221	  else if ((operand->flags & PPC_OPERAND_VSR) != 0)
    222	    printf("vs%ld", value);
    223	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
    224	    print_address(memaddr + value);
    225	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
    226	    print_address(value & 0xffffffff);
    227	  else if ((operand->flags & PPC_OPERAND_FSL) != 0)
    228	    printf("fsl%ld", value);
    229	  else if ((operand->flags & PPC_OPERAND_FCR) != 0)
    230	    printf("fcr%ld", value);
    231	  else if ((operand->flags & PPC_OPERAND_UDI) != 0)
    232	    printf("%ld", value);
    233	  else if ((operand->flags & PPC_OPERAND_CR_REG) != 0
    234		   && (((dialect & PPC_OPCODE_PPC) != 0)
    235		       || ((dialect & PPC_OPCODE_VLE) != 0)))
    236	    printf("cr%ld", value);
    237	  else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0)
    238		   && (((dialect & PPC_OPCODE_PPC) != 0)
    239		       || ((dialect & PPC_OPCODE_VLE) != 0)))
    240	    {
    241	      static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
    242	      int cr;
    243	      int cc;
    244
    245	      cr = value >> 2;
    246	      if (cr != 0)
    247		printf("4*cr%d+", cr);
    248	      cc = value & 3;
    249	      printf("%s", cbnames[cc]);
    250	    }
    251	  else
    252	    printf("%d", (int) value);
    253
    254	  if (need_paren)
    255	    {
    256	      printf(")");
    257	      need_paren = 0;
    258	    }
    259
    260	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
    261	    need_comma = 1;
    262	  else
    263	    {
    264	      printf("(");
    265	      need_paren = 1;
    266	    }
    267	}
    268
    269      /* We have found and printed an instruction.
    270         If it was a short VLE instruction we have more to do.  */
    271      if (insn_is_short)
    272        {
    273          memaddr += 2;
    274          return 2;
    275        }
    276      else
    277        /* Otherwise, return.  */
    278        return 4;
    279    }
    280
    281  /* We could not find a match.  */
    282  printf(".long 0x%lx", insn);
    283
    284  return 4;
    285}