CFE Bare Bones
This example shows how to boot a simple "Hello world!" kernel using Broadcom's Common Firmware Environment (CFE). I have tested it on a Clarke-Tech ET9000 DVB-S receiver, which is based on a BCM7405 MIPS CPU. To compile this example, you need a GCC / Binutils cross toolchain for a mipsel-elf target - and a basic knowledge of the MIPS architecture.
Entry.S
The entry point of the kernel is written in assembler language. It sets up a small stack (4 kB), calls the C entry point and puts the CPU in an endless loop.
.global start .extern main .set noreorder .set STACKSIZE, 0x1000 .section .text start: la $sp, stack addiu $sp, STACKSIZE - 32 jal main nop b . nop .section .bss stack: .space STACKSIZE
Assemble this code using:
mipsel-elf-as -o Entry.o Entry.S
Main.c
The C part of the kernel contains a simple putchar function that outputs a character to the serial console, a printk function for printing a string, and the main function. Note that putchar directly accesses some hardware registers, which may be at a different address on other CPUs. This example prints the output to UART0 (16550A compatible) of the BCM7405, which is connected to the serial port of the ET9000.
void putchar(char c)
{
volatile int* lsr = (volatile int*)0xb0400b14; // Line status register.
volatile int* thr = (volatile int*)0xb0400b00; // Transmitter holding register.
while(((*lsr) & 0x20) == 0) ; // Wait until THR is empty.
*thr = c;
}
void printk(const char* s)
{
while(*s)
{
putchar(*s);
s++;
}
}
int main(void)
{
printk("Hello world!\n");
return 0;
}
Compile this code using:
mipsel-elf-gcc -o Main.o -c Main.c -Wall -Wextra -Werror \
-nostdlib -fno-builtin -nostartfiles -nodefaultlibs -O2
ldscript
Finally, we need to link our kernel. In this case we link the kernel to virtual address 0x80001000, which is the start of available RAM on the ET9000, accessed through the cached kseg0 window of the MIPS architecture.
OUTPUT_FORMAT(elf32-littlemips) OUTPUT_ARCH(mips:isa32) ENTRY(start) SECTIONS { .text (0x80001000) : { *(.text) *(.text.*) *(.stub) *(.gnu.linkonce.t.*) } .rodata ALIGN(4K) : { *(.rodata*) *(.gnu.linkonce.r.*) } .data ALIGN(4K) : { *(.data*) *(.gnu.linkonce.d.*) } .bss ALIGN(4K) : { *(.common) *(.bss*) *(.gnu.linkonce.b.*) } /DISCARD/ : { *(.gcc_except_table) *(.eh_frame) *(.note) *(.comment) *(.rel.*) *(.rela.*) } }
Finally, link the kernel:
mipsel-elf-ld -T ldscript -o Kernel.elf Entry.o Main.o
Booting the kernel
These instructions are again hardware dependent. I have tested them on an ET9000 DVB-S receiver, but booting other devices may be very different.
- Switch off the ET9000.
- Put the kernel file Kernel.elf on a FAT32 formatted USB stick and plug it into the ET9000.
- Connect the serial port of the ET9000 to your computer.
- Open a serial console program.
- Switch on the ET9000.
- Press Ctrl + C to prevent an automatic startup and boot into the CFE console.
- Enter the command "show devices" at the CFE prompt to see whether the USB stick has been found.
- Enter "dir usbdisk0" (or whatever name has been assigned to the USB stick by CFE) to see whether your kernel is in place.
- Enter "boot -elf usbdisk0:Kernel.elf" to boot the kernel.
If you see something like this, your kernel works:
CFE> boot -elf usbdisk0:Kernel.elf Loader:elf Filesys:fat Dev:usbdisk0 File:Kernel.elf Options:(null) Loading: 0x80001000/4112 0x80003000/4096 Entry address is 0x80001000 TP1 Entry Address at 0x80000ffc = 80001000 Starting program at 0x80001000 Hello world!