• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/simple_mtx.h"
38 
39 FILE *pandecode_dump_stream;
40 
41 /* Memory handling */
42 
43 static struct rb_tree mmap_tree;
44 
45 static struct util_dynarray ro_mappings;
46 
47 static simple_mtx_t pandecode_lock = _SIMPLE_MTX_INITIALIZER_NP;
48 
49 #define to_mapped_memory(x) \
50 	rb_node_data(struct pandecode_mapped_memory, x, node)
51 
52 /*
53  * Compare a GPU VA to a node, considering a GPU VA to be equal to a node if it
54  * is contained in the interval the node represents. This lets us store
55  * intervals in our tree.
56  */
57 static int
pandecode_cmp_key(const struct rb_node * lhs,const void * key)58 pandecode_cmp_key(const struct rb_node *lhs, const void *key)
59 {
60         struct pandecode_mapped_memory *mem = to_mapped_memory(lhs);
61         uint64_t *gpu_va = (uint64_t *) key;
62 
63         if (mem->gpu_va <= *gpu_va && *gpu_va < (mem->gpu_va + mem->length))
64                 return 0;
65         else
66                 return mem->gpu_va - *gpu_va;
67 }
68 
69 static int
pandecode_cmp(const struct rb_node * lhs,const struct rb_node * rhs)70 pandecode_cmp(const struct rb_node *lhs, const struct rb_node *rhs)
71 {
72         return to_mapped_memory(lhs)->gpu_va - to_mapped_memory(rhs)->gpu_va;
73 }
74 
75 static struct pandecode_mapped_memory *
pandecode_find_mapped_gpu_mem_containing_rw(uint64_t addr)76 pandecode_find_mapped_gpu_mem_containing_rw(uint64_t addr)
77 {
78         simple_mtx_assert_locked(&pandecode_lock);
79 
80         struct rb_node *node = rb_tree_search(&mmap_tree, &addr, pandecode_cmp_key);
81 
82         return to_mapped_memory(node);
83 }
84 
85 struct pandecode_mapped_memory *
pandecode_find_mapped_gpu_mem_containing(uint64_t addr)86 pandecode_find_mapped_gpu_mem_containing(uint64_t addr)
87 {
88         simple_mtx_assert_locked(&pandecode_lock);
89 
90         struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing_rw(addr);
91 
92         if (mem && mem->addr && !mem->ro) {
93                 mprotect(mem->addr, mem->length, PROT_READ);
94                 mem->ro = true;
95                 util_dynarray_append(&ro_mappings, struct pandecode_mapped_memory *, mem);
96         }
97 
98         return mem;
99 }
100 
101 void
pandecode_map_read_write(void)102 pandecode_map_read_write(void)
103 {
104         simple_mtx_assert_locked(&pandecode_lock);
105 
106         util_dynarray_foreach(&ro_mappings, struct pandecode_mapped_memory *, mem) {
107                 (*mem)->ro = false;
108                 mprotect((*mem)->addr, (*mem)->length, PROT_READ | PROT_WRITE);
109         }
110         util_dynarray_clear(&ro_mappings);
111 }
112 
113 static void
pandecode_add_name(struct pandecode_mapped_memory * mem,uint64_t gpu_va,const char * name)114 pandecode_add_name(struct pandecode_mapped_memory *mem, uint64_t gpu_va, const char *name)
115 {
116         simple_mtx_assert_locked(&pandecode_lock);
117 
118         if (!name) {
119                 /* If we don't have a name, assign one */
120 
121                 snprintf(mem->name, sizeof(mem->name) - 1,
122                          "memory_%" PRIx64, gpu_va);
123         } else {
124                 assert((strlen(name) + 1) < sizeof(mem->name));
125                 memcpy(mem->name, name, strlen(name) + 1);
126         }
127 }
128 
129 void
pandecode_inject_mmap(uint64_t gpu_va,void * cpu,unsigned sz,const char * name)130 pandecode_inject_mmap(uint64_t gpu_va, void *cpu, unsigned sz, const char *name)
131 {
132         simple_mtx_lock(&pandecode_lock);
133 
134         /* First, search if we already mapped this and are just updating an address */
135 
136         struct pandecode_mapped_memory *existing =
137                 pandecode_find_mapped_gpu_mem_containing_rw(gpu_va);
138 
139         if (existing && existing->gpu_va == gpu_va) {
140                 existing->length = sz;
141                 existing->addr = cpu;
142                 pandecode_add_name(existing, gpu_va, name);
143         } else {
144                 /* Otherwise, add a fresh mapping */
145                 struct pandecode_mapped_memory *mapped_mem = NULL;
146 
147                 mapped_mem = calloc(1, sizeof(*mapped_mem));
148                 mapped_mem->gpu_va = gpu_va;
149                 mapped_mem->length = sz;
150                 mapped_mem->addr = cpu;
151                 pandecode_add_name(mapped_mem, gpu_va, name);
152 
153                 /* Add it to the tree */
154                 rb_tree_insert(&mmap_tree, &mapped_mem->node, pandecode_cmp);
155         }
156 
157         simple_mtx_unlock(&pandecode_lock);
158 }
159 
160 void
pandecode_inject_free(uint64_t gpu_va,unsigned sz)161 pandecode_inject_free(uint64_t gpu_va, unsigned sz)
162 {
163         simple_mtx_lock(&pandecode_lock);
164 
165         struct pandecode_mapped_memory *mem =
166                 pandecode_find_mapped_gpu_mem_containing_rw(gpu_va);
167 
168         if (mem) {
169                 assert(mem->gpu_va == gpu_va);
170                 assert(mem->length == sz);
171 
172                 rb_tree_remove(&mmap_tree, &mem->node);
173                 free(mem);
174         }
175 
176         simple_mtx_unlock(&pandecode_lock);
177 }
178 
179 char *
pointer_as_memory_reference(uint64_t ptr)180 pointer_as_memory_reference(uint64_t ptr)
181 {
182         simple_mtx_assert_locked(&pandecode_lock);
183 
184         struct pandecode_mapped_memory *mapped;
185         char *out = malloc(128);
186 
187         /* Try to find the corresponding mapped zone */
188 
189         mapped = pandecode_find_mapped_gpu_mem_containing_rw(ptr);
190 
191         if (mapped) {
192                 snprintf(out, 128, "%s + %d", mapped->name, (int) (ptr - mapped->gpu_va));
193                 return out;
194         }
195 
196         /* Just use the raw address if other options are exhausted */
197 
198         snprintf(out, 128, "0x%" PRIx64, ptr);
199         return out;
200 
201 }
202 
203 static int pandecode_dump_frame_count = 0;
204 
205 static bool force_stderr = false;
206 
207 void
pandecode_dump_file_open(void)208 pandecode_dump_file_open(void)
209 {
210         simple_mtx_assert_locked(&pandecode_lock);
211 
212         if (pandecode_dump_stream)
213                 return;
214 
215         /* This does a getenv every frame, so it is possible to use
216          * setenv to change the base at runtime.
217          */
218         const char *dump_file_base = debug_get_option("PANDECODE_DUMP_FILE", "pandecode.dump");
219         if (force_stderr || !strcmp(dump_file_base, "stderr"))
220                 pandecode_dump_stream = stderr;
221         else {
222                 char buffer[1024];
223                 snprintf(buffer, sizeof(buffer), "%s.%04d", dump_file_base, pandecode_dump_frame_count);
224                 printf("pandecode: dump command stream to file %s\n", buffer);
225                 pandecode_dump_stream = fopen(buffer, "w");
226                 if (!pandecode_dump_stream)
227                         fprintf(stderr,
228                                 "pandecode: failed to open command stream log file %s\n",
229                                 buffer);
230         }
231 }
232 
233 static void
pandecode_dump_file_close(void)234 pandecode_dump_file_close(void)
235 {
236         simple_mtx_assert_locked(&pandecode_lock);
237 
238         if (pandecode_dump_stream && pandecode_dump_stream != stderr) {
239                 if (fclose(pandecode_dump_stream))
240                         perror("pandecode: dump file");
241 
242                 pandecode_dump_stream = NULL;
243         }
244 }
245 
246 void
pandecode_initialize(bool to_stderr)247 pandecode_initialize(bool to_stderr)
248 {
249         force_stderr = to_stderr;
250         rb_tree_init(&mmap_tree);
251         util_dynarray_init(&ro_mappings, NULL);
252 }
253 
254 void
pandecode_next_frame(void)255 pandecode_next_frame(void)
256 {
257         simple_mtx_lock(&pandecode_lock);
258 
259         pandecode_dump_file_close();
260         pandecode_dump_frame_count++;
261 
262         simple_mtx_unlock(&pandecode_lock);
263 }
264 
265 void
pandecode_close(void)266 pandecode_close(void)
267 {
268         simple_mtx_lock(&pandecode_lock);
269 
270         rb_tree_foreach_safe(struct pandecode_mapped_memory, it, &mmap_tree, node) {
271                 rb_tree_remove(&mmap_tree, &it->node);
272                 free(it);
273         }
274 
275         util_dynarray_fini(&ro_mappings);
276         pandecode_dump_file_close();
277 
278         simple_mtx_unlock(&pandecode_lock);
279 }
280 
281 void
pandecode_dump_mappings(void)282 pandecode_dump_mappings(void)
283 {
284         simple_mtx_lock(&pandecode_lock);
285 
286         pandecode_dump_file_open();
287 
288         rb_tree_foreach(struct pandecode_mapped_memory, it, &mmap_tree, node) {
289                 if (!it->addr || !it->length)
290                         continue;
291 
292                 fprintf(pandecode_dump_stream, "Buffer: %s gpu %" PRIx64 "\n\n",
293                         it->name, it->gpu_va);
294 
295                 pan_hexdump(pandecode_dump_stream, it->addr, it->length, false);
296                 fprintf(pandecode_dump_stream, "\n");
297         }
298 
299         fflush(pandecode_dump_stream);
300         simple_mtx_unlock(&pandecode_lock);
301 }
302 
303 void pandecode_abort_on_fault_v4(mali_ptr jc_gpu_va);
304 void pandecode_abort_on_fault_v5(mali_ptr jc_gpu_va);
305 void pandecode_abort_on_fault_v6(mali_ptr jc_gpu_va);
306 void pandecode_abort_on_fault_v7(mali_ptr jc_gpu_va);
307 void pandecode_abort_on_fault_v9(mali_ptr jc_gpu_va);
308 
309 void
pandecode_abort_on_fault(mali_ptr jc_gpu_va,unsigned gpu_id)310 pandecode_abort_on_fault(mali_ptr jc_gpu_va, unsigned gpu_id)
311 {
312         simple_mtx_lock(&pandecode_lock);
313 
314         switch (pan_arch(gpu_id)) {
315         case 4: pandecode_abort_on_fault_v4(jc_gpu_va); break;
316         case 5: pandecode_abort_on_fault_v5(jc_gpu_va); break;
317         case 6: pandecode_abort_on_fault_v6(jc_gpu_va); break;
318         case 7: pandecode_abort_on_fault_v7(jc_gpu_va); break;
319         case 9: pandecode_abort_on_fault_v9(jc_gpu_va); break;
320         default: unreachable("Unsupported architecture");
321         }
322 
323         simple_mtx_unlock(&pandecode_lock);
324 }
325 
326 void pandecode_jc_v4(mali_ptr jc_gpu_va, unsigned gpu_id);
327 void pandecode_jc_v5(mali_ptr jc_gpu_va, unsigned gpu_id);
328 void pandecode_jc_v6(mali_ptr jc_gpu_va, unsigned gpu_id);
329 void pandecode_jc_v7(mali_ptr jc_gpu_va, unsigned gpu_id);
330 void pandecode_jc_v9(mali_ptr jc_gpu_va, unsigned gpu_id);
331 
332 void
pandecode_jc(mali_ptr jc_gpu_va,unsigned gpu_id)333 pandecode_jc(mali_ptr jc_gpu_va, unsigned gpu_id)
334 {
335         simple_mtx_lock(&pandecode_lock);
336 
337         switch (pan_arch(gpu_id)) {
338         case 4: pandecode_jc_v4(jc_gpu_va, gpu_id); break;
339         case 5: pandecode_jc_v5(jc_gpu_va, gpu_id); break;
340         case 6: pandecode_jc_v6(jc_gpu_va, gpu_id); break;
341         case 7: pandecode_jc_v7(jc_gpu_va, gpu_id); break;
342         case 9: pandecode_jc_v9(jc_gpu_va, gpu_id); break;
343         default: unreachable("Unsupported architecture");
344         }
345 
346         simple_mtx_unlock(&pandecode_lock);
347 }
348