Merge pull request #218 from saper/build-fixes
[envytools.git] / rnn / demmio.c
blobd86fa4c659750903784fe864c46e36bfa7a02345
1 /*
2 * Copyright (C) 2010-2011 Marcelina Koƛcielnicka <mwk@0x04.net>
3 * Copyright (C) 2011 Martin Peres <martin.peres@ensi-bourges.fr>
4 * All Rights Reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
26 #include "rnn.h"
27 #include "rnndec.h"
28 #include "var.h"
29 #include "dis.h"
30 #include "util.h"
31 #include "nvhw/chipset.h"
32 #include "seq.h"
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <inttypes.h>
36 #include <string.h>
37 #include <getopt.h>
39 int sleep_disabled = 0;
41 struct i2c_ctx {
42 int last;
43 int aok;
44 int wr;
45 int bits;
46 int b;
47 int pend;
50 struct cctx {
51 struct rnndeccontext *ctx;
52 struct chipset_info chipset;
53 uint64_t praminbase;
54 uint64_t ramins;
55 uint64_t fakechan;
56 int i2cip;
57 int hwsqip;
58 uint32_t hwsqnext;
59 uint32_t ctxpos;
60 uint8_t hwsq[0x200];
61 struct mpage **pages;
62 int pagesnum, pagesmax;
63 uint64_t bar0, bar0l, bar1, bar1l, bar2, bar2l;
64 struct i2c_ctx i2cb[10];
65 int crx0, crx1;
66 struct {
67 uint32_t len;
68 uint32_t script[2048];
69 enum {
70 SEQ_NONE = 0,
71 SEQ_PRINT,
72 SEQ_SKIP,
73 } action;
74 } seq;
77 struct cctx *cctx = 0;
78 int cctxnum = 0, cctxmax = 0;
80 struct mpage {
81 uint64_t tag;
82 uint32_t contents[0x1000/4];
85 uint32_t *findmem (struct cctx *ctx, uint64_t addr) {
86 int i;
87 uint64_t tag = addr & ~0xfffull;
88 for (i = 0; i < ctx->pagesnum; i++) {
89 if (tag == ctx->pages[i]->tag)
90 return &ctx->pages[i]->contents[(addr&0xfff)/4];
92 struct mpage *pg = calloc (sizeof *pg, 1);
93 pg->tag = tag;
94 ADDARRAY(ctx->pages, pg);
95 return &pg->contents[(addr&0xfff)/4];
98 int i2c_bus_num (uint64_t addr) {
99 switch (addr) {
100 case 0xe138:
101 return 0;
102 case 0xe150:
103 return 1;
104 case 0xe168:
105 return 2;
106 case 0xe180:
107 return 3;
108 case 0xe254:
109 return 4;
110 case 0xe274:
111 return 5;
112 case 0xe764:
113 return 6;
114 case 0xe780:
115 return 7;
116 case 0xe79c:
117 return 8;
118 case 0xe7b8:
119 return 9;
120 default:
121 return -1;
125 void doi2cr (struct cctx *cc, struct i2c_ctx *ctx, int byte) {
126 if (ctx->pend) {
127 if (ctx->bits == 8) {
128 if (byte & 2)
129 printf ("- ");
130 else
131 printf ("+ ");
132 if (!ctx->aok) {
133 ctx->aok = 1;
134 ctx->wr = !(ctx->b&1);
136 ctx->bits = 0;
137 ctx->b = 0;
138 } else {
139 ctx->b <<= 1;
140 ctx->b |= (byte & 2) >> 1;
141 ctx->bits++;
142 if (ctx->bits == 8) {
143 printf ("<%02x", ctx->b);
146 ctx->pend = 0;
150 void doi2cw (struct cctx *cc, struct i2c_ctx *ctx, int byte) {
151 if (!ctx->last)
152 ctx->last = 7;
153 if (!(byte & 1) && (ctx->last & 1)) {
154 /* clock went low */
156 if ((byte & 1) && !(ctx->last & 1)) {
157 if (ctx->pend) {
158 printf ("\nI2C LOST!\n");
159 doi2cr(cc, ctx, 0);
160 ctx->pend = 0;
162 /* clock went high */
163 if (ctx->bits == 8) {
164 if (ctx->wr || !ctx->aok) {
165 ctx->pend = 1;
166 } else {
167 if (byte & 2)
168 printf ("- ");
169 else
170 printf ("+ ");
171 ctx->bits = 0;
172 ctx->b = 0;
174 } else {
175 if (ctx->wr || !ctx->aok) {
176 ctx->b <<= 1;
177 ctx->b |= (byte & 2) >> 1;
178 ctx->bits++;
179 if (ctx->bits == 8) {
180 printf (">%02x", ctx->b);
182 } else {
183 ctx->pend = 1;
187 if ((byte & 1) && !(byte & 2) && (ctx->last & 2)) {
188 /* data went low with high clock - start bit */
189 printf ("START ");
190 ctx->bits = 0;
191 ctx->b = 0;
192 ctx->aok = 0;
193 ctx->wr = 0;
194 ctx->pend = 0;
195 sleep_disabled = 1;
197 if ((byte & 1) && (byte & 2) && !(ctx->last & 2)) {
198 /* data went high with high clock - stop bit */
199 printf ("STOP\n");
200 cc->i2cip = -1;
201 ctx->bits = 0;
202 ctx->b = 0;
203 ctx->aok = 0;
204 ctx->wr = 0;
205 ctx->pend = 0;
206 sleep_disabled = 0;
208 ctx->last = byte;
211 static void print_help() {
212 fprintf(stderr,
213 "Usage: demmio [-a <NVXXX>|-c|-f <file>|-h]\n"
214 "\n"
215 "Decodes MMIO traces using rnndb\n"
216 "\n"
217 "Options:\n"
218 "\t-a <gen> Specify the chipset variant to use (autodetected by default)\n"
219 "\t-c Disable colors\n"
220 "\t-f <file> Specify the file to read from (defaults to stdin)\n"
221 "\t-h Show this help message\n");
224 int main(int argc, char **argv) {
225 char *file = NULL;
226 char *variant = NULL;
227 unsigned long chip = 0;
228 int c,use_colors=1;
229 while ((c = getopt (argc, argv, "f:ca:h")) != -1) {
230 switch (c) {
231 case 'a':
232 chip = strtoull(optarg, NULL, 16);
233 if (!chip)
234 variant = strdup(optarg);
235 else {
236 free(variant);
237 variant = NULL;
239 break;
240 case 'f':{
241 file = strdup(optarg);
242 break;
244 case 'c':{
245 use_colors = 0;
246 break;
248 case 'h':{
249 print_help();
250 return 0;
252 default:{
253 break;
257 rnn_init();
259 struct rnndb *db = rnn_newdb();
260 rnn_parsefile (db, "nv_mmio.xml");
261 rnn_prepdb (db);
262 struct rnndomain *mmiodom = rnn_finddomain(db, "NV_MMIO");
263 struct rnndomain *crdom = rnn_finddomain(db, "NV_CR");
264 FILE *fin = (file==NULL) ? stdin : open_input(file);
265 if (!fin) {
266 fprintf (stderr, "Failed to open input file!\n");
267 return 1;
270 char line[1024];
271 int i;
272 const struct disisa *ctx_isa = ed_getisa("ctx");
273 struct varinfo *ctx_var_nv40 = varinfo_new(ctx_isa->vardata);
274 struct varinfo *ctx_var_g80 = varinfo_new(ctx_isa->vardata);
275 varinfo_set_variant(ctx_var_nv40, "nv40");
276 varinfo_set_variant(ctx_var_g80, "g80");
277 const struct disisa *hwsq_isa = ed_getisa("hwsq");
278 struct varinfo *hwsq_var_nv17 = varinfo_new(hwsq_isa->vardata);
279 struct varinfo *hwsq_var_nv41 = varinfo_new(hwsq_isa->vardata);
280 struct varinfo *hwsq_var_g80 = varinfo_new(hwsq_isa->vardata);
281 varinfo_set_variant(hwsq_var_nv17, "nv17");
282 varinfo_set_variant(hwsq_var_nv41, "nv41");
283 varinfo_set_variant(hwsq_var_g80, "g80");
284 const struct envy_colors *colors = use_colors ? &envy_def_colors : &envy_null_colors;
285 while (1) {
286 /* yes, static buffer. but mmiotrace lines are bound to have sane length anyway. */
287 if (!fgets(line, sizeof(line), fin))
288 break;
289 if (!strncmp(line, "PCIDEV ", 7)) {
290 uint64_t bar[4], len[4], pciid;
291 sscanf (line, "%*s %*s %"SCNx64" %*s %"SCNx64" %"SCNx64" %"SCNx64" %"SCNx64" %*s %*s %*s %"SCNx64" %"SCNx64" %"SCNx64" %"SCNx64"", &pciid, &bar[0], &bar[1], &bar[2], &bar[3], &len[0], &len[1], &len[2], &len[3]);
292 if ((pciid >> 16) == 0x10de && bar[0] && (bar[0] & 0xf) == 0 && bar[1] && (bar[1] & 0x1) == 0x0) {
293 struct cctx nc = { 0 };
294 nc.bar0 = bar[0], nc.bar0l = len[0];
295 nc.bar1 = bar[1], nc.bar1l = len[1];
296 if (bar[2])
297 nc.bar2 = bar[2], nc.bar2l = len[2];
298 else
299 nc.bar2 = bar[3], nc.bar2l = len[3];
300 nc.bar0 &= ~0xf;
301 nc.bar1 &= ~0xf;
302 nc.bar2 &= ~0xf;
303 nc.i2cip = -1;
304 nc.ctx = rnndec_newcontext(db);
305 nc.ctx->colors = colors;
306 for (i = 0; i < 10; i++)
307 nc.i2cb[i].last = 7;
308 ADDARRAY(cctx, nc);
310 printf ("%s", line);
311 } else if (!strncmp(line, "W ", 2) || !strncmp(line, "R ", 2)) {
312 int skip = 0;
313 static double timestamp, timestamp_old = 0;
314 uint64_t addr, value;
315 int width;
316 int cci;
317 sscanf (line, "%*s %d %lf %*d %"SCNx64" %"SCNx64, &width, &timestamp, &addr, &value);
318 width *= 8;
320 /* Add a SLEEP line when two mmio accesses are more distant than 100”s */
321 if (!sleep_disabled && timestamp_old > 0 && (timestamp - timestamp_old) > 0.0001)
322 printf("SLEEP %lfms\n", (timestamp - timestamp_old)*1000.0);
323 timestamp_old = timestamp;
325 for (cci = 0; cci < cctxnum; cci++) {
326 struct cctx *cc = &cctx[cci];
327 if (cc->bar0 && addr >= cc->bar0 && addr < cc->bar0+cc->bar0l) {
328 addr -= cc->bar0;
329 if (cc->hwsqip && addr != cc->hwsqnext) {
330 struct varinfo *var = hwsq_var_nv17;
331 if (cc->chipset.chipset >= 0x41)
332 var = hwsq_var_nv41;
333 if (cc->chipset.card_type == 0x50)
334 var = hwsq_var_g80;
335 envydis(hwsq_isa, stdout, cc->hwsq, 0, cc->hwsqnext & 0x3fc, var, 0, 0, 0, colors);
336 cc->hwsqip = 0;
338 /* Seq */
339 if (cc->seq.action == SEQ_SKIP && addr != 0x10a1c4) {
340 cc->seq.action = SEQ_NONE;
341 } else if (cc->seq.action == SEQ_PRINT && addr != 0x10a1c4) {
342 seq_print(cc->seq.script, cc->seq.len, cc->ctx, mmiodom);
343 cc->seq.len = 0;
344 cc->seq.action = SEQ_NONE;
347 if (!cc->chipset.chipset) {
348 /* The user may have manually specified this */
349 if (variant) {
350 rnndec_varadd(cc->ctx, "chipset", variant);
351 } else if (chip) {
352 rnndec_varaddvalue(cc->ctx, "chipset", chip);
353 } else if (addr == 0) {
354 parse_pmc_id(value, &cc->chipset);
355 if (cc->chipset.chipset)
356 rnndec_varaddvalue(cc->ctx, "chipset",
357 cc->chipset.chipset);
359 } else if (cc->chipset.card_type >= 0x50 && addr == 0x1700) {
360 cc->praminbase = value << 16;
361 } else if (cc->chipset.card_type == 0x50 && addr == 0x1704) {
362 cc->fakechan = (value & 0xfffffff) << 12;
363 } else if (cc->chipset.card_type == 0x50 && addr == 0x170c) {
364 cc->ramins = (value & 0xffff) << 4;
365 } else if (cc->chipset.card_type >= 0xc0 && addr == 0x1714) {
366 cc->ramins = (value & 0xfffffff) << 12;
367 } else if (addr == 0x6013d4) {
368 cc->crx0 = value & 0xff;
369 } else if (addr == 0x6033d4) {
370 cc->crx1 = value & 0xff;
371 } else if (addr == 0x6013d5) {
372 struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, crdom, cc->crx0, line[0] == 'W');
373 char *decoded_val = rnndec_decodeval(cc->ctx, ai->typeinfo, value, ai->width);
374 printf ("[%d] %lf HEAD0 %c 0x%02x 0x%02"PRIx64" %s %s %s\n", cci, timestamp, line[0], cc->crx0, value, ai->name, line[0]=='W'?"<=":"=>", decoded_val);
375 rnndec_free_decaddrinfo(ai);
376 free(decoded_val);
377 skip = 1;
378 } else if (addr == 0x6033d5) {
379 struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, crdom, cc->crx1, line[0] == 'W');
380 char *decoded_val = rnndec_decodeval(cc->ctx, ai->typeinfo, value, ai->width);
381 printf ("[%d] %lf HEAD1 %c 0x%02x 0x%02"PRIx64" %s %s %s\n", cci, timestamp, line[0], cc->crx1, value, ai->name, line[0]=='W'?"<=":"=>", decoded_val);
382 rnndec_free_decaddrinfo(ai);
383 free(decoded_val);
384 skip = 1;
385 } else if (cc->chipset.card_type >= 0x50 && (addr & 0xfff000) == 0xe000) {
386 int bus = i2c_bus_num(addr);
387 if (bus != -1) {
388 if (cc->i2cip != bus) {
389 if (cc->i2cip != -1)
390 printf ("\n");
391 struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, mmiodom, addr, line[0] == 'W');
392 printf ("[%d] I2C 0x%06"PRIx64" %s ", cci, addr, ai->name);
393 rnndec_free_decaddrinfo(ai);
394 cc->i2cip = bus;
396 if (line[0] == 'R') {
397 doi2cr(cc, &cc->i2cb[bus], value);
398 } else {
399 doi2cw(cc, &cc->i2cb[bus], value);
401 skip = 1;
403 } else if ((addr & 0xfff000) == 0x9000 && (cc->i2cip != -1)) {
404 /* ignore PTIMER meddling during I2C */
405 skip = 1;
406 } else if (addr == 0x1400 || addr == 0x80000 || (addr == cc->hwsqnext && cc->hwsqip)) {
407 if (!cc->hwsqip) {
408 struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, mmiodom, addr, line[0] == 'W');
409 printf ("[%d] HWSQ 0x%06"PRIx64" %s\n", cci, addr, ai->name);
410 rnndec_free_decaddrinfo(ai);
412 cc->hwsq[(addr & 0x1fc) + 0] = value;
413 cc->hwsq[(addr & 0x1fc) + 1] = value >> 8;
414 cc->hwsq[(addr & 0x1fc) + 2] = value >> 16;
415 cc->hwsq[(addr & 0x1fc) + 3] = value >> 24;
416 cc->hwsqip = 1;
417 cc->hwsqnext = addr + 4;
418 skip = 1;
419 } else if (addr == 0x10a1c4) {
420 if (cc->seq.action == SEQ_NONE) {
421 /* Crude test whether this vaguely looks like an opcode..
422 * print will do a more thorough check */
423 if ((value & 0xfc00ffc0) == 0 && value != 0) {
424 cc->seq.action = SEQ_PRINT;
425 } else {
426 cc->seq.action = SEQ_SKIP;
430 if(cc->seq.action == SEQ_PRINT) {
431 if (cc->seq.len < 2048) {
432 cc->seq.script[cc->seq.len] = value;
433 cc->seq.len++;
434 } else {
435 printf("[%d] PDAEMON %06"PRIx64" Script too long, skipping\n", cci, addr);
436 cc->seq.len = 0;
437 cc->seq.action = SEQ_SKIP;
440 } else if (addr == 0x400324 && cc->chipset.card_type >= 0x40 && cc->chipset.card_type <= 0x50) {
441 cc->ctxpos = value;
442 } else if (addr == 0x400328 && cc->chipset.card_type >= 0x40 && cc->chipset.card_type <= 0x50) {
443 uint8_t param[4];
444 param[0] = value;
445 param[1] = value >> 8;
446 param[2] = value >> 16;
447 param[3] = value >> 24;
448 struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, mmiodom, addr, line[0] == 'W');
449 printf ("[%d] MMIO%d %c 0x%06"PRIx64" 0x%08"PRIx64" %s %s ", cci, width, line[0], addr, value, ai->name, line[0]=='W'?"<=":"=>");
450 envydis(ctx_isa, stdout, param, cc->ctxpos, 1, (cc->chipset.card_type == 0x50 ? ctx_var_g80 : ctx_var_nv40), 0, 0, 0, colors);
451 cc->ctxpos++;
452 rnndec_free_decaddrinfo(ai);
453 skip = 1;
455 if (!skip && (cc->i2cip != -1)) {
456 printf ("\n");
457 cc->i2cip = -1;
459 if (cc->chipset.card_type >= 0x50 && addr >= 0x700000 && addr < 0x800000) {
460 addr -= 0x700000;
461 addr += cc->praminbase;
462 printf ("[%d] %lf, MEM%d %"PRIx64" %s %"PRIx64"\n", cci, timestamp, width, addr, line[0]=='W'?"<=":"=>", value);
463 *findmem(cc, addr) = value;
464 } else if (!skip) {
465 struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, mmiodom, addr, line[0] == 'W');
466 if (width == 32 && ai->width == 8) {
467 /* 32-bit write to 8-bit location - split it up */
468 int b;
469 rnndec_free_decaddrinfo(ai);
470 int cnt;
471 for (b = 0; b < 4; b++) {
472 struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, mmiodom, addr+b, line[0] == 'W');
473 char *decoded_val = rnndec_decodeval(cc->ctx, ai->typeinfo, value >> b * 8 & 0xff, ai->width);
474 if (b == 0) {
475 printf ("[%d] %lf MMIO%d %c 0x%06"PRIx64" 0x%08"PRIx64" %n%s %s %s\n", cci, timestamp, width, line[0], addr, value, &cnt, ai->name, line[0]=='W'?"<=":"=>", decoded_val);
476 } else {
477 int c;
478 for (c = 0; c < cnt; c++)
479 printf(" ");
480 printf ("%s %s %s\n", ai->name, line[0]=='W'?"<=":"=>", decoded_val);
482 rnndec_free_decaddrinfo(ai);
483 free(decoded_val);
485 } else {
486 char *decoded_val = rnndec_decodeval(cc->ctx, ai->typeinfo, value, ai->width);
487 printf ("[%d] %lf MMIO%d %c 0x%06"PRIx64" 0x%08"PRIx64" %s %s %s\n", cci, timestamp, width, line[0], addr, value, ai->name, line[0]=='W'?"<=":"=>", decoded_val);
488 free(ai->name);
489 free(ai);
490 free(decoded_val);
493 } else if (cc->bar1 && addr >= cc->bar1 && addr < cc->bar1+cc->bar1l) {
494 addr -= cc->bar1;
495 printf ("[%d] %lf, FB%d %"PRIx64" %s %"PRIx64"\n", cci, timestamp, width, addr, line[0]=='W'?"<=":"=>", value);
496 } else if (cc->bar2 && addr >= cc->bar2 && addr < cc->bar2+cc->bar2l) {
497 addr -= cc->bar2;
498 if (cc->chipset.card_type >= 0xc0) {
499 uint64_t pd = *findmem(cc, cc->ramins + 0x200);
500 uint64_t pt = *findmem(cc, pd + 4);
501 pt &= 0xfffffff0;
502 pt <<= 8;
503 uint64_t pg = *findmem(cc, pt + (addr/0x1000) * 8);
504 pg &= 0xfffffff0;
505 pg <<= 8;
506 pg += (addr&0xfff);
507 *findmem(cc, pg) = value;
508 // printf ("%"PRIx64" %"PRIx64" %"PRIx64" %"PRIx64"\n", ramins, pd, pt, pg);
509 printf ("[%d] %lf RAMIN%d %"PRIx64" %"PRIx64" %s %"PRIx64"\n", cci, timestamp, width, addr, pg, line[0]=='W'?"<=":"=>", value);
510 } else if (cc->chipset.card_type == 0x50) {
511 uint64_t paddr = addr;
512 paddr += *findmem(cc, cc->fakechan + cc->ramins + 8);
513 paddr += (uint64_t)(*findmem(cc, cc->fakechan + cc->ramins + 12) >> 24) << 32;
514 uint64_t pt = *findmem(cc, cc->fakechan + (cc->chipset.chipset == 0x50 ? 0x1400 : 0x200) + ((paddr >> 29) << 3));
515 // printf ("%#"PRIx64" PT: %#"PRIx64" %#"PRIx64" ", paddr, fakechan + 0x200 + ((paddr >> 29) << 3), pt);
516 uint32_t div = (pt & 2 ? 0x1000 : 0x10000);
517 pt &= 0xfffff000;
518 uint64_t pg = *findmem(cc, pt + ((paddr&0x1ffff000)/div) * 8);
519 uint64_t pgh = *findmem(cc, pt + ((paddr&0x1ffff000)/div) * 8 + 4);
520 // printf ("PG: %#"PRIx64" %#"PRIx64"\n", pt + ((paddr&0x1ffff000)/div) * 8, pgh << 32 | pg);
521 pg &= 0xfffff000;
522 pg |= (pgh & 0xff) << 32;
523 pg += (paddr & (div-1));
524 *findmem(cc, pg) = value;
525 // printf ("%"PRIx64" %"PRIx64" %"PRIx64" %"PRIx64"\n", ramins, pd, pt, pg);
526 printf ("[%d] %lf RAMIN%d %"PRIx64" %"PRIx64" %s %"PRIx64"\n", cci, timestamp, width, addr, pg, line[0]=='W'?"<=":"=>", value);
527 } else {
528 printf ("[%d] %lf RAMIN%d %"PRIx64" %s %"PRIx64"\n", cci, timestamp, width, addr, line[0]=='W'?"<=":"=>", value);
532 } else {
533 printf ("%s", line);
537 rnn_freedb(db);
538 rnn_fini();
540 return 0;