Wednesday, June 9, 2010

Beagleboard: Designing the 2nd stage Bootloader (XLOADER)

One of the main functionality of this 2nd stage bootloader is to setup a basic Interrupt Vector Table to catch exceptions that might occur during the initial boot stages, setting up external SDRAM for early availability, basic console setup to track the boot progress and finally setting up stacks for all available ARM modes in preparation for a complete C runtime environment.
As there are no initialized segments or stacks available to run a C program, we will start with ARM assembly instructions for the first few steps.

We compile and link our loader image using the ARM GNU compiler toolchain for all development purposes here.
As soon as our program is loaded onto the board, we need to ensure that the control jumps to our program's entry point. We will label our entry point as '_start' as this is the most common entry point label generated by most of the compilers for any program, by default.
For any source file when being compiled and linked, we can notify the entry point of our code to the Linker using the directive ENTRY. So in our case, we write a linker script file called "PB.ld" and add the following directives:

OUTPUT_FORMAT ("elf32-littlearm")
OUTPUT_ARCH (arm)
ENTRY (_start)


Here the first directive OUTPUT_FORMAT notifies the linker that our file will be linked as an ELF32 executable, executed in LITTLE ENDIAN mode.
The second line OUTPUT_ARCH specifies that the file is to be linked in for an ARM architecture platform.
Finally, the third line, ENTRY specifies the label of entry point of our image to be _start.

To be continued.........

Beagleboard: The XLOADER

XLoader is typically a very tiny bootloader code (which has a restriction on its size to be less than ~61KB)
that prepares the board/HW for the 3rd stage bootloader.
The limitation on Xloader size applies due to the fact that this code gets loaded onto an internal (within the OMAP 3530 die, closer to L2 Cache) onchip SRAM whose size is limited to 64KB. Though 64KB in size, this SRAM is further divided to accomodate stacks for different modes, Interrupt Vector Tables, Tracing data etc., leaving behind only  61KB available for the actual code and static data.

This stage of the bootloader does additional configuration (Mostly external SDRAM setup, basic IVT setup, Stacks setup etc.) in preparation for the 3rd stage bootloader  (Typically the "UBOOT" in a Linux setup).


We will start our development from this 2nd stage bootloader phase and proceed forward bringing more and more features to life as we progress......

Beagleboard: 1st stage bootstrap code (aka The BOOTROM)

Bringing up Beagleboard hardware to life happens in several stages. When the board is first powered up, the CPU execution starts from a pre-flashed ROM code called the BootROM.

As descibed in the OMAP TRM, BootROM code resides in an internal ROM within the OMAP 3530 chipset and is considered as the bootstrap code of the chip. This code initializes some of the very basic modules required for executing the later boot code stages. This includes setting up initial clocks, reset and power connections, configure multiplexed hardware pins involved in setting up boot memory space for the next stages.

BootROM code also comes with very basic drivers for certain boot peripherals like the MMC module, NAND/OneNAND, USB or the UART ports.
Using the configuration of OMAP Boot Switch SYS.BOOT[5], any of the above modules can be used for loading the next stage bootloader.
In case of Beagleboard, we can choose the order in which the BootROM looks for the 2nd stage boot code using the provided USER button.

  • User button not pressed: NAND -> USB -> UART -> MMC
  • User button is pressed: USB -> UART -> MMC -> NAND
In a normal linux configuration, 2nd stage bootloader is called the XLOADER.