static void handle_nvrm_ioctl_vspace_unmap(struct nvrm_ioctl_vspace_unmap *s) { struct buffer *buf; int found = 0; for (buf = buffers_list; buf != NULL; buf = buf->next) if (buf->data1 == s->dev && buf->data2 == s->handle && buf->gpu_start == s->addr) { mmt_debug("clearing gpu address for buffer %d (was: 0x%08lx)\n", buf->id, buf->gpu_start); buf->gpu_start = 0; found = 1; break; } if (!found) { for (buf = gpu_only_buffers_list; buf != NULL; buf = buf->next) { if (buf->data1 == s->dev && buf->data2 == s->handle && buf->gpu_start == s->addr) { mmt_debug("deregistering gpu only buffer of size %ld\n", buf->length); buffer_free(buf); found = 1; break; } } if (!found) mmt_log("gpu only buffer not found%s\n", ""); } }
void decode_gf100_m2mf_verbose(struct gpu_object *obj, struct pushbuf_decode_state *pstate) { int mthd = pstate->mthd; uint32_t data = pstate->mthd_data; struct gf100_m2mf_data *objdata = obj->class_data; if (check_addresses_verbose(pstate, objdata->addresses)) { } else if (mthd == 0x0300) // EXEC { int flags_ok = (data & 0x111) == 0x111 ? 1 : 0; mmt_debug("m2mf exec: 0x%08x push&linear: %d\n", data, flags_ok); if (!flags_ok || objdata->offset_out.gpu_mapping == NULL) { objdata->offset_out.address = 0; objdata->offset_out.gpu_mapping = NULL; } } else if (mthd == 0x0304) // DATA { mmt_debug("m2mf data: 0x%08x\n", data); if (objdata->offset_out.gpu_mapping) { gpu_mapping_register_write(objdata->offset_out.gpu_mapping, objdata->offset_out.address + objdata->data_offset, 4, &data); objdata->data_offset += 4; } } }
static void maybe_merge_with_previous(struct region *cur, struct regions *parent) { // previous exists? if (!cur->prev) return; // previous ends before start of this one? if (cur->prev->end < cur->start) return; // now previous ends within this one // previous starts within this one? if (cur->prev->start >= cur->start) { // just drop previous entry drop_region(cur->prev, parent); // and see if previous^2 should be merged maybe_merge_with_previous(cur, parent); } else { // now previous starts before this one // extend current start mmt_debug("extending entry <0x%08x, 0x%08x> left to 0x%08x\n", cur->start, cur->end, cur->prev->start); cur->start = cur->prev->start; // and drop previous entry drop_region(cur->prev, parent); } }
static void handle_nvrm_ioctl_vspace_map(struct nvrm_ioctl_vspace_map *s) { struct buffer *buf; int found = 0; for (buf = buffers_list; buf != NULL; buf = buf->next) if (buf->data1 == s->dev && buf->data2 == s->handle && buf->length == s->size) { buf->gpu_start = s->addr; mmt_debug("setting gpu address for buffer %d to 0x%08lx\n", buf->id, buf->gpu_start); found = 1; break; } if (!found) { struct unk_map *tmp; for (tmp = unk_maps; tmp != NULL; tmp = tmp->next) { if (tmp->data1 == s->dev && tmp->data2 == s->handle) { mmt_log("TODO: unk buffer found, demmt_nv_gpu_map needs to be updated!%s\n", ""); break; } } register_gpu_only_buffer(s->addr, s->size, 0, s->dev, s->handle); } }
static void maybe_merge_with_next(struct region *cur, struct regions *parent) { // next exists? if (!cur->next) return; // next starts after this one? if (cur->next->start > cur->end) return; // now next starts within this one // next ends within this one? if (cur->next->end <= cur->end) { // drop next one drop_region(cur->next, parent); // and see if next^2 should be merged maybe_merge_with_next(cur, parent); } else { // now next ends after this one // extend current end mmt_debug("extending entry <0x%08x, 0x%08x> right to 0x%08x\n", cur->start, cur->end, cur->next->end); cur->end = cur->next->end; // and drop next entry drop_region(cur->next, parent); } }
static void g80_3d_disassemble(struct buffer *buf, const char *mode, uint32_t start_id) { if (!buf) return; mmt_debug("%s_start id 0x%08x\n", mode, start_id); struct region *reg; for (reg = buf->written_regions.head; reg != NULL; reg = reg->next) { if (reg->start != start_id) continue; if (MMT_DEBUG) { uint32_t x; mmt_debug("CODE: %s", ""); for (x = reg->start; x < reg->end; x += 4) mmt_debug_cont("0x%08x ", *(uint32_t *)(buf->data + x)); mmt_debug_cont("%s\n", ""); } if (!isa_g80) isa_g80 = ed_getisa("g80"); struct varinfo *var = varinfo_new(isa_g80->vardata); if (chipset == 0x50) varinfo_set_variant(var, "g80"); else if (chipset >= 0x84 && chipset <= 0x98) varinfo_set_variant(var, "g84"); else if (chipset == 0xa0) varinfo_set_variant(var, "g200"); else if (chipset >= 0xaa && chipset <= 0xac) varinfo_set_variant(var, "mcp77"); else if ((chipset >= 0xa3 && chipset <= 0xa8) || chipset == 0xaf) varinfo_set_variant(var, "gt215"); varinfo_set_mode(var, mode); envydis(isa_g80, stdout, buf->data + reg->start, 0, reg->end - reg->start, var, 0, NULL, 0, colors); varinfo_del(var); break; } }
void decode_g80_3d_verbose(struct pushbuf_decode_state *pstate) { int mthd = pstate->mthd; uint32_t data = pstate->mthd_data; if (check_addresses_verbose(pstate, g80_3d_addresses)) { } else if (mthd == 0x140c && dump_vp) // VP_START_ID g80_3d_disassemble(g80_3d.vp.buffer, "vp", data); else if (mthd == 0x1414 && dump_fp) // FP_START_ID g80_3d_disassemble(g80_3d.fp.buffer, "fp", data); else if (mthd == 0x1410 && dump_gp) // GP_START_ID g80_3d_disassemble(g80_3d.gp.buffer, "gp", data); else if (mthd >= 0x1444 && mthd < 0x1448 + 0x8 * 3) { int i; for (i = 0; i < 3; ++i) { if (dump_tsc && g80_3d.tsc.buffer && mthd == 0x1444 + i * 0x8) // BIND_TSC[i] { int j, tsc = (data >> 12) & 0xff; mmt_debug("bind tsc[%d]: 0x%08x\n", i, tsc); uint32_t *tsc_data = (uint32_t *)&g80_3d.tsc.buffer->data[8 * tsc]; for (j = 0; j < 8; ++j) decode_tsc(tsc, j, tsc_data); break; } if (dump_tic && g80_3d.tic.buffer && mthd == 0x1448 + i * 0x8) // BIND_TIC[i] { int j, tic = (data >> 9) & 0x1ffff; mmt_debug("bind tic[%d]: 0x%08x\n", i, tic); uint32_t *tic_data = (uint32_t *)&g80_3d.tic.buffer->data[8 * tic]; for (j = 0; j < 8; ++j) decode_tic(tic, j, tic_data); break; }
static void drop_region(struct region *reg, struct regions *parent) { struct region *prev = reg->prev; struct region *next = reg->next; mmt_debug("dropping entry <0x%08x, 0x%08x>\n", reg->start, reg->end); free(reg); if (prev) prev->next = next; else { mmt_debug("new head is at <0x%08x, 0x%08x>\n", next->start, next->end); parent->head = next; } if (next) next->prev = prev; else { mmt_debug("new last is at <0x%08x, 0x%08x>\n", prev->start, prev->end); parent->last = prev; } }
int check_addresses_verbose(struct pushbuf_decode_state *pstate, struct mthd2addr *addresses) { int mthd = pstate->mthd; struct mthd2addr *tmp = addresses; while (tmp->high) { if (tmp->low == mthd) { mmt_debug("buffer found: %d\n", tmp->buf->buffer ? 1 : 0); return 1; } tmp++; } return 0; }
static void handle_nvrm_ioctl_host_map(struct nvrm_ioctl_host_map *s) { struct buffer *buf; int found = 0; for (buf = buffers_list; buf != NULL; buf = buf->next) if (buf->mmap_offset == s->foffset) { buf->data1 = s->subdev; buf->data2 = s->handle; found = 1; break; } if (!found) { for (buf = gpu_only_buffers_list; buf != NULL; buf = buf->next) { if (buf->data1 == s->subdev && buf->data2 == s->handle) { if (buf->mmap_offset != s->foffset) { mmt_debug("gpu only buffer found (0x%016lx), merging mmap_offset\n", buf->gpu_start); buf->mmap_offset = s->foffset; } found = 1; break; } } if (!found) { struct unk_map *m = malloc(sizeof(struct unk_map)); m->data1 = s->subdev; m->data2 = s->handle; m->mmap_offset = s->foffset; m->next = unk_maps; unk_maps = m; } } }
static void __regions_add_range(struct regions *regions, uint32_t start, uint32_t len) { struct region *cur = regions->head; if (cur == NULL) { regions->head = cur = malloc(sizeof(struct region)); cur->start = start; cur->end = start + len; cur->prev = NULL; cur->next = NULL; regions->last = cur; return; } struct region *last_reg = regions->last; if (start == last_reg->end) { mmt_debug("extending last entry <0x%08x, 0x%08x> right by %d\n", last_reg->start, last_reg->end, len); last_reg->end += len; return; } if (start > last_reg->end) { mmt_debug("adding last entry <0x%08x, 0x%08x> after <0x%08x, 0x%08x>\n", start, start + len, last_reg->start, last_reg->end); cur = malloc(sizeof(struct region)); cur->start = start; cur->end = start + len; cur->prev = last_reg; cur->next = NULL; last_reg->next = cur; regions->last = cur; return; } if (start + len > last_reg->end) { mmt_debug("extending last entry <0x%08x, 0x%08x> right to 0x%08x\n", last_reg->start, last_reg->end, start + len); last_reg->end = start + len; if (start < last_reg->start) { mmt_debug("... and extending last entry <0x%08x, 0x%08x> left to 0x%08x\n", last_reg->start, last_reg->end, start); last_reg->start = start; maybe_merge_with_previous(last_reg, regions); } return; } while (start + len > cur->end) // if we will ever crash on cur being NULL then it means we screwed up earlier { if (cur->end == start) // optimization { mmt_debug("extending entry <0x%08x, 0x%08x> by %d\n", cur->start, cur->end, len); cur->end += len; maybe_merge_with_next(cur, regions); return; } cur = cur->next; } // now it ends before end of current // does it start in this one? if (start >= cur->start) return; // does it end before start of current one? if (start + len < cur->start) { mmt_debug("adding new entry <0x%08x, 0x%08x> before <0x%08x, 0x%08x>\n", start, start + len, cur->start, cur->end); struct region *tmp = malloc(sizeof(struct region)); tmp->start = start; tmp->end = start + len; tmp->prev = cur->prev; tmp->next = cur; if (cur->prev) cur->prev->next = tmp; else regions->head = tmp; cur->prev = tmp; maybe_merge_with_previous(tmp, regions); return; } // now it ends in current and starts before cur->start = start; maybe_merge_with_previous(cur, regions); }