Linux on Alpha AXP—Milo, The Mini-loader

Linux on Alpha AXP—Milo, The Mini-loader
Device drivers

One of the really excellent things about Linux is the number of device drivers that have been developed for it. It seems as if any commercially-available card or chip set has a driver already written for it. It therefore seemed vital that Milo should be able to make use of those drivers. This allows companies building Alpha-based systems to differentiate their products by having a vast choice of possible devices.

To run the device drivers unmodified, I had to duplicate some services of the Linux kernel. Originally, I planned not to have real interrupts, but instead to poll the drivers. This was the way that Milo worked in Linux 1.1.68. However, once I started to try and get the NCR 53C810 SCSI driver working in Milo, I ended up needing proper interrupt handling, and it seemed best to take the interrupt handling directly from Linux, which I did.

I have tried to keep the number of Linux services that I have had to duplicate in Milo to a minimum. After all, as Linux progresses, these routines tend to need re-writing. A good example is the change from 1.1.68 and 1.2.8; the floppy driver changed its way of determining that it was running during kernel initialisation. This caused me headaches as I figured this out.

Maybe over time I will incorporate more of the real Linux kernel into Milo, but it is supposed to be the Mini loader, so I do not want to add the whole of the kernel into it. Right now, Milo includes the PCI BIOS code, the block device code, the interrupt handling and DMA code directly from the kernel. The scheduling services are mine and I cannot see them changing unless I add multi-threading support.

Using Milo

The final functional piece of Milo is the part that most users see, the user interface. Milo can operate via the serial port, but mainly people use it via the system console. For this reason, it must have some keyboard and VGA initialization code.

The keyboard code is very very simple and does just enough to take in commands correctly. Linux itself assumes that some BIOS code has initialized the VGA device and its console device drivers just use it; that meant that Milo had to initialize the VGA device. There are two ways of doing this. The first is to have very simple ISA VGA initialisation code, and this is how Milo first operated. The second way is to include BIOS emulation code that can run the on-board initialisation (which is Intel x86 object code) from the different video cards. David Mosberger-Tang pulled this part of Milo together, with the result that it can successfully initialise a number of common ISA and PCI graphics cards.

The Milo interface is meant to be very simple and do just enough to get the right kernel loaded and to pass the right boot arguments to it. Typing anything other than a legal command displays all of the commands available. Right now, Milo assumes that all devices that it can see are available to boot from and will attempt to use the EXT2 file system with them.

Loading the Loader

Milo was developed on an Alpha evaluation board (an EB66, which is a 21066 based system similar to the AxpPCI33). This meant that loading and testing Milo was easy, since the Evaluation Board Debug Monitor was running. However, for real systems like the AxpPCI33 (Noname), Milo needs to be loaded some other way.

Alpha-based systems boot in several steps. The first step, immediately after power on, is to clock the SROM code directly into the I-Cache stream and then to start executing it. This code does really basic system set up such as figuring out how many DRAM slots are occupied, and with what size of memory. The next step varies from system to system, but essentially that SROM code loads the firmware code (whatever it is) into memory and passes control to it in PALmode. This is the PALcode reset entry point for the image. Some firmware, notably Milo, has the address of the entry point to the user-mode firmware defaulted in the PALcode, and that is where control is passed to when the PALcode reset code has finished initialising the system. Other systems have this information stored in NVRAM or infer it from jumper settings.

For a variety of reasons, Milo can be loaded from a failsafe boot block floppy, from flash, and via the Windows NT ARC firmware. What varies most from system to system is where the SROM code is able to load firmware from. On the AxpPCI33, the SROM code is capable of loading from flash, from a serial line, or from a failsafe boot block floppy. On the AlphaPC64, the failsafe boot block floppy is not supported. All of this is controlled by jumpers and/or boot options saved in NVRAM (in the TOY clock in the AlphaPC64's case). There are systems that do not support flash and instead have ROMs. These are not easy for users to change without access to a ROM blower. and so yet another way must be found for Milo to be loaded. Paradoxically, you could load Milo via the SRM console, but a more fruitful approach is to load it via the Windows NT ARC firmware, since that is the firmware these boards ship with.

There are a number of ways to put an image into flash, and for this reason Milo supports running any image, so long as it is linked to where the Linux kernel usually is. In this way, I can build images that update the flash when loaded and not burden Milo with knowing about the flash requirements of every different system that it runs on.

Loading via the Windows NT ARC console is interesting. On Alpha, Windows NT runs in “super paged” mode, which does not support KSEG addressing—which is unfortunately exactly what Linux needs for fully 64-bit operations. However, all PALcode implementations must support the “Swap Pal” call, and this allows you to change from one mode to another. The Windows NT ARC console has within it the notion of running images and providing services to them so long as they are built to run in the appropriate addressing mode and run at a safe place in memory.

Thus, the Windows NT OS loader is in fact an executable image which gets loaded in order to load Windows NT using the appropriate call backs. I have written a very simple OS loader whose only function is to load Milo, which in turn loads Linux. It is this simple loader which makes the “Swap Pal” call which causes control to be passed to Milo and KSEG addressing turned on. From then on, Milo operates exactly as before with the addition that it can execute commands passed via the [cw]OSLOADOPTIONS[ecw] environment variable for this boot option, and thus boot directly without pausing at the Milo prompt.

I have tried to eliminate this need for an image that is built under the Windows NT firmware development tree; unfortunately this is not possible, so I have kept the functionality of this part as minimal as possible.

Of course, loading Milo via the Windows NT ARC console is one way to get Milo running so that Milo can run the flash update utility to put itself into flash. Alternatively, it can be a way of running either operating system without one interfering with the other.