Because I watch too much retro YouTube I decided it was a good idea to try installing Adelie Linux on my old G4/800 eMac, but the Live installer would freeze. By blacklisting nouveau I was able to get it booted and manually installed and, after hours and hours of compiling, get a working kernel tree to poke at. After only a few iterations with dump_stack() and nvkm_debug and the output of envytools/nvbios I worked out at the last initscript instruction was stored in the last byte of the ROM. I think the bounds check in the nvbios_addr() function is miscalculating the limit as one byte short, that’s why I was seeing this in the syslog:

 

nouveau 0000:00:10.0: bios: OOB 1 000007b2 000007b2

nouveau 0000:00:10.0: devinit: 0x000007b2[ ]: unknown opcode 0x00

nouveau 0000:00:10.0: preinit failed with -22

nouveau: DRM-master:00000000:00000080: init failed with -22

nouveau 0000:00:10.0: DRM-master: Device allocation failed: -22

nouveau: probe of 0000:00:10.0 failed with error -22

 

After I changed the limit check from:

if (unlikely(*addr + size >= bios->size)) {

to:

if (unlikely(*addr + size > bios->size)) {

 

it initialized the card properly, brought up the fbconsole and even seems to be working in X with DRI. So the question is: was the bounds check wrong, or is the NVDA,BMP image provided by OpenFirmware truncated? I’m guess this doesn’t turn up elsewhere because the ROM images read through any of the other methods are the size of flash chip they’re stored on so there’s always unused space at the end and they never use the last byte where the NVDA,BMP provided by OpenFirmware is just the active section.

 

The patch is against the Adelie easy-kernel patch 5.4 tree, but it looks like that code is still there in the current upstream torvalds/linux git.