17ec681f3Smrg/* 27ec681f3Smrg * Copyright (C) 2019 Alyssa Rosenzweig 37ec681f3Smrg * Copyright (C) 2017-2018 Lyude Paul 47ec681f3Smrg * Copyright (C) 2019 Collabora, Ltd. 57ec681f3Smrg * 67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 87ec681f3Smrg * to deal in the Software without restriction, including without limitation 97ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 107ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 117ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 127ec681f3Smrg * 137ec681f3Smrg * The above copyright notice and this permission notice (including the next 147ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 157ec681f3Smrg * Software. 167ec681f3Smrg * 177ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 187ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 197ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 207ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 217ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 227ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 237ec681f3Smrg * SOFTWARE. 247ec681f3Smrg */ 257ec681f3Smrg 267ec681f3Smrg#include <stdio.h> 277ec681f3Smrg#include <stdlib.h> 287ec681f3Smrg#include <assert.h> 297ec681f3Smrg#include <stdint.h> 307ec681f3Smrg#include <string.h> 317ec681f3Smrg#include <sys/mman.h> 327ec681f3Smrg 337ec681f3Smrg#include "decode.h" 347ec681f3Smrg#include "util/macros.h" 357ec681f3Smrg#include "util/u_debug.h" 367ec681f3Smrg#include "util/u_dynarray.h" 377ec681f3Smrg#include "util/hash_table.h" 387ec681f3Smrg 397ec681f3SmrgFILE *pandecode_dump_stream; 407ec681f3Smrg 417ec681f3Smrg/* Memory handling */ 427ec681f3Smrg 437ec681f3Smrgstatic struct hash_table_u64 *mmap_table; 447ec681f3Smrg 457ec681f3Smrgstatic struct util_dynarray ro_mappings; 467ec681f3Smrg 477ec681f3Smrgstatic struct pandecode_mapped_memory * 487ec681f3Smrgpandecode_find_mapped_gpu_mem_containing_rw(uint64_t addr) 497ec681f3Smrg{ 507ec681f3Smrg return _mesa_hash_table_u64_search(mmap_table, addr & ~(4096 - 1)); 517ec681f3Smrg} 527ec681f3Smrg 537ec681f3Smrgstruct pandecode_mapped_memory * 547ec681f3Smrgpandecode_find_mapped_gpu_mem_containing(uint64_t addr) 557ec681f3Smrg{ 567ec681f3Smrg struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing_rw(addr); 577ec681f3Smrg 587ec681f3Smrg if (mem && mem->addr && !mem->ro) { 597ec681f3Smrg mprotect(mem->addr, mem->length, PROT_READ); 607ec681f3Smrg mem->ro = true; 617ec681f3Smrg util_dynarray_append(&ro_mappings, struct pandecode_mapped_memory *, mem); 627ec681f3Smrg } 637ec681f3Smrg 647ec681f3Smrg return mem; 657ec681f3Smrg} 667ec681f3Smrg 677ec681f3Smrgvoid 687ec681f3Smrgpandecode_map_read_write(void) 697ec681f3Smrg{ 707ec681f3Smrg util_dynarray_foreach(&ro_mappings, struct pandecode_mapped_memory *, mem) { 717ec681f3Smrg (*mem)->ro = false; 727ec681f3Smrg mprotect((*mem)->addr, (*mem)->length, PROT_READ | PROT_WRITE); 737ec681f3Smrg } 747ec681f3Smrg util_dynarray_clear(&ro_mappings); 757ec681f3Smrg} 767ec681f3Smrg 777ec681f3Smrgstatic void 787ec681f3Smrgpandecode_add_name(struct pandecode_mapped_memory *mem, uint64_t gpu_va, const char *name) 797ec681f3Smrg{ 807ec681f3Smrg if (!name) { 817ec681f3Smrg /* If we don't have a name, assign one */ 827ec681f3Smrg 837ec681f3Smrg snprintf(mem->name, sizeof(mem->name) - 1, 847ec681f3Smrg "memory_%" PRIx64, gpu_va); 857ec681f3Smrg } else { 867ec681f3Smrg assert((strlen(name) + 1) < sizeof(mem->name)); 877ec681f3Smrg memcpy(mem->name, name, strlen(name) + 1); 887ec681f3Smrg } 897ec681f3Smrg} 907ec681f3Smrg 917ec681f3Smrgvoid 927ec681f3Smrgpandecode_inject_mmap(uint64_t gpu_va, void *cpu, unsigned sz, const char *name) 937ec681f3Smrg{ 947ec681f3Smrg /* First, search if we already mapped this and are just updating an address */ 957ec681f3Smrg 967ec681f3Smrg struct pandecode_mapped_memory *existing = 977ec681f3Smrg pandecode_find_mapped_gpu_mem_containing_rw(gpu_va); 987ec681f3Smrg 997ec681f3Smrg if (existing && existing->gpu_va == gpu_va) { 1007ec681f3Smrg existing->length = sz; 1017ec681f3Smrg existing->addr = cpu; 1027ec681f3Smrg pandecode_add_name(existing, gpu_va, name); 1037ec681f3Smrg return; 1047ec681f3Smrg } 1057ec681f3Smrg 1067ec681f3Smrg /* Otherwise, add a fresh mapping */ 1077ec681f3Smrg struct pandecode_mapped_memory *mapped_mem = NULL; 1087ec681f3Smrg 1097ec681f3Smrg mapped_mem = calloc(1, sizeof(*mapped_mem)); 1107ec681f3Smrg mapped_mem->gpu_va = gpu_va; 1117ec681f3Smrg mapped_mem->length = sz; 1127ec681f3Smrg mapped_mem->addr = cpu; 1137ec681f3Smrg pandecode_add_name(mapped_mem, gpu_va, name); 1147ec681f3Smrg 1157ec681f3Smrg /* Add it to the table */ 1167ec681f3Smrg assert((gpu_va & 4095) == 0); 1177ec681f3Smrg 1187ec681f3Smrg for (unsigned i = 0; i < sz; i += 4096) 1197ec681f3Smrg _mesa_hash_table_u64_insert(mmap_table, gpu_va + i, mapped_mem); 1207ec681f3Smrg} 1217ec681f3Smrg 1227ec681f3Smrgvoid 1237ec681f3Smrgpandecode_inject_free(uint64_t gpu_va, unsigned sz) 1247ec681f3Smrg{ 1257ec681f3Smrg struct pandecode_mapped_memory *mem = 1267ec681f3Smrg pandecode_find_mapped_gpu_mem_containing_rw(gpu_va); 1277ec681f3Smrg 1287ec681f3Smrg if (!mem) 1297ec681f3Smrg return; 1307ec681f3Smrg 1317ec681f3Smrg assert(mem->gpu_va == gpu_va); 1327ec681f3Smrg assert(mem->length == sz); 1337ec681f3Smrg 1347ec681f3Smrg free(mem); 1357ec681f3Smrg 1367ec681f3Smrg for (unsigned i = 0; i < sz; i += 4096) 1377ec681f3Smrg _mesa_hash_table_u64_remove(mmap_table, gpu_va + i); 1387ec681f3Smrg} 1397ec681f3Smrg 1407ec681f3Smrgchar * 1417ec681f3Smrgpointer_as_memory_reference(uint64_t ptr) 1427ec681f3Smrg{ 1437ec681f3Smrg struct pandecode_mapped_memory *mapped; 1447ec681f3Smrg char *out = malloc(128); 1457ec681f3Smrg 1467ec681f3Smrg /* Try to find the corresponding mapped zone */ 1477ec681f3Smrg 1487ec681f3Smrg mapped = pandecode_find_mapped_gpu_mem_containing_rw(ptr); 1497ec681f3Smrg 1507ec681f3Smrg if (mapped) { 1517ec681f3Smrg snprintf(out, 128, "%s + %d", mapped->name, (int) (ptr - mapped->gpu_va)); 1527ec681f3Smrg return out; 1537ec681f3Smrg } 1547ec681f3Smrg 1557ec681f3Smrg /* Just use the raw address if other options are exhausted */ 1567ec681f3Smrg 1577ec681f3Smrg snprintf(out, 128, "0x%" PRIx64, ptr); 1587ec681f3Smrg return out; 1597ec681f3Smrg 1607ec681f3Smrg} 1617ec681f3Smrg 1627ec681f3Smrgstatic int pandecode_dump_frame_count = 0; 1637ec681f3Smrg 1647ec681f3Smrgstatic bool force_stderr = false; 1657ec681f3Smrg 1667ec681f3Smrgvoid 1677ec681f3Smrgpandecode_dump_file_open(void) 1687ec681f3Smrg{ 1697ec681f3Smrg if (pandecode_dump_stream) 1707ec681f3Smrg return; 1717ec681f3Smrg 1727ec681f3Smrg /* This does a getenv every frame, so it is possible to use 1737ec681f3Smrg * setenv to change the base at runtime. 1747ec681f3Smrg */ 1757ec681f3Smrg const char *dump_file_base = debug_get_option("PANDECODE_DUMP_FILE", "pandecode.dump"); 1767ec681f3Smrg if (force_stderr || !strcmp(dump_file_base, "stderr")) 1777ec681f3Smrg pandecode_dump_stream = stderr; 1787ec681f3Smrg else { 1797ec681f3Smrg char buffer[1024]; 1807ec681f3Smrg snprintf(buffer, sizeof(buffer), "%s.%04d", dump_file_base, pandecode_dump_frame_count); 1817ec681f3Smrg printf("pandecode: dump command stream to file %s\n", buffer); 1827ec681f3Smrg pandecode_dump_stream = fopen(buffer, "w"); 1837ec681f3Smrg if (!pandecode_dump_stream) 1847ec681f3Smrg fprintf(stderr, 1857ec681f3Smrg "pandecode: failed to open command stream log file %s\n", 1867ec681f3Smrg buffer); 1877ec681f3Smrg } 1887ec681f3Smrg} 1897ec681f3Smrg 1907ec681f3Smrgstatic void 1917ec681f3Smrgpandecode_dump_file_close(void) 1927ec681f3Smrg{ 1937ec681f3Smrg if (pandecode_dump_stream && pandecode_dump_stream != stderr) { 1947ec681f3Smrg if (fclose(pandecode_dump_stream)) 1957ec681f3Smrg perror("pandecode: dump file"); 1967ec681f3Smrg 1977ec681f3Smrg pandecode_dump_stream = NULL; 1987ec681f3Smrg } 1997ec681f3Smrg} 2007ec681f3Smrg 2017ec681f3Smrgvoid 2027ec681f3Smrgpandecode_initialize(bool to_stderr) 2037ec681f3Smrg{ 2047ec681f3Smrg force_stderr = to_stderr; 2057ec681f3Smrg mmap_table = _mesa_hash_table_u64_create(NULL); 2067ec681f3Smrg util_dynarray_init(&ro_mappings, NULL); 2077ec681f3Smrg} 2087ec681f3Smrg 2097ec681f3Smrgvoid 2107ec681f3Smrgpandecode_next_frame(void) 2117ec681f3Smrg{ 2127ec681f3Smrg pandecode_dump_file_close(); 2137ec681f3Smrg pandecode_dump_frame_count++; 2147ec681f3Smrg} 2157ec681f3Smrg 2167ec681f3Smrgvoid 2177ec681f3Smrgpandecode_close(void) 2187ec681f3Smrg{ 2197ec681f3Smrg _mesa_hash_table_u64_destroy(mmap_table); 2207ec681f3Smrg util_dynarray_fini(&ro_mappings); 2217ec681f3Smrg pandecode_dump_file_close(); 2227ec681f3Smrg} 2237ec681f3Smrg 2247ec681f3Smrgvoid pandecode_abort_on_fault_v4(mali_ptr jc_gpu_va); 2257ec681f3Smrgvoid pandecode_abort_on_fault_v5(mali_ptr jc_gpu_va); 2267ec681f3Smrgvoid pandecode_abort_on_fault_v6(mali_ptr jc_gpu_va); 2277ec681f3Smrgvoid pandecode_abort_on_fault_v7(mali_ptr jc_gpu_va); 2287ec681f3Smrg 2297ec681f3Smrgvoid 2307ec681f3Smrgpandecode_abort_on_fault(mali_ptr jc_gpu_va, unsigned gpu_id) 2317ec681f3Smrg{ 2327ec681f3Smrg switch (pan_arch(gpu_id)) { 2337ec681f3Smrg case 4: pandecode_abort_on_fault_v4(jc_gpu_va); return; 2347ec681f3Smrg case 5: pandecode_abort_on_fault_v5(jc_gpu_va); return; 2357ec681f3Smrg case 6: pandecode_abort_on_fault_v6(jc_gpu_va); return; 2367ec681f3Smrg case 7: pandecode_abort_on_fault_v7(jc_gpu_va); return; 2377ec681f3Smrg default: unreachable("Unsupported architecture"); 2387ec681f3Smrg } 2397ec681f3Smrg} 2407ec681f3Smrg 2417ec681f3Smrgvoid pandecode_jc_v4(mali_ptr jc_gpu_va, unsigned gpu_id); 2427ec681f3Smrgvoid pandecode_jc_v5(mali_ptr jc_gpu_va, unsigned gpu_id); 2437ec681f3Smrgvoid pandecode_jc_v6(mali_ptr jc_gpu_va, unsigned gpu_id); 2447ec681f3Smrgvoid pandecode_jc_v7(mali_ptr jc_gpu_va, unsigned gpu_id); 2457ec681f3Smrg 2467ec681f3Smrgvoid 2477ec681f3Smrgpandecode_jc(mali_ptr jc_gpu_va, unsigned gpu_id) 2487ec681f3Smrg{ 2497ec681f3Smrg switch (pan_arch(gpu_id)) { 2507ec681f3Smrg case 4: pandecode_jc_v4(jc_gpu_va, gpu_id); return; 2517ec681f3Smrg case 5: pandecode_jc_v5(jc_gpu_va, gpu_id); return; 2527ec681f3Smrg case 6: pandecode_jc_v6(jc_gpu_va, gpu_id); return; 2537ec681f3Smrg case 7: pandecode_jc_v7(jc_gpu_va, gpu_id); return; 2547ec681f3Smrg default: unreachable("Unsupported architecture"); 2557ec681f3Smrg } 2567ec681f3Smrg} 257