Home | History | Annotate | Line # | Download | only in genxml
      1 /*
      2  * Copyright (C) 2019 Alyssa Rosenzweig
      3  * Copyright (C) 2017-2018 Lyude Paul
      4  * Copyright (C) 2019 Collabora, Ltd.
      5  *
      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:
     12  *
     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.
     16  *
     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 OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23  * SOFTWARE.
     24  */
     25 
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <assert.h>
     29 #include <stdint.h>
     30 #include <string.h>
     31 #include <sys/mman.h>
     32 
     33 #include "decode.h"
     34 #include "util/macros.h"
     35 #include "util/u_debug.h"
     36 #include "util/u_dynarray.h"
     37 #include "util/hash_table.h"
     38 
     39 FILE *pandecode_dump_stream;
     40 
     41 /* Memory handling */
     42 
     43 static struct hash_table_u64 *mmap_table;
     44 
     45 static struct util_dynarray ro_mappings;
     46 
     47 static struct pandecode_mapped_memory *
     48 pandecode_find_mapped_gpu_mem_containing_rw(uint64_t addr)
     49 {
     50         return _mesa_hash_table_u64_search(mmap_table, addr & ~(4096 - 1));
     51 }
     52 
     53 struct pandecode_mapped_memory *
     54 pandecode_find_mapped_gpu_mem_containing(uint64_t addr)
     55 {
     56         struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing_rw(addr);
     57 
     58         if (mem && mem->addr && !mem->ro) {
     59                 mprotect(mem->addr, mem->length, PROT_READ);
     60                 mem->ro = true;
     61                 util_dynarray_append(&ro_mappings, struct pandecode_mapped_memory *, mem);
     62         }
     63 
     64         return mem;
     65 }
     66 
     67 void
     68 pandecode_map_read_write(void)
     69 {
     70         util_dynarray_foreach(&ro_mappings, struct pandecode_mapped_memory *, mem) {
     71                 (*mem)->ro = false;
     72                 mprotect((*mem)->addr, (*mem)->length, PROT_READ | PROT_WRITE);
     73         }
     74         util_dynarray_clear(&ro_mappings);
     75 }
     76 
     77 static void
     78 pandecode_add_name(struct pandecode_mapped_memory *mem, uint64_t gpu_va, const char *name)
     79 {
     80         if (!name) {
     81                 /* If we don't have a name, assign one */
     82 
     83                 snprintf(mem->name, sizeof(mem->name) - 1,
     84                          "memory_%" PRIx64, gpu_va);
     85         } else {
     86                 assert((strlen(name) + 1) < sizeof(mem->name));
     87                 memcpy(mem->name, name, strlen(name) + 1);
     88         }
     89 }
     90 
     91 void
     92 pandecode_inject_mmap(uint64_t gpu_va, void *cpu, unsigned sz, const char *name)
     93 {
     94         /* First, search if we already mapped this and are just updating an address */
     95 
     96         struct pandecode_mapped_memory *existing =
     97                 pandecode_find_mapped_gpu_mem_containing_rw(gpu_va);
     98 
     99         if (existing && existing->gpu_va == gpu_va) {
    100                 existing->length = sz;
    101                 existing->addr = cpu;
    102                 pandecode_add_name(existing, gpu_va, name);
    103                 return;
    104         }
    105 
    106         /* Otherwise, add a fresh mapping */
    107         struct pandecode_mapped_memory *mapped_mem = NULL;
    108 
    109         mapped_mem = calloc(1, sizeof(*mapped_mem));
    110         mapped_mem->gpu_va = gpu_va;
    111         mapped_mem->length = sz;
    112         mapped_mem->addr = cpu;
    113         pandecode_add_name(mapped_mem, gpu_va, name);
    114 
    115         /* Add it to the table */
    116         assert((gpu_va & 4095) == 0);
    117 
    118         for (unsigned i = 0; i < sz; i += 4096)
    119                 _mesa_hash_table_u64_insert(mmap_table, gpu_va + i, mapped_mem);
    120 }
    121 
    122 void
    123 pandecode_inject_free(uint64_t gpu_va, unsigned sz)
    124 {
    125         struct pandecode_mapped_memory *mem =
    126                 pandecode_find_mapped_gpu_mem_containing_rw(gpu_va);
    127 
    128         if (!mem)
    129                 return;
    130 
    131         assert(mem->gpu_va == gpu_va);
    132         assert(mem->length == sz);
    133 
    134         free(mem);
    135 
    136         for (unsigned i = 0; i < sz; i += 4096)
    137                 _mesa_hash_table_u64_remove(mmap_table, gpu_va + i);
    138 }
    139 
    140 char *
    141 pointer_as_memory_reference(uint64_t ptr)
    142 {
    143         struct pandecode_mapped_memory *mapped;
    144         char *out = malloc(128);
    145 
    146         /* Try to find the corresponding mapped zone */
    147 
    148         mapped = pandecode_find_mapped_gpu_mem_containing_rw(ptr);
    149 
    150         if (mapped) {
    151                 snprintf(out, 128, "%s + %d", mapped->name, (int) (ptr - mapped->gpu_va));
    152                 return out;
    153         }
    154 
    155         /* Just use the raw address if other options are exhausted */
    156 
    157         snprintf(out, 128, "0x%" PRIx64, ptr);
    158         return out;
    159 
    160 }
    161 
    162 static int pandecode_dump_frame_count = 0;
    163 
    164 static bool force_stderr = false;
    165 
    166 void
    167 pandecode_dump_file_open(void)
    168 {
    169         if (pandecode_dump_stream)
    170                 return;
    171 
    172         /* This does a getenv every frame, so it is possible to use
    173          * setenv to change the base at runtime.
    174          */
    175         const char *dump_file_base = debug_get_option("PANDECODE_DUMP_FILE", "pandecode.dump");
    176         if (force_stderr || !strcmp(dump_file_base, "stderr"))
    177                 pandecode_dump_stream = stderr;
    178         else {
    179                 char buffer[1024];
    180                 snprintf(buffer, sizeof(buffer), "%s.%04d", dump_file_base, pandecode_dump_frame_count);
    181                 printf("pandecode: dump command stream to file %s\n", buffer);
    182                 pandecode_dump_stream = fopen(buffer, "w");
    183                 if (!pandecode_dump_stream)
    184                         fprintf(stderr,
    185                                 "pandecode: failed to open command stream log file %s\n",
    186                                 buffer);
    187         }
    188 }
    189 
    190 static void
    191 pandecode_dump_file_close(void)
    192 {
    193         if (pandecode_dump_stream && pandecode_dump_stream != stderr) {
    194                 if (fclose(pandecode_dump_stream))
    195                         perror("pandecode: dump file");
    196 
    197                 pandecode_dump_stream = NULL;
    198         }
    199 }
    200 
    201 void
    202 pandecode_initialize(bool to_stderr)
    203 {
    204         force_stderr = to_stderr;
    205         mmap_table = _mesa_hash_table_u64_create(NULL);
    206         util_dynarray_init(&ro_mappings, NULL);
    207 }
    208 
    209 void
    210 pandecode_next_frame(void)
    211 {
    212         pandecode_dump_file_close();
    213         pandecode_dump_frame_count++;
    214 }
    215 
    216 void
    217 pandecode_close(void)
    218 {
    219         _mesa_hash_table_u64_destroy(mmap_table);
    220         util_dynarray_fini(&ro_mappings);
    221         pandecode_dump_file_close();
    222 }
    223 
    224 void pandecode_abort_on_fault_v4(mali_ptr jc_gpu_va);
    225 void pandecode_abort_on_fault_v5(mali_ptr jc_gpu_va);
    226 void pandecode_abort_on_fault_v6(mali_ptr jc_gpu_va);
    227 void pandecode_abort_on_fault_v7(mali_ptr jc_gpu_va);
    228 
    229 void
    230 pandecode_abort_on_fault(mali_ptr jc_gpu_va, unsigned gpu_id)
    231 {
    232         switch (pan_arch(gpu_id)) {
    233         case 4: pandecode_abort_on_fault_v4(jc_gpu_va); return;
    234         case 5: pandecode_abort_on_fault_v5(jc_gpu_va); return;
    235         case 6: pandecode_abort_on_fault_v6(jc_gpu_va); return;
    236         case 7: pandecode_abort_on_fault_v7(jc_gpu_va); return;
    237         default: unreachable("Unsupported architecture");
    238         }
    239 }
    240 
    241 void pandecode_jc_v4(mali_ptr jc_gpu_va, unsigned gpu_id);
    242 void pandecode_jc_v5(mali_ptr jc_gpu_va, unsigned gpu_id);
    243 void pandecode_jc_v6(mali_ptr jc_gpu_va, unsigned gpu_id);
    244 void pandecode_jc_v7(mali_ptr jc_gpu_va, unsigned gpu_id);
    245 
    246 void
    247 pandecode_jc(mali_ptr jc_gpu_va, unsigned gpu_id)
    248 {
    249         switch (pan_arch(gpu_id)) {
    250         case 4: pandecode_jc_v4(jc_gpu_va, gpu_id); return;
    251         case 5: pandecode_jc_v5(jc_gpu_va, gpu_id); return;
    252         case 6: pandecode_jc_v6(jc_gpu_va, gpu_id); return;
    253         case 7: pandecode_jc_v7(jc_gpu_va, gpu_id); return;
    254         default: unreachable("Unsupported architecture");
    255         }
    256 }
    257