7. Consoling Yourself

Hitting start_kernel() is in theory the beginning of the easy road. On a PC at least you have text mode consoles instead of stripes, on a Macintosh hitting start_kernel() meant that the prospect of getting the kernel to initialise a text console and begin showing useful debugging information was close. Nothing could have been further from the truth.

After several attempts to get the console up I wrote some routines to print penguins and macs on the screen (this was easier than text). Each significant point the kernel reached added a penguin to the display and a failure point before the console came up printed a given number of burning macintosh logos. While hardly as good as print statements this was good enough to rapidly locate several bugs in the processing of options passed by the boot loader (little things like apparently having 0K of memory tend to upset the Linux memory initialisation). The code would get to the beginning of the console setup and die.

To get past this point I had to fill in support for the 4bit packed pixel displays that were used by the Apple Macintosh 'Toby' display card. The generic bitmapped console drivers for the 680x0 port supported a wide variety of pixel formats, and naturally excluded the one I needed.

Had I known at the time I could simply have switched the machine to Mono in the display preferences but at the time I didn't know the physically switched the card into a monochrome mode. Adding 4bit packed pixel wasn't too difficult. I left the somewhat scarier 2bit packed pixel support for later, in the hope someone else would have to write it not me. The console code is also very modular on the 680x0 and these console layers (abscon, fbcon) are now used by most non Intel ports. It's reasonable to assume that it will be driving all the ports by the 2.3 kernel series.

The machine still crashed mysteriously and all evidence pointed to a structure getting stamped on. I put guard values either side of it and checked they were not overwritten, I moved the structure in memory and I tried everything I could think of in order to stop it being apparently corrupted. No joy, no change. After a bit of head scratching I added code to check the values were ok at boot, and at initialisation of each subsystem. The value was wrong at the start of the C code. I checked it at the start of the assembler and it was wrong by then.

This was beginning to look worrying, it seemed that the boot loader was corrupting data, yet this made no sense as the loader would corrupt the same location, not pick on a specific helpless little variable wherever it may have been located. Eventually I used the GNU objdump tools to look at the binary I was loaded. It turned out that the GNU linker was at fault and in some places was loading a completely bogus address for a relocation.

A new linker and the magic words 'Calibrating Bogomips' appeared on the screen, followed by a hang, and there was much rejoicing. In many ways the time lost to the linker bug was not that bad. Eyeballing the code in search of the mystery bug I had fixed some twenty or thirty other serious bugs in a vain attempt to find the illusionary real bug.

I wasn't too worried the Bogomip calibration hung. It's very hard to calibrate time before the interrupt routines, especially the timer interrupt routines have been written. I commented it out and after a short while the rest of the code booted to the point of saying 'Panic:unable to mount root filesystem'. A reasonable situation as I had exactly no device support except the screen.