A second stage bootloader for the Raspberry Pi to load kernels over UART.
While developing bare-metal software for Raspberry Pi is fun, testing it quickly becomes tiresome. You need to repeat the same steps over and over again:
- compile your kernel
- power down RasPi
- remove SD card
- insert card into card reader
- mount cards filesystem
- copy compiled kernel to card
- unmount
- remove card from the reader
- put it back into RasPi
- power on RasPi, check results
- write some more code
- repeat
Wouldn't it be nice if the above could be reduced to something like this:
- compile your kernel
- run a command, loading it on RasPi
- check results
- write some more code
- repeat
Well, that's what PiLoader is all about.
Raspberry Pi can be connected to computer in several ways, the easiest (to program) being UART interface.
Unfortunately, the ease of programming comes with a price - RasPi can not be directly connected to computer's serial port. It needs some sort of additional hardware to convert incompatible voltage levels. I am using my own homebrew board, but I'm sure there are several other options available.
Once we can send bytes from computer to Raspberry Pi and back, the rest is straightforward. We need 2 pieces of software, speaking the same language at the each end of the connection.
The part sitting on RasPi (second stage bootloader or server) starts the same way as average bare-metal kernel and sits there waiting for instructions.
The part running on PC (client) checks if it can contact the server over the UART link, and then starts to send commands and data to be placed in RasPi's memory (hopefully not overwriting the bootloader itself). Once the new program is loaded, it instructs the server to jump to it.
RasPi firmware loads every kernel from SD card at address 0x8000 and then jumps to same address to start executing. PiLoader's server is no exception. Since this is a second stage bootloader, there's a problem: things it is meant to load most probably will also want to occupy the space starting from 0x8000. To solve this, the bootloader first relocates itself to ~60 MiB memory location.
ARM bootloader protocol specifies that registers r0-r2 contains some special values.
- r0 - should be zero;
- r1 - machine type. Could check if running on RasPi or different board;
- r2 - pointer to ATags. A way to telling kernel few important things, like available memory amount;
Since PiLoader means to be as transparent as possible, it preserves these values and passes them to kernels when jumping to them.
PiLoader currently is able to load from plain binary and ELF formats.
- Supports "polluting" memory areas which normally should be zeroed, with 0xDEADBEEF. Useful to test if kernel initializes it's memory correctly. Works only when loading ELF files.
When kernel is started it will probably start to send some output back using UART. Monitor reads and outputs anything that comes from serial line.
RasPi hardware contains a watchdog feature. Once enabled it will wait for certain amount of time (around 16 s) and then reboot the board. Very useful since we are going to load many untested things on to RasPi, and they will most likely hang. If not for watchdog, we would need to power cycle the RasPi then.
If loaded kernel "knows what it is doing" it may disable the watchdog itself. Also there's a command-line option to do so.
If the kernel is finished everything it intended, and if it did not ruin the memory location where bootloader is located it may simply jump back to the bootloader's entry point.
Kernel file to load sometimes can grow quite large. Often it does not contain any useful code or data but is just padded with zeros to certain alignment. When loading ELF files, they are already optimized to exclude such parts. The story is different when loading binary files. They are just a "stream of bytes" none of which makes any sense to naive loader.
More intelligent loader (which PiLoader is as of recently) can look for big chunks of zeros in binary streams and upload them using special command to receiver. In other words: instead of sending, say, 16 KiB worth of zeros, it sends a message saying "and now insert 16 KiB of zeros".
Sometimes, while playing with hardware, just a return to bootloader is not enough. It's somewhat tainted
environment where pheriperals are left configured from previous runs. There are some things left in memory,
you name it. Of course you can power cycle the Pi. But now there is easier way. Just use --reboot switch
with piboot
.
Clone a Git repo or download and unpack tarball.
Server part should be compiled using ARM cross-compiler for Raspberry Pi and installed on the SD card. Since original Raspberry Pi and Raspberry Pi 2 are based on slightly different SOCs (and currently there is no auto-detection implemented), you need to choose the target platform. Add --enable-rpi or --enable-rpi2 options when configuring sources:
cd raspi
./configure --host=arm-elf-eabi --enable-rpi2
make
Now take a SD card with Raspberry Pi bootloader on it and copy kernel.img (or kernel7.img for Raspberry Pi 2) there. You can re-use a card with any official Linux distro image (Raspbian for example) if you do not know how to make an empty one. You might want to make backup (copy/rename) of existing file there first, if you plan to use that later.
A note about cross-compiler: yes you need to acquire one. But if you're into low level development, you should already know that. The recommended way is to build one.
Client part should be compiled a regular compiler on a computer you intend to use.
cd client
./configure
make
sudo make install
Connect your Raspi using appropiate serial adapter to computer and power it on.
Run piboot specifying port and kernel image to load. For example:
piboot -p /dev/ttyUSB0 -m kernel.elf
Sample kernel is provided to quickly check if everything works. It should be compiled using ARM cross-compiler. Similarly to Server:
cd samplekernel
./configure --host=arm-elf-eabi --enable-rpi2
make
Now, try to upload it on Raspberry Pi using piboot. It should respond with "Hello, World!" and then return to bootloader.
- 2-way monitor;
- More samples and documentation;
- ...