github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/ifuzz/powerpc/powerpc.go (about)

     1  // Copyright 2020 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  // Package ifuzz allows to generate and mutate PPC64 PowerISA 3.0B machine code.
     5  
     6  // The ISA for POWER9 (the latest available at the moment) is at:
     7  // https://openpowerfoundation.org/?resource_lib=power-isa-version-3-0
     8  //
     9  // A script on top of pdftotext was used to produce insns.go:
    10  // ./powerisa30_to_syz /home/aik/Documents/ppc/power9/PowerISA_public.v3.0B.pdf > 1.go
    11  // .
    12  
    13  package powerpc
    14  
    15  import (
    16  	"encoding/binary"
    17  	"errors"
    18  	"fmt"
    19  	"math/rand"
    20  
    21  	"github.com/google/syzkaller/pkg/ifuzz/iset"
    22  )
    23  
    24  type InsnBits struct {
    25  	Start  uint // Big endian bit order.
    26  	Length uint
    27  }
    28  
    29  type InsnField struct {
    30  	Name string
    31  	Bits []InsnBits
    32  }
    33  
    34  type Insn struct {
    35  	Name   string
    36  	Priv   bool
    37  	Pseudo bool
    38  	Fields []InsnField // for ra/rb/rt/si/...
    39  	Opcode uint32
    40  	Mask   uint32
    41  
    42  	FieldsSuffix []InsnField
    43  	OpcodeSuffix uint32
    44  	MaskSuffix   uint32
    45  
    46  	insnMap   *insnSetMap
    47  	generator func(cfg *iset.Config, r *rand.Rand) []byte
    48  }
    49  
    50  type insnSetMap map[string]*Insn
    51  
    52  type InsnSet struct {
    53  	Insns     []*Insn
    54  	modeInsns iset.ModeInsns
    55  	insnMap   insnSetMap
    56  }
    57  
    58  const (
    59  	prefixShift  = 32 - 6
    60  	prefixMask   = uint32(0x3f) << prefixShift
    61  	prefixOpcode = uint32(1) << prefixShift
    62  )
    63  
    64  func (insn Insn) isPrefixed() bool {
    65  	return insn.Opcode&prefixMask == prefixOpcode
    66  }
    67  
    68  func (insnset *InsnSet) GetInsns(mode iset.Mode, typ iset.Type) []iset.Insn {
    69  	return insnset.modeInsns[mode][typ]
    70  }
    71  
    72  func (insnset *InsnSet) Decode(mode iset.Mode, text []byte) (int, error) {
    73  	if len(text) < 4 {
    74  		return 0, errors.New("must be at least 4 bytes")
    75  	}
    76  	insn32 := binary.LittleEndian.Uint32(text)
    77  	if insn32&prefixMask == prefixOpcode {
    78  		insn2 := uint32(0)
    79  		for _, ins := range insnset.Insns {
    80  			if !ins.isPrefixed() || ins.Mask&insn32 != ins.Opcode {
    81  				continue
    82  			}
    83  			if len(text) < 8 {
    84  				return 0, errors.New("prefixed instruction must be at least 8 bytes")
    85  			}
    86  			insn2 = binary.LittleEndian.Uint32(text[4:])
    87  			for _, ins := range insnset.Insns {
    88  				if !ins.isPrefixed() {
    89  					continue
    90  				}
    91  				if ins.MaskSuffix&insn2 == ins.OpcodeSuffix {
    92  					return 8, nil
    93  				}
    94  			}
    95  			break
    96  		}
    97  		return 0, fmt.Errorf("unrecognised prefixed instruction %08x %08x", insn32, insn2)
    98  	}
    99  	for _, ins := range insnset.Insns {
   100  		if ins.Mask&insn32 == ins.Opcode {
   101  			return 4, nil
   102  		}
   103  	}
   104  	return 0, fmt.Errorf("unrecognised instruction %08x", insn32)
   105  }
   106  
   107  func (insnset *InsnSet) DecodeExt(mode iset.Mode, text []byte) (int, error) {
   108  	return 0, fmt.Errorf("no external decoder")
   109  }
   110  
   111  func encodeBits(n uint, ff []InsnBits) uint32 {
   112  	ret := uint32(0)
   113  	for _, f := range ff {
   114  		mask := uint(1<<f.Length) - 1
   115  		field := uint32((n & mask) << (31 - (f.Start + f.Length - 1)))
   116  		ret = ret | field
   117  		n = n >> f.Length
   118  	}
   119  	return ret
   120  }
   121  
   122  func (insn Insn) Encode(cfg *iset.Config, r *rand.Rand) []byte {
   123  	if insn.Pseudo {
   124  		return insn.generator(cfg, r)
   125  	}
   126  
   127  	ret := make([]byte, 0)
   128  	ret = append(ret, insn.encodeOpcode(cfg, r, insn.Opcode, insn.Mask, insn.Fields)...)
   129  	if insn.isPrefixed() {
   130  		ret = append(ret, insn.encodeOpcode(cfg, r, insn.OpcodeSuffix, insn.MaskSuffix, insn.FieldsSuffix)...)
   131  	}
   132  	return ret
   133  }
   134  
   135  func (insn Insn) encodeOpcode(cfg *iset.Config, r *rand.Rand, opcode, mask uint32, f []InsnField) []byte {
   136  	ret := make([]byte, 0)
   137  	insn32 := opcode
   138  	if len(cfg.MemRegions) != 0 {
   139  		// The PowerISA pdf parser could have missed some fields,
   140  		// randomize them there.
   141  		insn32 |= r.Uint32() & ^mask
   142  	}
   143  	for _, f := range f {
   144  		field := uint(r.Intn(1 << 16))
   145  		if f.Name == "Ap" || f.Name == "FRAp" || f.Name == "FRBp" || f.Name == "FRTp" || f.Name == "FRSp" {
   146  			// These are pairs and have to be even numbers.
   147  			field &^= 1
   148  		}
   149  		insn32 |= encodeBits(field, f.Bits)
   150  		if len(cfg.MemRegions) != 0 && (f.Name == "RA" || f.Name == "RB" || f.Name == "RS") {
   151  			val := iset.GenerateInt(cfg, r, 8)
   152  			ret = append(ret, insn.insnMap.ld64(field, val)...)
   153  		}
   154  	}
   155  
   156  	return append(ret, uint32toBytes(insn32)...)
   157  }
   158  
   159  func Register(insns []*Insn) {
   160  	if len(insns) == 0 {
   161  		panic("no instructions")
   162  	}
   163  	insnset := &InsnSet{
   164  		Insns:   insns,
   165  		insnMap: make(map[string]*Insn),
   166  	}
   167  	for _, insn := range insnset.Insns {
   168  		insnset.insnMap[insn.Name] = insn
   169  		insn.insnMap = &insnset.insnMap
   170  	}
   171  	insnset.initPseudo()
   172  	for _, insn := range insnset.Insns {
   173  		insnset.modeInsns.Add(insn)
   174  	}
   175  	iset.Arches[iset.ArchPowerPC] = insnset
   176  }
   177  
   178  func (insn *Insn) Info() (string, iset.Mode, bool, bool) {
   179  	return insn.Name, insn.mode(), insn.Pseudo, insn.Priv
   180  }
   181  
   182  func (insn Insn) mode() iset.Mode {
   183  	return (1 << iset.ModeLong64) | (1 << iset.ModeProt32)
   184  }
   185  
   186  func uint32toBytes(v uint32) []byte {
   187  	ret := make([]byte, 4)
   188  	binary.LittleEndian.PutUint32(ret, v)
   189  
   190  	return ret
   191  }
   192  
   193  func (insn *Insn) enc(v map[string]uint) []byte {
   194  	ret := make([]byte, 0)
   195  	ret = append(ret, insn.encOpcode(v, insn.Opcode, insn.Fields)...)
   196  	if insn.isPrefixed() {
   197  		ret = append(ret, insn.encOpcode(v, insn.OpcodeSuffix, insn.FieldsSuffix)...)
   198  	}
   199  	return ret
   200  }
   201  
   202  func (insn *Insn) encOpcode(v map[string]uint, opcode uint32, f []InsnField) []byte {
   203  	insn32 := opcode
   204  	for _, f := range insn.Fields {
   205  		if val, ok := v[f.Name]; ok {
   206  			insn32 |= encodeBits(val, f.Bits)
   207  		}
   208  	}
   209  	return uint32toBytes(insn32)
   210  }
   211  
   212  func (imap insnSetMap) ld64(reg uint, v uint64) []byte {
   213  	ret := make([]byte, 0)
   214  
   215  	// This is a widely used macro to load immediate on ppc64
   216  	// #define LOAD64(rn,name)
   217  	//	addis   rn,0,name##@highest \ lis     rn,name##@highest
   218  	//	ori     rn,rn,name##@higher
   219  	//	rldicr  rn,rn,32,31
   220  	//	oris    rn,rn,name##@h
   221  	//	ori     rn,rn,name##@l
   222  	ret = append(ret, imap["addis"].enc(map[string]uint{
   223  		"RT": reg,
   224  		"RA": 0, // In "addis", '0' means 0, not GPR0 .
   225  		"SI": uint((v >> 48) & 0xffff)})...)
   226  	ret = append(ret, imap["ori"].enc(map[string]uint{
   227  		"RA": reg,
   228  		"RS": reg,
   229  		"UI": uint((v >> 32) & 0xffff)})...)
   230  	ret = append(ret, imap["rldicr"].enc(map[string]uint{
   231  		"RA": reg,
   232  		"RS": reg,
   233  		"SH": 32,
   234  		"ME": 31})...)
   235  	ret = append(ret, imap["oris"].enc(map[string]uint{
   236  		"RA": reg,
   237  		"RS": reg,
   238  		"UI": uint((v >> 16) & 0xffff)})...)
   239  	ret = append(ret, imap["ori"].enc(map[string]uint{
   240  		"RA": reg,
   241  		"RS": reg,
   242  		"UI": uint(v & 0xffff)})...)
   243  
   244  	return ret
   245  }
   246  
   247  func (imap insnSetMap) ld32(reg uint, v uint32) []byte {
   248  	ret := make([]byte, 0)
   249  
   250  	ret = append(ret, imap["addis"].enc(map[string]uint{
   251  		"RT": reg,
   252  		"RA": 0, // In "addis", '0' means 0, not GPR0
   253  		"SI": uint((v >> 16) & 0xffff)})...)
   254  	ret = append(ret, imap["ori"].enc(map[string]uint{
   255  		"RA": reg,
   256  		"RS": reg,
   257  		"UI": uint(v & 0xffff)})...)
   258  
   259  	return ret
   260  }
   261  
   262  func (imap insnSetMap) ldgpr32(regaddr, regval uint, addr uint64, v uint32) []byte {
   263  	ret := make([]byte, 0)
   264  
   265  	ret = append(ret, imap.ld64(regaddr, addr)...)
   266  	ret = append(ret, imap.ld32(regval, v)...)
   267  	ret = append(ret, imap["stw"].enc(map[string]uint{
   268  		"RA": regaddr,
   269  		"RS": regval})...)
   270  
   271  	return ret
   272  }
   273  
   274  func (imap insnSetMap) sc(lev uint) []byte {
   275  	return imap["sc"].enc(map[string]uint{"LEV": lev})
   276  }