Path: blob/21.2-virgl/src/panfrost/lib/decode_common.c
4560 views
/*1* Copyright (C) 2019 Alyssa Rosenzweig2* Copyright (C) 2017-2018 Lyude Paul3* Copyright (C) 2019 Collabora, Ltd.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the "Software"),7* to deal in the Software without restriction, including without limitation8* the rights to use, copy, modify, merge, publish, distribute, sublicense,9* and/or sell copies of the Software, and to permit persons to whom the10* Software is furnished to do so, subject to the following conditions:11*12* The above copyright notice and this permission notice (including the next13* paragraph) shall be included in all copies or substantial portions of the14* Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR17* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL19* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER20* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,21* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE22* SOFTWARE.23*/2425#include <stdio.h>26#include <stdlib.h>27#include <assert.h>28#include <stdint.h>29#include <string.h>30#include <sys/mman.h>3132#include "decode.h"33#include "util/macros.h"34#include "util/u_debug.h"35#include "util/u_dynarray.h"36#include "util/hash_table.h"3738/* Memory handling */3940static struct hash_table_u64 *mmap_table;4142static struct util_dynarray ro_mappings;4344static struct pandecode_mapped_memory *45pandecode_find_mapped_gpu_mem_containing_rw(uint64_t addr)46{47return _mesa_hash_table_u64_search(mmap_table, addr & ~(4096 - 1));48}4950struct pandecode_mapped_memory *51pandecode_find_mapped_gpu_mem_containing(uint64_t addr)52{53struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing_rw(addr);5455if (mem && mem->addr && !mem->ro) {56mprotect(mem->addr, mem->length, PROT_READ);57mem->ro = true;58util_dynarray_append(&ro_mappings, struct pandecode_mapped_memory *, mem);59}6061return mem;62}6364void65pandecode_map_read_write(void)66{67util_dynarray_foreach(&ro_mappings, struct pandecode_mapped_memory *, mem) {68(*mem)->ro = false;69mprotect((*mem)->addr, (*mem)->length, PROT_READ | PROT_WRITE);70}71util_dynarray_clear(&ro_mappings);72}7374static void75pandecode_add_name(struct pandecode_mapped_memory *mem, uint64_t gpu_va, const char *name)76{77if (!name) {78/* If we don't have a name, assign one */7980snprintf(mem->name, sizeof(mem->name) - 1,81"memory_%" PRIx64, gpu_va);82} else {83assert((strlen(name) + 1) < sizeof(mem->name));84memcpy(mem->name, name, strlen(name) + 1);85}86}8788void89pandecode_inject_mmap(uint64_t gpu_va, void *cpu, unsigned sz, const char *name)90{91/* First, search if we already mapped this and are just updating an address */9293struct pandecode_mapped_memory *existing =94pandecode_find_mapped_gpu_mem_containing_rw(gpu_va);9596if (existing && existing->gpu_va == gpu_va) {97existing->length = sz;98existing->addr = cpu;99pandecode_add_name(existing, gpu_va, name);100return;101}102103/* Otherwise, add a fresh mapping */104struct pandecode_mapped_memory *mapped_mem = NULL;105106mapped_mem = calloc(1, sizeof(*mapped_mem));107mapped_mem->gpu_va = gpu_va;108mapped_mem->length = sz;109mapped_mem->addr = cpu;110pandecode_add_name(mapped_mem, gpu_va, name);111112/* Add it to the table */113assert((gpu_va & 4095) == 0);114115for (unsigned i = 0; i < sz; i += 4096)116_mesa_hash_table_u64_insert(mmap_table, gpu_va + i, mapped_mem);117}118119void120pandecode_inject_free(uint64_t gpu_va, unsigned sz)121{122struct pandecode_mapped_memory *mem =123pandecode_find_mapped_gpu_mem_containing_rw(gpu_va);124125if (!mem)126return;127128assert(mem->gpu_va == gpu_va);129assert(mem->length == sz);130131free(mem);132133for (unsigned i = 0; i < sz; i += 4096)134_mesa_hash_table_u64_remove(mmap_table, gpu_va + i);135}136137char *138pointer_as_memory_reference(uint64_t ptr)139{140struct pandecode_mapped_memory *mapped;141char *out = malloc(128);142143/* Try to find the corresponding mapped zone */144145mapped = pandecode_find_mapped_gpu_mem_containing_rw(ptr);146147if (mapped) {148snprintf(out, 128, "%s + %d", mapped->name, (int) (ptr - mapped->gpu_va));149return out;150}151152/* Just use the raw address if other options are exhausted */153154snprintf(out, 128, "0x%" PRIx64, ptr);155return out;156157}158159static int pandecode_dump_frame_count = 0;160161static bool force_stderr = false;162163void164pandecode_dump_file_open(void)165{166if (pandecode_dump_stream)167return;168169/* This does a getenv every frame, so it is possible to use170* setenv to change the base at runtime.171*/172const char *dump_file_base = debug_get_option("PANDECODE_DUMP_FILE", "pandecode.dump");173if (force_stderr || !strcmp(dump_file_base, "stderr"))174pandecode_dump_stream = stderr;175else {176char buffer[1024];177snprintf(buffer, sizeof(buffer), "%s.%04d", dump_file_base, pandecode_dump_frame_count);178printf("pandecode: dump command stream to file %s\n", buffer);179pandecode_dump_stream = fopen(buffer, "w");180if (!pandecode_dump_stream)181fprintf(stderr,182"pandecode: failed to open command stream log file %s\n",183buffer);184}185}186187static void188pandecode_dump_file_close(void)189{190if (pandecode_dump_stream && pandecode_dump_stream != stderr) {191if (fclose(pandecode_dump_stream))192perror("pandecode: dump file");193194pandecode_dump_stream = NULL;195}196}197198void199pandecode_initialize(bool to_stderr)200{201force_stderr = to_stderr;202mmap_table = _mesa_hash_table_u64_create(NULL);203util_dynarray_init(&ro_mappings, NULL);204}205206void207pandecode_next_frame(void)208{209pandecode_dump_file_close();210pandecode_dump_frame_count++;211}212213void214pandecode_close(void)215{216_mesa_hash_table_u64_destroy(mmap_table);217util_dynarray_fini(&ro_mappings);218pandecode_dump_file_close();219}220221222