Searching the instrument cluster for a drawing route

Clutch Cargo runs games on the 800 by 480 screen of the MIB2 head unit in my Volkswagen Scirocco. The instrument cluster is a separate display. I wanted to put an arbitrary eight by eight checkerboard there, with every pixel chosen in advance, because a photograph could then distinguish my bytes from a warning icon or a convenient pattern already stored in the cluster's firmware.

None has appeared. This part of the work stayed offline, using a retained, hash-checked firmware image and earlier evidence from the car.

A callback with a good address

The first lead was a callback near the cluster's drawing functions. Its address appeared in enough places to look useful. I checked direct callers, literal function pointers, switch candidates, two lifecycle rows, twelve backend slots and thirty painter callbacks against the exact image. The body calls a function that returns. It returns too.

The actual bitmap calls led back to stock resources. All 28 recovered direct image-draw calls use the same image lookup, whose 752 admitted entries obtain pixel pointers from ROM. The three direct glyph calls build their descriptors from the cluster's ROM font. A different stock image selection can change the picture on a normal screen; the point of following the pointer assignments immediately before each draw was to find out whether any supplied bytes could survive lookup and reach the raster during that same paint.

Other apparent openings closed for different reasons. The stock lookup rebuilds a mutable descriptor before drawing. A bitmap converter clears and refills its scratch buffer before assigning the pixel pointer. Primitive commands carry fixed programme geometry. Several ROM images even contain an eight by eight checkerboard patch. Those pixels belong to existing artwork.

Source-derived diagram of the reviewed normal draw and conditional drawing-buffer route

Diagram from static firmware analysis. No cluster output is pictured.

The route I nearly dismissed

I had written that no admitted input could mark the whole drawing area dirty. That was wrong. A later event-table check found a guarded route to the full-dirty action, and all three recovered backend selectors can eventually copy bytes from drawing RAM into the transfer staging area. Two selectors add a timer and another event before the copy.

That route is a static byte-consumption finding. The delay is a problem: those two backends change internal state, arm a timer and later select a fixed ROM command sequence before copying the current drawing buffer, so an ordinary paint between the addressed write and that later copy can change what reaches staging even when the event was accepted. The third backend copies earlier, but its addressed write and trigger are still separate operations. Nothing in the reviewed path owns the buffer across them.

The completion trace raised another question. It changes owner state and schedules two other events. One updates fixed hardware bits; the other recomputes state through six fixed callback rows. No row carries the original pixels or a token identifying the transferred frame. There is no confirmed panel receipt in this evidence, either.

The conditional route needs a protected interval from the write to the copy, then a way to tell that the intended frame arrived, then a paired redraw of the original content. Current factory state and backend selection would also need measuring. I sent no diagnostic request and wrote no cluster memory during this investigation.

The callback lead is exhausted for this image. The buffer route remains conditional. Next I will follow only a new source-derived owner or pixel edge; repeating a stock-image test would leave the missing interval and restoration unanswered.