1/* 2 * Copyright © 2021 Google, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#include <err.h> 25#include <stdarg.h> 26#include <stdio.h> 27#include <string.h> 28 29#include "rnn.h" 30#include "rnndec.h" 31 32#include "afuc.h" 33#include "util.h" 34 35static struct rnndeccontext *ctx; 36static struct rnndb *db; 37static struct rnndomain *control_regs; 38static struct rnndomain *pipe_regs; 39struct rnndomain *dom[2]; 40static struct rnnenum *pm4_packets; 41 42static int 43find_reg(struct rnndomain *dom, const char *name) 44{ 45 for (int i = 0; i < dom->subelemsnum; i++) 46 if (!strcmp(name, dom->subelems[i]->name)) 47 return dom->subelems[i]->offset; 48 49 return -1; 50} 51 52static unsigned 53reg(struct rnndomain *dom, const char *type, const char *name) 54{ 55 int val = find_reg(dom, name); 56 if (val < 0) { 57 char *endptr = NULL; 58 val = strtol(name, &endptr, 0); 59 if (endptr && *endptr) { 60 printf("invalid %s reg: %s\n", type, name); 61 exit(2); 62 } 63 } 64 return (unsigned)val; 65} 66 67static char * 68reg_name(struct rnndomain *dom, unsigned id) 69{ 70 if (rnndec_checkaddr(ctx, dom, id, 0)) { 71 struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, dom, id, 0); 72 char *name = info->name; 73 free(info); 74 return name; 75 } else { 76 return NULL; 77 } 78} 79 80/** 81 * Map control reg name to offset. 82 */ 83unsigned 84afuc_control_reg(const char *name) 85{ 86 return reg(control_regs, "control", name); 87} 88 89/** 90 * Map offset to control reg name (or NULL), caller frees 91 */ 92char * 93afuc_control_reg_name(unsigned id) 94{ 95 return reg_name(control_regs, id); 96} 97 98/** 99 * Map pipe reg name to offset. 100 */ 101unsigned 102afuc_pipe_reg(const char *name) 103{ 104 return reg(pipe_regs, "pipe", name); 105} 106 107/** 108 * "void" pipe regs don't have a value written, the $addr right is 109 * enough to trigger what they do 110 */ 111bool 112afuc_pipe_reg_is_void(unsigned id) 113{ 114 if (rnndec_checkaddr(ctx, pipe_regs, id, 0)) { 115 struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, pipe_regs, id, 0); 116 free(info->name); 117 bool ret = !strcmp(info->typeinfo->name, "void"); 118 free(info); 119 return ret; 120 } else { 121 return false; 122 } 123} 124 125/** 126 * Map offset to pipe reg name (or NULL), caller frees 127 */ 128char * 129afuc_pipe_reg_name(unsigned id) 130{ 131 return reg_name(pipe_regs, id); 132} 133 134/** 135 * Map GPU reg name to offset. 136 */ 137unsigned 138afuc_gpu_reg(const char *name) 139{ 140 int val = find_reg(dom[0], name); 141 if (val < 0) 142 val = find_reg(dom[1], name); 143 if (val < 0) { 144 char *endptr = NULL; 145 val = strtol(name, &endptr, 0); 146 if (endptr && *endptr) { 147 printf("invalid control reg: %s\n", name); 148 exit(2); 149 } 150 } 151 return (unsigned)val; 152} 153 154/** 155 * Map offset to gpu reg name (or NULL), caller frees 156 */ 157char * 158afuc_gpu_reg_name(unsigned id) 159{ 160 struct rnndomain *d = NULL; 161 162 if (rnndec_checkaddr(ctx, dom[0], id, 0)) { 163 d = dom[0]; 164 } else if (rnndec_checkaddr(ctx, dom[1], id, 0)) { 165 d = dom[1]; 166 } 167 168 if (d) { 169 struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, d, id, 0); 170 if (info) { 171 char *name = info->name; 172 free(info); 173 return name; 174 } 175 } 176 177 return NULL; 178} 179 180unsigned 181afuc_gpr_reg(const char *name) 182{ 183 /* If it starts with '$' just swallow it: */ 184 if (name[0] == '$') 185 name++; 186 187 /* handle aliases: */ 188 if (!strcmp(name, "rem")) { 189 return REG_REM; 190 } else if (!strcmp(name, "memdata")) { 191 return REG_MEMDATA; 192 } else if (!strcmp(name, "addr")) { 193 return REG_ADDR; 194 } else if (!strcmp(name, "regdata")) { 195 return REG_REGDATA; 196 } else if (!strcmp(name, "usraddr")) { 197 return REG_USRADDR; 198 } else if (!strcmp(name, "data")) { 199 return REG_DATA; 200 } else { 201 char *endptr = NULL; 202 unsigned val = strtol(name, &endptr, 16); 203 if (endptr && *endptr) { 204 printf("invalid gpr reg: %s\n", name); 205 exit(2); 206 } 207 return val; 208 } 209} 210 211static int 212find_enum_val(struct rnnenum *en, const char *name) 213{ 214 int i; 215 216 for (i = 0; i < en->valsnum; i++) 217 if (en->vals[i]->valvalid && !strcmp(name, en->vals[i]->name)) 218 return en->vals[i]->value; 219 220 return -1; 221} 222 223/** 224 * Map pm4 packet name to id 225 */ 226int 227afuc_pm4_id(const char *name) 228{ 229 return find_enum_val(pm4_packets, name); 230} 231 232const char * 233afuc_pm_id_name(unsigned id) 234{ 235 return rnndec_decode_enum(ctx, "adreno_pm4_type3_packets", id); 236} 237 238void 239afuc_printc(enum afuc_color c, const char *fmt, ...) 240{ 241 va_list args; 242 if (c == AFUC_ERR) { 243 printf("%s", ctx->colors->err); 244 } else if (c == AFUC_LBL) { 245 printf("%s", ctx->colors->btarg); 246 } 247 va_start(args, fmt); 248 vprintf(fmt, args); 249 va_end(args); 250 printf("%s", ctx->colors->reset); 251} 252 253int afuc_util_init(int gpuver, bool colors) 254{ 255 char *name, *control_reg_name; 256 char *pipe_reg_name = NULL; 257 258 switch (gpuver) { 259 case 6: 260 name = "A6XX"; 261 control_reg_name = "A6XX_CONTROL_REG"; 262 pipe_reg_name = "A6XX_PIPE_REG"; 263 break; 264 case 5: 265 name = "A5XX"; 266 control_reg_name = "A5XX_CONTROL_REG"; 267 pipe_reg_name = "A5XX_PIPE_REG"; 268 break; 269 default: 270 fprintf(stderr, "unknown GPU version!\n"); 271 return -1; 272 } 273 274 rnn_init(); 275 db = rnn_newdb(); 276 277 ctx = rnndec_newcontext(db); 278 ctx->colors = colors ? &envy_def_colors : &envy_null_colors; 279 280 rnn_parsefile(db, "adreno.xml"); 281 rnn_prepdb(db); 282 if (db->estatus) 283 errx(db->estatus, "failed to parse register database"); 284 dom[0] = rnn_finddomain(db, name); 285 dom[1] = rnn_finddomain(db, "AXXX"); 286 control_regs = rnn_finddomain(db, control_reg_name); 287 pipe_regs = rnn_finddomain(db, pipe_reg_name); 288 289 rnndec_varadd(ctx, "chip", name); 290 291 pm4_packets = rnn_findenum(ctx->db, "adreno_pm4_type3_packets"); 292 293 return 0; 294} 295 296