diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2013-09-11 09:06:48 +0200 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2013-09-11 09:06:48 +0200 |
commit | bf09dc9587232ac7ed69a05bf725cfaeb7eeaa34 (patch) | |
tree | a90c4b2cdf67839540223c5ffe507df0117650aa | |
parent | f688359ba004407d918177c149cbee3d9be7b209 (diff) |
utils: move utilities such as viv_gpu_top to separate directory
Split them off from fb and replay, where they don't belong.
Some of these are useful beyond reverse engineering.
Also add a few utilities not part of etna_viv before:
- viv_registers: print contents of all (non-crashing on read) GPU registers
- viv_watch: watch debug registers
-rw-r--r-- | native/Makefile | 2 | ||||
-rw-r--r-- | native/README.md | 2 | ||||
-rw-r--r-- | native/fb/Makefile | 2 | ||||
-rw-r--r-- | native/replay/Makefile | 2 | ||||
-rw-r--r-- | native/replay/reset.c | 29 | ||||
-rw-r--r-- | native/utils/.gitignore | 5 | ||||
-rw-r--r-- | native/utils/Makefile | 40 | ||||
-rw-r--r-- | native/utils/viv_gpu_top.c (renamed from native/fb/viv_gpu_top.c) | 0 | ||||
-rw-r--r-- | native/utils/viv_info.c (renamed from native/replay/viv_info.c) | 0 | ||||
-rw-r--r-- | native/utils/viv_registers.c | 86 | ||||
-rw-r--r-- | native/utils/viv_reset.c | 56 | ||||
-rw-r--r-- | native/utils/viv_watch.c | 172 |
12 files changed, 364 insertions, 32 deletions
diff --git a/native/Makefile b/native/Makefile index 2c66f0f..4bcc7b2 100644 --- a/native/Makefile +++ b/native/Makefile @@ -2,7 +2,7 @@ TOP=. include $(TOP)/Makefile.inc -DIRS=gallium etnaviv driver fb fb_rawshader replay test2d +DIRS=gallium etnaviv driver fb fb_rawshader replay test2d utils # only needed for reverse engineering/dumping # this needs a current EGL+OpenGL ES2 driver diff --git a/native/README.md b/native/README.md index 648ddef..134400e 100644 --- a/native/README.md +++ b/native/README.md @@ -25,3 +25,5 @@ Directory contents - `test2d`: 2D engine tests +- `util`: Various utilities for developing, debugging and profiling for Vivante GPUS + diff --git a/native/fb/Makefile b/native/fb/Makefile index 050c325..b3e6afa 100644 --- a/native/fb/Makefile +++ b/native/fb/Makefile @@ -8,7 +8,7 @@ CXXFLAGS += LDFLAGS += TARGETS = rotate_cube alpha_blend cube_companion cubemap_sphere particle_system etna_gears stencil_test displacement mip_cube viv_profile ps_sandbox \ - viv_gpu_top downsample_test + downsample_test COMPANION_OBJS = ../resources/companion_array.o ../resources/companion_mesh.o ../resources/companion_texture.o ETNA_OBJS = ../lib/fbdemos.o ../lib/etna_bswap.o ../driver/libetnadriver.a ../gallium/libminigallium.a ../etnaviv/libetnaviv.a diff --git a/native/replay/Makefile b/native/replay/Makefile index 317e014..d3c5f4c 100644 --- a/native/replay/Makefile +++ b/native/replay/Makefile @@ -5,7 +5,7 @@ include $(TOP)/Makefile.inc COMMON_FLAGS += -I$(TOP)/resources -I$(TOP)/driver LDFLAGS_ETNA = $(LDFLAGS) -L$(TOP)/etnaviv -letnaviv -TARGETS = reset viv_info +TARGETS = TARGETS_GC800 = cube cube_companion cube_etna ps_sandbox_etna etna_test cube_etna2 TARGETS_GC2000 = cube_etna2_gc2000 empty_screen_gc2000 cube_gc2000 cube_companion_gc2000 cube_etna_gc2000 COMPANION_OBJS = ../resources/companion_array.o ../resources/companion_mesh.o ../resources/companion_texture.o diff --git a/native/replay/reset.c b/native/replay/reset.c deleted file mode 100644 index 3b40fff..0000000 --- a/native/replay/reset.c +++ /dev/null @@ -1,29 +0,0 @@ -/* Reset GPU, useful in case it hangs */ -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdbool.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <stdarg.h> - -#include "viv_raw.h" - -int main(int argc, char **argv) -{ - int rv; - struct viv_conn *conn = 0; - rv = viv_open(VIV_HW_3D, &conn); - if(rv!=0) - { - fprintf(stderr, "Error opening device\n"); - exit(1); - } - printf("Succesfully opened device, resetting\n"); - viv_reset(conn); - viv_close(conn); - return 0; -} - diff --git a/native/utils/.gitignore b/native/utils/.gitignore new file mode 100644 index 0000000..9b4cc5e --- /dev/null +++ b/native/utils/.gitignore @@ -0,0 +1,5 @@ +viv_gpu_top +viv_info +viv_registers +viv_reset +viv_watch diff --git a/native/utils/Makefile b/native/utils/Makefile new file mode 100644 index 0000000..1ac3604 --- /dev/null +++ b/native/utils/Makefile @@ -0,0 +1,40 @@ +TOP=.. + +include $(TOP)/Makefile.inc + +COMMON_FLAGS += +CFLAGS += +CXXFLAGS += +LDFLAGS += + +ifeq ($(ETNAVIV_PROFILER), 1) +# Define ETNAVIV_PROFILER=1 if the kernel was built with VIVANTE_PROFILER +# enabled +COMMON_FLAGS += -DVIVANTE_PROFILER=1 +endif + +TARGETS = viv_gpu_top viv_info viv_registers viv_reset viv_watch + +ETNA_OBJS = ../etnaviv/libetnaviv.a + +all: $(TARGETS) + +clean: + rm -f *.o ../lib/*.o ../resources/*.o + rm -f $(TARGETS) + +viv_gpu_top: viv_gpu_top.o $(ETNA_OBJS) + $(CXX) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +viv_info: viv_info.o $(ETNA_OBJS) + $(CXX) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +viv_registers: viv_registers.o $(ETNA_OBJS) + $(CXX) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +viv_reset: viv_reset.o $(ETNA_OBJS) + $(CXX) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +viv_watch: viv_watch.o $(ETNA_OBJS) + $(CXX) $(CFLAGS) -o $@ $^ $(LDFLAGS) + diff --git a/native/fb/viv_gpu_top.c b/native/utils/viv_gpu_top.c index 97ee3a6..97ee3a6 100644 --- a/native/fb/viv_gpu_top.c +++ b/native/utils/viv_gpu_top.c diff --git a/native/replay/viv_info.c b/native/utils/viv_info.c index 9f1cf37..9f1cf37 100644 --- a/native/replay/viv_info.c +++ b/native/utils/viv_info.c diff --git a/native/utils/viv_registers.c b/native/utils/viv_registers.c new file mode 100644 index 0000000..2e295e9 --- /dev/null +++ b/native/utils/viv_registers.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2012-2013 Etnaviv Project + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* Dump all reachable GPU registers */ +/* + * Important: Needs kernel module compiled with user space register access + * (gcdREGISTER_ACCESS_FROM_USER=1) + */ +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> + +#include <etnaviv/viv.h> +#include "gc_hal_base.h" +#include "gc_hal.h" +#include "gc_hal_driver.h" +#include "gc_abi.h" + +int main() +{ + struct viv_conn *conn = 0; + int rv = 0; + rv = viv_open(VIV_HW_3D, &conn); + if(rv!=0) + { + fprintf(stderr, "Error opening device\n"); + exit(1); + } + + gcsHAL_INTERFACE id = {}; + memset((void*)&id, 0, sizeof(id)); + + // 0x000..0x200 ok + // 0x200..0x400 crash + // 0x400..0x800 ok + // 0x800..0xa00 crash + // 0xa00..0xc00 crash + // 0xc00..0xe00 crash + // 0xe00..0x1000 crash + // everything above that I've tested: crash + for(int address=0x000; address<0x800; address+=4) + { + if(address >= 0x200 && address < 0x400) + continue; /* reading causes CPU(!) crash */ + id.command = gcvHAL_READ_REGISTER; + id.u.ReadRegisterData.address = address; + if(viv_invoke(conn, &id) != VIV_STATUS_OK) + { + perror("Ioctl error"); + exit(1); + } + printf("%05x %08x\n", address, id.u.ReadRegisterData.data); + fflush(stdout); + } + + viv_close(conn); + return 0; +} + diff --git a/native/utils/viv_reset.c b/native/utils/viv_reset.c new file mode 100644 index 0000000..0d7c6a2 --- /dev/null +++ b/native/utils/viv_reset.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012-2013 Etnaviv Project + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* Reset GPU, useful in case it hangs. + */ +/* + * Note: this is known to be unreliable with many kernel drivers and can bring + * the GPU in a state that can only be recovered with a device reboot. + */ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <stdarg.h> + +#include <etnaviv/viv.h> + +int main(int argc, char **argv) +{ + int rv; + struct viv_conn *conn = 0; + rv = viv_open(VIV_HW_3D, &conn); + if(rv!=0) + { + fprintf(stderr, "Error opening device\n"); + exit(1); + } + printf("Succesfully opened device, resetting\n"); + viv_reset(conn); + viv_close(conn); + return 0; +} + diff --git a/native/utils/viv_watch.c b/native/utils/viv_watch.c new file mode 100644 index 0000000..9a12d39 --- /dev/null +++ b/native/utils/viv_watch.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2012-2013 Etnaviv Project + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* Watch GPU debug registers */ +/* Important: Needs kernel module compiled with user space register access + * (gcdREGISTER_ACCESS_FROM_USER=1) */ +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> + +#include <etnaviv/viv.h> +#include "gc_hal_base.h" +#include "gc_hal.h" +#include "gc_hal_driver.h" +#include "gc_abi.h" + +struct viv_conn *conn = 0; + +static const char clear_screen[] = {0x1b, '[', 'H', + 0x1b, '[', 'J', + 0x0}; +static const char color_num_zero[] = "\x1b[1;30m"; +static const char color_num[] = "\x1b[1;33m"; +static const char color_reset[] = "\x1b[0m"; + +static void write_register(uint32_t address, uint32_t data) +{ + gcsHAL_INTERFACE id; + id.command = gcvHAL_WRITE_REGISTER; + id.u.WriteRegisterData.address = address; + id.u.WriteRegisterData.data = data; + if(viv_invoke(conn, &id) != VIV_STATUS_OK) + { + perror("Ioctl error"); + exit(1); + } +} + +static uint32_t read_register(uint32_t address) +{ + gcsHAL_INTERFACE id; + id.command = gcvHAL_READ_REGISTER; + id.u.ReadRegisterData.address = address; + if(viv_invoke(conn, &id) != VIV_STATUS_OK) + { + perror("Ioctl error"); + exit(1); + } + return id.u.ReadRegisterData.data; +} + +struct debug_register +{ + const char *module; + uint32_t select_reg; + uint32_t select_shift; + uint32_t read_reg; + uint32_t count; + uint32_t signature; +}; + +/* XXX possible to select/clear four debug registers at a time? this would + * avoid writes. + */ +static struct debug_register debug_registers[] = +{ + { "RA", 0x474, 16, 0x448, 16, 0x12344321 }, + { "TX", 0x474, 24, 0x44C, 16, 0x12211221 }, + { "FE", 0x470, 0, 0x450, 16, 0xBABEF00D }, + { "PE", 0x470, 16, 0x454, 16, 0xBABEF00D }, + { "DE", 0x470, 8, 0x458, 16, 0xBABEF00D }, + { "SH", 0x470, 24, 0x45C, 16, 0xDEADBEEF }, + { "PA", 0x474, 0, 0x460, 16, 0x0000AAAA }, + { "SE", 0x474, 8, 0x464, 16, 0x5E5E5E5E }, + { "MC", 0x478, 0, 0x468, 16, 0x12345678 }, + { "HI", 0x478, 8, 0x46C, 16, 0xAAAAAAAA } +}; +#define NUM_MODULES (sizeof(debug_registers) / sizeof(struct debug_register)) +#define MAX_COUNT 16 + +int main() +{ + int rv = 0; + rv = viv_open(VIV_HW_3D, &conn); + if(rv!=0) + { + fprintf(stderr, "Error opening device\n"); + exit(1); + } + + uint32_t counters[NUM_MODULES][MAX_COUNT] = {{}}; + uint32_t counters_prev[NUM_MODULES][MAX_COUNT] = {{}}; + int interval = 1000000; + int reset = 0; /* reset counters after read */ + + int has_prev = 0; + while(true) + { + printf("%s", clear_screen); + for(unsigned int rid=0; rid<NUM_MODULES; ++rid) + { + struct debug_register *rdesc = &debug_registers[rid]; + for(unsigned int sid=0; sid<15; ++sid) + { + write_register(rdesc->select_reg, sid << rdesc->select_shift); + counters[rid][sid] = read_register(rdesc->read_reg); + } + if(reset) + { + write_register(rdesc->select_reg, 15 << rdesc->select_shift); + counters[rid][15] = read_register(rdesc->read_reg); + } + write_register(debug_registers[rid].select_reg, 0 << rdesc->select_shift); + } + + printf(" "); + for(unsigned int rid=0; rid<NUM_MODULES; ++rid) + { + printf("%-8s ", debug_registers[rid].module); + } + printf("\n"); + for(unsigned int sid=0; sid<MAX_COUNT ; ++sid) + { + printf("%01x ", sid); + for(unsigned int rid=0; rid<NUM_MODULES; ++rid) + { + const char *color = ""; + if(has_prev && counters[rid][sid] != counters_prev[rid][sid]) + color = color_num; + printf("%s%08x%s ", color, counters[rid][sid], color_reset); + } + printf("\n"); + } + usleep(interval); + + for(unsigned int rid=0; rid<NUM_MODULES; ++rid) + for(unsigned int sid=0; sid<MAX_COUNT; ++sid) + counters_prev[rid][sid] = counters[rid][sid]; + has_prev = 1; + } + + viv_close(conn); + return 0; +} + |