CtxInit

English/Español

How to create a context init code for some cards (nv4x and up)

This page refers to nv4X cards and up (NV4X/G7X/G8X). Almost all information was gathered from the Irclog. The process of new context init code consists from few steps:

Get ctx_voodoo

You can see example of ctx_voodoo in nv40_graph.c. It is, probably, some kind of microcode used in Nvidia cards, and you can get it from MmioTrace. In a parsed mmio trace you have to search for a single write to register 0x400324, followed by multiple writes to register 0x400328. Notice that the write to 0x00400324 is (almost always) zero. It is probably an index register that sets the starting writing position for the 0x00400328 register. Also, the register at 0x00400324 is probably auto incremented for each data write.

write32 #1 0x00400324 <- 0x00000000
write32 #1 0x00400328 <- 0x00400889
write32 #1 0x00400328 <- 0x00200000
write32 #1 0x00400328 <- 0x0060000a
write32 #1 0x00400328 <- 0x00200000
write32 #1 0x00400328 <- 0x00300000
...

Take all writes to 0x00400328 and store them in an array named static uint32_t nvXX_ctx_voodoo[] (XX is your card type). Put ~0 (0xFFFF) at the end of the array.

It's a good idea to automate the processing, as it may result in RSI otherwise ;-)

If you cannot find the voodoo, try doing the mmio-tracing again after a fresh cold boot. Keep the machine off for at last 30 seconds before power-on, and do not start X before you trace.

Get INSTANCE_WR writes (NV4x only)

I have no idea what these writes means, I only guess how to get them. First get REnouveau and apply patch. One of these could work for nv4X. However it may not. In that case look at them and try to come up with custom one. Also read the Irclog from 19:20.

If you apply the patch and run Renouveau, grep your card_stdout.txt (or maybe *graph_ctx_dump.txt if it exists) for GRCTX[0x. If you find it, just ignore all the 0 values (a lot of them will be 0) and convert the repeated writes of the same value into loops. You just got your INSTANCE_WR!

Graphics context at RAMIN+0x00083340
GRCTX[0x00000000] = 0x00008334
GRCTX[0x00000004] = 0x00000000
GRCTX[0x00000008] = 0x00000000
GRCTX[0x0000000c] = 0x00000000
GRCTX[0x00000010] = 0x00000000
GRCTX[0x00000014] = 0x00000000
GRCTX[0x00000018] = 0x00000000
GRCTX[0x0000001c] = 0x00000000
GRCTX[0x00000020] = 0x00000000
GRCTX[0x00000024] = 0x0000ffff
GRCTX[0x00000028] = 0x0000ffff
GRCTX[0x0000002c] = 0x00000000
GRCTX[0x00000030] = 0x00000001
GRCTX[0x00000034] = 0x00000000
GRCTX[0x00000038] = 0x00000000
GRCTX[0x0000003c] = 0x00000000

The irc log of for nv44 card and http://users.on.net/~darktama/renouveau-dump-nv44-grctx.diff patch.
19:40 < stillunknown> You say the nv44 method works always?
19:40 < darktama> no, it can still fail in quite a number of ways
19:41 < darktama> stillunknown: it'll fail if renouveau doesn't get assigned channel 2.. or if the context is in a part of instance memory not accesible through the "main" mmio regs
19:41 < mg> Graphics context at RAMIN+0x00409050... *not* a graphics context
19:41 < mg> Graphics context at RAMIN+0x00409050... *not* a graphics context
19:41 < pq> mg, it might or might not crash, look for Xid messages in kernel log
19:43 < mg> anyhow i have xis
19:47 < darktama> yup, got it.. can you add a printf("0x%08x\n", all_regs[0x2220/4]); somewhere please?
19:48 < darktama> just before the "ramfc_offset = " line will do.. doesn't really matter.
19:48 < darktama> the same for all_regs[0x0072000c/4]
19:54 < mg> darktama: all_regs[0x2220/4]:     0x00030002
19:55 < mg> darktama: all_regs[0x0072000c/4]: 0x00005029
19:55 < darktama> mg: ok, nvidia weren't being helpful :)  the 0x72000c value looks promising though.. so..
19:56 < darktama> change the "ramfc = " line to "ramfc = &all_regs[(0x00700000 + 0x20000 + (CTX_DUMP_CHANNEL * 128))/4];"
20:00 < mg> ok I got a dump now

If your card_stdout.txt contains ... *not* a graphics context, you'll have to try to adjust the patch. Probably ask in IRC.

Keep in mind that that some GRCTX do not belong to initilization. Sometimes this is easily seen, when the values become random. Also look for a jump in register address, this is a good indication.

NV44_GRCTX_SIZE

It is size of INSTANCE_WR writes... more or less. As long as you make it big enough(256x1024), it should be ok. If you want to get correct size, you should identify when another grctx starts and calculate the difference.

Now you should have enough information for creating new context init. Just look at the source code (DRM nv40_graph.c and similar) or ask in the channel. New developers are always welcome and the channel is a very friendly place.

Get INSTANCE_WR writes (g80+)

Things are a bit different here, you can use the same mmio-trace you used for the voodoo.

My trick is just looking for a marker. Look for some special value from existing ctxvals, then go up and search for the beginning.

Writing 0x30 at offset 0x10C is very common as a start value. In a parsed log it looks like this:

37.104057   write32 #5  0xc457810c <- 0x00000030

In an unparsed log it looks like this:

W 4 37.104057 5 0xc457810c 0x30 0x0 0

Once you find this you write down the line number and start going down, keeping an eye on the addresses. It's ok to jump to lower addresses, but once it starts doing other things (like accessing other mappings, mapping number is 5 in my example) or being too random it's probably done. Go back to the last jump and write that line down as well. Note that the highest address is at most 0x60000 compared to the first one. Note that lower end cards stay in the lower addresses. It's a bit of a guess where to stop and you may need to try more than once. Again it's wise to automate the conversion, as this'll really give you RSI and we wouldn't want that, would we? You are welcome to come to the channel if you need help, but do realise that we can't always hold your hand.

Some scripts that may or may not be useful:

If they don't make sense to you, then you probably shouldn't be doing this.

voodoo.py:

def tohex(val, padding):
        if padding == 8:
                return "0x" + "%08x" % val;
        elif padding == 4:
                return "0x" + "%04x" % val;
        else:
                return "0x" + "%x" % val;

file = open("voodoo.txt");
first_line = file.readline();
tmp = first_line.split();
base = tmp[4];

if base[len(base) - 6 :len(base)] != "400328":
        print "Unknown start address, expecting 0xXX400328"
        print "Address is " + base
        sys.exit(-1)

print ""
print "--- Cut below this line ---"
print ""

# go back to start
file.seek(0);

print "static uint32_t nvXX_ctxprog[] = {"
print " ",

counter = 0;
for line in file.readlines():
        tmp = line.split()

        print tohex(long(tmp[5], 16), 8) + ",",

        if counter == 5:
                print
                print " ",
                counter = 0
        else:
                counter = counter + 1;

print "~0"
print "};"

ctxvals.py:

def tohex(val, padding):
        if padding == 8:
                return "0x" + "%08x" % val;
        elif padding == 4:
                return "0x" + "%04x" % val;
        else:
                return "0x" + "%x" % val;

file = open("ctxvals.txt");
ctxvals = list();
# Pre-allocate the list
ctxvals = [0]*(0x70000/4)
first_line = file.readline();
tmp = first_line.split();
base = tmp[4];

if base[len(base) - 3 :len(base)] != "10c":
        print "Unknown start address, expecting 0xXXXXX10c"
        print "Address is " + base
        sys.exit(-1)

# python used signed values, so use long's so 0xFFFFFFFF is acceptable
base = (long(base,16) - 0x10c)/4

print "Base address: " + tohex(base*4, 8)
print ""
print "--- Cut below this line ---"
print ""

# go back to start
file.seek(0);

# store all values, the last write counts
for line in file.readlines():
        tmp = line.split()
        ctxvals[long(tmp[4], 16)/4 - base] = long(tmp[5], 16)

# make table
counter = 0
last_val = 0
output = list()
for val in ctxvals:
        if val == last_val:
                counter = counter + 1;
        else:
                if counter != 0:
                        output.append(" " + tohex(counter, 4) + ", " + tohex(last_val, 8) + ",");
                counter = 1;
                last_val = val;

# output table
print "static uint32_t nvXX_ctxvals[] = {"
for line in output:
        print line
print " " + tohex(0, 4)
print "};"