This post describes the steps required for setting up an Ubuntu based compilation and debugging environment for U-Boot and Linux 2.6 w/a JFFS2 filesystem on a custom PPC board, using an Abatron BDI3000. It mostly discusses the environment and doesn’t dive too much as to how to customize the packages for your specific board (this is the hard part, but also extremely board specific). While you will probably not follow this guide from start to finish, it serves as a reference for what is the minimal amount of work required to build U-Boot and Linux for a PPC8xx board and a supplement to the DENX DULG, which is a must read.
It assumes that Ubuntu is already installed on the station, but nothing else. On the host side we mostly need the ELDK – a single package that contains all the cross tools needed (compiler, linker, debugger, tools to generate a file system, etc.).
A basic U-Boot/Linux target requires four things:
- A U-Boot binary (u-boot.bin) generated by customizing the U-Boot sources for your board, compiled using a cross-compiler (ppc_8xx-gcc in our case) and burned to the correct offset in the flash
- Linux image (uImage) generated by compiling the untouched Linux sources
- A Flat Device Tree BLOB (.dtb file), generated by compiling (using a specialized compiler) a textual DTS file which describes busses, offsets and devices of the target board
- A Root file system containing all the files we’d like to appear on the target once it’s up, packed into a single file. This file is generated by packaging up a directory from the ELDK which contains all the tools compiled for the architecture using the appropriate file system maker (in our case, mkfs.jffs2).
Step 1: Getting the sources
In this step we install git (the source control system), eldk (the development environment), U-Boot (the bootloader) and Linux (the OS). Start by getting eldk 4.2 for PPC (iso) from here (The file is under /pub/eldk/4.2/ppc-linux-x86/ppc-2008-04-01.iso). Keep in mind that this may be very slow as the file is 1.9 GB; I used GetRight on windows to pull the file from all the mirrors concurrently.
Create a working directory in your home directory:
sudo apt-get install git-core
Get U-Boot sources:
git clone git://git.denx.de/u-boot.git u-boot/
Get Linux sources:
git clone git://git.denx.de/linux-2.6-denx.git linux-2.6-denx/
Step 2: Installing the ELDK
Create an installation directory under your working directory (e.g. ~/dev/eldk)
Create a mount point for the ELDK installation CD and mount it (prepend the path of the iso to the file):
sudo mkdir /mnt/eldk-inst
sudo mount -o loop,exec ppc-2008-04-01.iso /mnt/eldk-inst/
Install the eldk for the ppc8xx architecture
Add eldk to path by appending the following in ~/.bashrc using a text editor of choice (make sure to show hidden files). After this is done, make sure to re-open a terminal window for the next steps:
Test this by running the following in your dev directory:
You should see the standard gcc “no input files” error.
Step 3: Preparing a JFFS2 filesystem
The ELDK contains a basic yet functional file system that we can use. It is packaged as a ramdisk image and we need to extract it so that we can build a JFFS2 image. Strip the prepared ramdisk of its 64 byte header, revealing a gzipped file. Unzip it to receive ramdisk_image
dd if=uRamdisk bs=64 skip=1 of=ramdisk.gz
Mount the image and give everyone access/execute permissions to it
sudo mkdir /mnt/rootfs-inst
sudo mount -o loop ramdisk_image /mnt/rootfs-inst
sudo chmod -R 777 /mnt/rootfs-inst/
Generate the JFFS2 image assuming a sector size of 128KB (0×20000), in this case
mkfs.jffs2 -b -r /mnt/rootfs-inst -e 0x20000 -o image.jffs2
Step 4: Finishing up environment installation
The development station requires a TFTP server for two reasons: the BDI3000 TFTPs a configuration file each time it loads and U-Boot will fetch the Linux images via TFTP once it is burnt to flash. We must therefore install a TFTP server and set up its directories.
First, we’ll install atftpd:
sudo apt-get install atftpd
sudo gedit /etc/default/atftpd (modify to USE_INETD=FALSE)
sudo invoke-rc.d atftpd start
sudo chmod 777 /srv/tftp
We then create three directories @ /srv/tftp:
Configure the BDI’s server IP address. See BDI documentation for more info how to do this.
Step 5: Compiling U-Boot to receive a burnable u-boot.bin
Customize U-Boot for your board. For a custom board with SDRAM and 8MB Flash, I had to:
Add a header file under include/configs/myboard.h with all the preprocessor directives. Again, you can reference the standard ep8xx board, but make sure to define CONFIGOFLIBFDT and CONFIGOFBOARDSETUP. Otherwise Linux will not boot because it doesn’t receive the FDT BLOB
- Create a directory under /board/myboard and have a Makefile, config.mk, u-boot.lds and myboard.c. You can copy these files from the standard ep8xx board
- myboard.c implemented the following functions:
poweroff: Reboot hook (didn’t implement anything here)
- checkboard: Just printed a banner
- initdram: Initialize the SDRAM
- ftboardsetup: Fixed up the FTD BLOB passed to Linux with information gathered by U-Boot
Add the board to the main Makefile (you should be able to easily understand using ep8xx as an example)
Clean, just to make sure
And then compile it
Step 6: Compiling Linux
Start by installing ncurses, required for menuconfig
sudo apt-get libncurses5-dev
At this point you will have to customize Linux. For PPC this mostly means creating a compilable device tree file (with a .dts extension) which describes the offsets of the core peripherals and such (instead of instantiating drivers in code). This is not trivial and is yet another syntax/structure to learn, but at least you have examples in the form of dts files for existing boards. In addition, you will also have to create a default configuration in arch/powerpc/configs, a custom platform in arch/powerpc/platforms (which will, at least, initialize I/O pins) and modify arch/powerpc/platforms/Kconfig + arch/powerpc/platforms/Makefile to support your new platform. Simply go by example of existing boards and check out this PDF.
Build Linux and the FDT BLOB (DTB file)
make ARCH=powerpc CROSS_COMPILE=ppc_8xx- my_board_defconfig
make ARCH=powerpc CROSS_COMPILE=ppc_8xx- uImage
make ARCH=powerpc CROSS_COMPILE=ppc_8xx- my_board.dtb
Step 7: Burning and configuring U-Boot
The following sections assume the following offsets: Flash starts at 0xFF800000 which is where the Linux kernel resides (until 0xFF9DFFFF), the DTB file resides at 0xFF9E0000 until 0xFF9FFFFF, the JFFS2 filesystem image resides at 0xFFA00000. Finally, U-Boot resides at 0xFFF00000.
Set up your BDI with a configuration script that will allow you to attach to the board and erase its flash. Define the sectors on which u-boot will reside so that the erase command will know what to delete. Copy u-boot.bin (from ~/dev/u-boot) to /srv/tftp/u-boot and then telnet to the bdi.
Open a serial connection to the target. Setup u-boot to auto-load the kernel at 0xFF800000 and pass the DTB @ 0xFF9E0000.
setenv ethaddr 00:e0:6f:00:00:01
setenv ipaddr [target-ip-address]
setenv serverip [your-pc-ip-address]
setenv bootargs root=/dev/mtdblock2 rw rootfstype=jffs2
setenv bootcmd bootm 0xff800000 - 0xff9e0000
setenv bootdelay 3
Step 8: Burning Linux, the DTB and the Root filesystem
Copy image.jffs2 created earlier and uImage, my_board.dtb from arch/powerpc/boot to the /srv/tftp/linux directory. Using the U-Boot console, download the images to RAM via tftp. After each download, note the size printed by u-boot in hex: Bytes transferred = 1284822 (139ad6 hex). You will need this for the next step.
tftp 0x100000 /linux/image.jffs2
tftpboot 0x400000 /linux/uImage
tftpboot 0x800000 /linux/my_board.dtb
Burn the images to the flash
erase 0xffa00000 0xffcfffff
erase 0xff800000 0xff9fffff
cp.b 0x400000 0xff800000 [linux-size-in-hex, e.g. 139ad6]
cp.b 0x800000 0xff9e0000 [dtb-size-in-hex]
cp.b 0x100000 0xffa00000 [jffs2-size-in-hex]
Power cycle the board – Linux should be up. Easy!