Contributed by marco on from the dept.
Something I really like in my OpenBSD work, is that I get to play with lots of odd hardware, each platform having unique pecularities, such as non-coherent virtually addressed caches, register windows, or externally controllable MMUs.
This gives me a fair share of janitor and QA work, which benefits the project as a whole. But sometimes, I need to take a break from this. When I am taking breaks, I am usually playing with old or obscure hardware noone is interested in, just for the sake of it. I can't help but do this - I must have the computer tinkerer's gene. Sometimes getting a long dead machine to display a blurred ``Hello World'' on a dying-of-old-age 100lbs monitor with a unique connector nobody remembers the pinout of makes me happy for the next ten months. Sometimes, I need a greater achievement.
During the second half of April, I had the chance to have more spare time than expected, so I could afford tinkering with something different, for a change. But since that spare time was unexpected, I had no idea what to do!
If you are following source-changes@, or simply checking ``who-does-what'' in OpenBSD, you probably know that I am responsible for most of the m88k-based work. This processor is a very elegant RISC design; before Motorola killed it in favour of the PowerPC processor, several lines of workstations were built on top of this processor. The three most successful, and most known lines were the Data General AViiON, the OMRON Luna88k, and Motorola's own m88k-based VME boards (MVME181, MVME187, MVME188, MVME197). OpenBSD was initially ported to Motorola's boards; then Kenji Aoyama ported it to the Luna88k, but nothing had happened for the AViiONs yet.
This was not exactly surprising; while Motorola's MVME boards are somewhat common among Unix hobbyists, and Luna's are still common in Japan, the AViiONs are often unheard of. The lack of any open source operating system available for these machines probably did not help!
I'll confess I was not interested in AViiONs myself, despite being a bit familiar with DG/UX which I used for some time in '99. My todo-list is large enough already!
But things changed when Chris Tribo, eagerly waiting for an operating system for his AViiONs, decided to publish some technical information about the machines he had available, borrowed from Data General technical books. Out of curiosity, I had a look, and it did not took me long to realize Data General had built the AViiON machines around a modified Motorola MVME188 design. A design I had extensive documentation for (including schematics!), which was supported by OpenBSD/mvme88k and which I knew well.
With these similarities, I had to give the port a try. Except I had no hardware, and wasn't interested. Plus I had no time. Until last month...
So I looked at this as a challenge: with the partial documentation I had access too, and my knowledge of the MVME188 design, would I be able to get a kernel to run?
Ok, I lied. I did not even ask me this question. I had thought about this for two years, it was time to write code. So I took an OpenBSD/mvme88k kernel, changed its name to OpenBSD/dg88k, removed all the non-MVME188 parts, and started changing the various register addresses to match the AViiON 400 addresses. This even compiled, but that kernel had no drivers but serial ports (using the same chip as on MVME188, of course), so the kernel would not be very useful.
Some more reading, a few guesses, and I had something for the on-board ethernet - enough to get a diskless system running over serial console, to begin with (actually, not really - it was obvious the interrupt vector for the ethernet controller was hardcoded in the design, yet I had no idea which value it was, but the first ``spurious interrupt'' message would tell me). Then I needed to replace the Motorola PROM calls with their AViiON equivalents, and I had a kernel ready to go. Except I had no bootloader for it!
At the moment, OpenBSD/luna88k and OpenBSD/mvme88k use a.out format binaries. But the AViiON PROM expects COFF binaries! So, in addition to the kernel, I needed to write a quick and dirty a.out to ECOFF converter.
Surprisingly, while changing the mvme88k code to become dg88k was sometimes tedious work, while writing this tool was just a matter of 300 simple lines of code, I had more fun playing with the kernel sources. So, before starting on this tool which would be the first real work done for the port, I contacted Chris Tribo, asking him if he would be interested in testing my work.
Fortunately for me, Chris agreed, and helped me with more documentation, which let me understand the few minor changes Data General had made against the original MVME188 design.
I gave Chris a kernel image converted to COFF. He tried to netboot it. Needless to say, he was not impressed by the results - the kernel froze before even writing anything on the console!
But there was no reason to despair or give up. I had the whole day to carefully proofread my code and try to find why it would misbehave; I would then upload a kernel in the evening, and thanks to living in different timezones, Chris could download it and play with it while I was asleep, mailing me his results during the night, and I could discover the results for breakfast. This is not a fast way to test, but there was no deadline anyway!
One day was enough for me to spot me stupidest errors, so every day Chris would test a new kernel which would print more things and eventually die. And everyday I would fix stupid bugs or typos, and get further. Until it was time to enable virtual memory. The kernel would freeze immediately after, and it had no reason to.
At this point, I spent nearly a week experimenting different things and ideas, usually causing severe regression because they were not good ideas. Eventually, I decided I would stop using the PROM routines to output characters and directly talk to the serial port. The kernel was then able to run substantially further, but froze as well. The freeze conveniently happend to match with a PROM call between two printf() calls, thus proving the PROM call to be the bad citizen. This meant that, while running with virtual memory enabled, the kernel was not respecting some of the PROM's assumptions. I had to move all the code which needed to use PROM calls (for example, to get the onboard ethernet address, which is stored in NVRAM) before enabling virtual memory.
The kernel thanked us by running to the end of the device autoconfiguration. It was not yet able to know it had been booted from the network, and was asking for its root device. Chris told it ``le0'', pressed enter... and got greeted by a panic from the interrupt handling code.
I was puzzled. The interrupt handling code was the same as on MVME188, except for the on-board interrupt source being different. Yet reserved bits in the interrupt status register were set, while they should have been masked, and obviously the kernel did not know how to handle a fictitious interrupt source!
I added a few traces, until I realized that it was obvious that some hardware registers I was reading to determine which interrupts the kernel could service were read as 0xffffffff (i.e. all bits set to one), because they were in fact write-only, unlike on MVME188! All I needed was to cache in global memory the values which had been written in these interrupt mask registers, and instead of reading back the hardware address, the kernel would use the cached value. Hoping this would be enough, I uploaded a new kernel for Chris and went to sleep.
When I got up the next morning, my mailbox contained a mail whose subject said ``Welcome to multiuser''. Chris was happily running multiuser but diskless on his machine. It was time to clean the code and commit it. The CVS tree shall now document all my future progress on this port!
(Comments are closed)