In the process of reverse engineering work for freedreno, I've cobbled together some interesting tools. The earliest and most useful of which is cffdump. (Named after some command-stream dumping debug code in the old kgsl android kernel driver, upon which it was originally inspired.) The cffdump tool knows how to parse out the "toplevel" command-stream stored as an .rd (re-dump) file, finding packets that load state memory, write registers, IB (indirect branch), etc. The .rd file contains snapshots of gpu buffers, in order to chase gpu pointers at decode time. It links in librnn from the nouveau envytools project for the decoding of individual registers, and a few other things. It also calls out to the freedreno disassembler code to show inline disassembly of shaders, decodes vertex and constant (uniform) buffers, etc. And even generates pretty color output (thanks to librnn):
A few months back, I added some basic lua scripting support to cffdump, mostly to assist in r/e work for adreno a4xx. When invoked with the --script argument, cffdump would load the specific lua script, and call the 'draw' function it defines on each CP_DRAW_INDX opcode. The choice of lua was mostly because it seemed fairly easy to integrate with .c code.
Since then, I've had the thought in the back of my mind that adding script bindings to integrate rnn register decode to lua would be useful for much more. Such as writing a command-stream validator to check for inconsistent programming. There are a number of places where inconsistencies between various register settings and such will result in gpu lockup. The general adreno design philosophy appears to be to not ever dedicate transistors to making the driver writer's life easier... which for a SoC gpu is certainly the right choice, but it doesn't make things any easier for me. Over time, I've discovered many of these of these rules, but they are mostly all in my head at the moment. And from time to time, when adding new features to the gallium driver, I inadvertently break one or more of the rules and end up wasting time studying cmdstream dumps from the freedreno gallium driver to figure out what I did wrong.
So, on the way to XDC2014 I started hacking up support for register decoding from lua scripts. It turns out that time in airports and airplanes, where I can't exactly break out an ifc6410 and hdmi monitor to do some driver work, is a good time to catch up on these sort of projects. Now I can do nifty things like:
which will generate output like:
Currently it should handle all of the rnndb constructs that are used for adreno. Ie. simple registers, arrays of simple registers, arrays of groups of registers, etc. No support for "stripes" yet since those are not used for freedreno.
At the moment, all the script bindings are in freedreno.git/util/script.c but if there is some interest in this from nouveau or anyone else using librnn then it would be a good idea to try to refactor some of this into more generic code in librnn. It would still need a bit of glue from the tool linking librnn to get at the actual register values.
Still needed are a few more script hooks (such as CP_LOAD_STATE) to do everything I need for a validator script. Hopefully I find some time to work on that before the next conference ;-)
PS. I hope this post is at least a bit coherent.. I am still a bit jetlagged..
A few months back, I added some basic lua scripting support to cffdump, mostly to assist in r/e work for adreno a4xx. When invoked with the --script argument, cffdump would load the specific lua script, and call the 'draw' function it defines on each CP_DRAW_INDX opcode. The choice of lua was mostly because it seemed fairly easy to integrate with .c code.
Since then, I've had the thought in the back of my mind that adding script bindings to integrate rnn register decode to lua would be useful for much more. Such as writing a command-stream validator to check for inconsistent programming. There are a number of places where inconsistencies between various register settings and such will result in gpu lockup. The general adreno design philosophy appears to be to not ever dedicate transistors to making the driver writer's life easier... which for a SoC gpu is certainly the right choice, but it doesn't make things any easier for me. Over time, I've discovered many of these of these rules, but they are mostly all in my head at the moment. And from time to time, when adding new features to the gallium driver, I inadvertently break one or more of the rules and end up wasting time studying cmdstream dumps from the freedreno gallium driver to figure out what I did wrong.
So, on the way to XDC2014 I started hacking up support for register decoding from lua scripts. It turns out that time in airports and airplanes, where I can't exactly break out an ifc6410 and hdmi monitor to do some driver work, is a good time to catch up on these sort of projects. Now I can do nifty things like:
-- load rnn database file for a320:
r = rnn.init("a320")
function start_cmdstream(name)
io.write("START: " .. name .. "\n")
end
function draw(primtype, nindx)
-- simple full register access:
io.write("GRAS_CL_VPORT_XOFFSET: " .. r.GRAS_CL_VPORT_XOFFSET .. "\n")
-- access boolean bitfield Z_ENABLE in RB_DEPTH_CONTROL register:
io.write("RB_DEPTH_CONTROL.Z_ENABLE: " .. tostring(r.RB_DEPTH_CONTROL.Z_ENABLE) .. "\n")
-- access ROP_CONTROL bitfield inside CONTROL register inside RB_MRT[] array:
io.write("RB_MRT[0].CONTROL.ROP_CODE: " .. r.RB_MRT[0].CONTROL.ROP_CODE .. "\n")
end
function end_cmdstream()
io.write("END\n")
end
function finish()
io.write("FINISH\n")
end
which will generate output like:
[robclark@thunkpad:~/src/freedreno (master)]$ ./cffdump --script test.lua piglit.rd
Reading piglit.rd...
START: piglit.rd
GRAS_CL_VPORT_XOFFSET: 79.5
RB_DEPTH_CONTROL.Z_ENABLE: true
RB_MRT[0].CONTROL.ROP_CODE: 12
Currently it should handle all of the rnndb constructs that are used for adreno. Ie. simple registers, arrays of simple registers, arrays of groups of registers, etc. No support for "stripes" yet since those are not used for freedreno.
At the moment, all the script bindings are in freedreno.git/util/script.c but if there is some interest in this from nouveau or anyone else using librnn then it would be a good idea to try to refactor some of this into more generic code in librnn. It would still need a bit of glue from the tool linking librnn to get at the actual register values.
Still needed are a few more script hooks (such as CP_LOAD_STATE) to do everything I need for a validator script. Hopefully I find some time to work on that before the next conference ;-)
PS. I hope this post is at least a bit coherent.. I am still a bit jetlagged..