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 }