What for ?In order to be able to boot Linux on the Palm, we need a loadlin-alike program that will wipe out the Palm OS from the RAM and then give the hand to the Linux kernel image we provide it with.
Why is it so specific ?As explained, the bootloader has to be a Palm OS program. Unlike Linux which is a cross-platform software, our bootloader is platform-specific, since it has to be written for the Tungsten E platform, and for the Palm OS (version 5).
Coding for the Palm OSIn order to be able to compile software that will run on the Palm OS, we need a SDK. There is a free Palm OS SDK called prc-tools which uses the Gnu Compiler Collection. However, while newer Palm OS devices sport different kinds of processors (X-Scale, OMAP, etc...), former one used to run a 68000 processor. In order to keep a binary compatibility, newer devices (among of which the Tungsten E) runs a 68k emulator. And even though, they are still faster than their predecessor because their CPUs are way faster (and also because the Palm OS itself doesn't use emulation but is coded natively for the host CPU). However, Palm OS applications can be compiled natively for ARM : you'll gain speed, but you'll lose backward compatibility as a tradeoff.
What had already been done ?A bootloader for the Palm OS had already been written, but for older Motorola 68k-powered Palm devices. This loader is distributed with the uClinux embedded linux distribution, but it's also available here as a tarball. A few parts of this bootloader helped us, but most of it wasn't useable, since 68ks are too different from ARMs.
What have we done ?Here are the problems we ran into, and here is how we tried to solve them :
- In order to boot it, we obviously need to send a kernel image to the PalmOS. However, PalmOS databases cannot be bigger than 64Kbytes. This problem can be quite easily solved by splitting the kernel in 64Kb chunks, and re-joining them later on.
- We needed to get out of the 68k emulator, because any application is started as if it was a 68k app. This is not so hard, because the Palm OS has provision for this : we just used the PceNativeCall function.
- We had to setup the machine properly (i.e. turn off interrupts, turn off MMU, set up registers according to Linux expectancies). That was not a very hard job for two reasons : that's fully documented, and anyway most of this can be copied from u-boot, which fully supports OMAPs
- Last, but not least : we had to actually launch the kernel. That can sound dumb, but it was not as easy as it might have seemed. For this very simple reason : we had turned off the MMU. That's why the kernel image address we had was no longer valid. Here is how we solved it : first of all, we disassembled the PalmOS itself so as to get an idea of the virtual to physical memory mapping. Thanks to a disassembly of the DAL.prc file (we cannot distribute this one because it's copyrighted), we managed to find where the mapping was stored. Altering the memory mapping, we created a linear-mapped memory area that wasn't used by the PalmOS in normal use, but that was still large enough to contain a kernel image plus a small piece of code. Before disabling the MMU we copied our kernel image to this location, plus the end of the bootloader. We then jumped to the end of the bootloader, and disabled the MMU. In effect, disabling the MMU must be done from a linear-mapped memory address, otherwise the PC isn't valid once we stopped the MMU.
A few words about GaruxThe bootloader we made is named Garux. This stands for... err... nothing :-) To get the latest version of Garux, just use our CVS repository. Here is a list of key facts about Garux :
- Garux is functional. We have had some output from a running Linux kernel through the LCD display, so we are positive about its functionality. However, it still has a few limitations (for example I'm not sure it will correctly boot images bigger than a megabyte (i.e. 8Mbit), because of the PalmOS heap size limit).
- Because of the peculiar file structure of the PalmOS it's not possible (or at least pretty awkward) to dissociate the bootloader from the kernel image : that's why Garux needs the kernel image at compile time (in order to split it in 32000 bytes chunks and to join them in the .prc file).
- Garux has a built-in machine detection algorithm that will prevent it from running the kernel if it is ran on another PalmOS device. This wasn't meant at all to prevent our code from being reused, but since running Garux on a machine that is not a Tungsten|E would obviously lead to a crash we thought it was safer. If you wish to re-use some code from Garux for another Palm, you're obviously welcome.