Today atlast I completed my task of building tiny embedded system using busybox for ARM. This is for your info,

Target – LPC 3250 (ARM926EJS processor),

Development Board – Embedded Artists LPC 3250 OEM,

Host linux distro – debian

I will direct you to generate bare minimum embedded system, that can run a terminal at last, over the linux ported on lpc 3250. For any embedded system you need,

1) Cross compiler, click for more info.

2) Bootloader – I may not discuss this now, better will post next time. Proceed further if only bootloader is installed in your development board. This can be known from u-boot terminal of board when connected serially with development station.

3) Kernel. I suggest to use default configuration file which is shipped with development board for newbies.
Once you created kernel image, do a check.

Loading kernel image to RAM,

uboot> tftp ${loadaddr} uImage

assuming loadaddr = 0x80100000. For more on tftp.

uboot> bootm ${loadaddr}

Kernel will start booting and it will panic atlast since root file system is not yet loaded. Hence our next process is to build up a minimal root file system, and use the same with our own kernel.

4) Building Root filesystem using BUSYBOX

Busybox is a binary utility which can replace more and more required utilities which we use often in linux system. It is very much prescribed for embedded system, where storage memory is very minimum. And it will create a minimum root filesystem too.

To Get latest busybox click here, follow as below

$ tar -xf busybox.tar.gz
$ cd busybox/

Configuring Busybox with this .config file,

$ make menuconfig

Go to “BusyBox Settings –> Build Options” and enable the option “Build BusyBox as a static binary (no shared libs).

Building busybox, with Cross compiler, which we created much early.

$ make ARCH=arm CROSS_COMPILE=arm-linux- 

Installing busybox at rootfile system,

$ make install

You can find root file system at _install directory of extracted busybox source directory.

Copy the rootfile system at some other directory (say /home/user/nfsrootfs), which is exposed to development board using nfs(Network File System).

So, upto this, we created 1) kernel image (uImage), 2) root filesystem at development pc. We need both of them to be tested with target board using u-boot terminal. Let us jump to u-boot terminal now.

When you power up target board, it will automatically starts loading bootloaders (kickstart bootloader, u-bootloader). Kick start type of bootloader is for target board specific. When it starts u-bootloader, press any key, it will drop you in uboot> terminal. Follow each steps below,

1) I need to say target board, that it will get root filesystem via NFS. I may give following commands for that.

uboot> setenv rootpath /home/user/nfsdir

where as /home/user/nfsdir holds rootfile system.

uboot> setenv bootargs console=ttyS0,115200n8 root=/dev/nfs3 rw nfsroot=${serverip}:${rootpath} ip=${ipaddr} ethaddr=${ethaddr}

whereas ttyS0 – 0 is zero not ‘O’.

uboot> saveenv

as a simple case you may assign the whole command to a single environment variable such as nfsboot (default variable for many U-bootloaders).

See this,

uboot> print nfsboot

nfsboot=setenv bootargs console=ttyS0,115200n8 root=/dev/nfs3 rw nfsroot=${serverip}:${rootpath} ip=${ipaddr} ethaddr=${ethaddr}

2) I may, send kernel image to RAM of target board using tftp protocol.

uboot> tftpboot ${loadaddr} ${serverip}:${bootfile}

whereas loadaddr is the RAM address of target board (In my case it is 0x80100000) and bootfile is uImage file. Assign all the above commands to a single environment variable named as tftpstatickernel.

See this,

uboot> print tftpstatickernel

tftpstatickernel=tftpboot ${loadaddr} ${serverip}:${bootfile}

3) Now we have kernel at RAM, and rootfile system can be accessed using NFS. Its time to boot up. Try to boot

 uboot> bootm ${loadaddr}

Once everything goes well, your kernel will bootup and looks for rootfile, then you should get errors on missing /dev/ttyX files something as below.

You need to create each of such device files manually,

$ cd /home/user/nfsboot
$ mkdir dev
$ cd dev/

Use same major and minor number, what our pc holds for device files.

$ sudo mknod -m 600 console c 5 1
$ sudo mknod -m 666 null c 1 3
$ sudo mknod -m 666 tty c 5 0
$ sudo mknod -m 666 tty0 c 4 0
$ sudo mknod -m 666 tty1 c 4 1
$ sudo mknod -m 666 tty2 c 4 2
$ sudo mknod -m 666 tty3 c 4 3
$ sudo mknod -m 666 tty4 c 4 4

For reference, you may get major and minor number of each device from linux distro(development pc).

$ ls -l /dev

crw——-  1 root root        4,   0 May  3  2013 tty0, Here ‘4’ is major number and ‘0’ is minor number.

We can automate all 3 steps, once board is powered on, it will automatically start booting.

uboot> setenv bootcmd 'run nfsboot; run tftpstatickernel; bootm ${loadaddr}'
uboot> saveenv

Once everything is fine, you will get a terminal atlast, this is what is running on target board.

Upto this till we haven’t mounted any virtual filesystem, that is very much needed for a kernel to operate, you can test this defect by typing ps command

$ ps

/proc : directory does not exists.

Manually create proc, sys, directories

$ mkdir proc sys etc

Only way is to mount development workstation’s proc and sys at target proc and sys. This can be done by /etc/init.d/rcS script.

When a system starts the first userspace program executed is /sbin/init, and its configuration file is /etc/inittab. A basic version of /etc/inittab that support busybox based root filesystem is,

$ vim /etc/inittab

# /etc/inittab: init configuration for /sbin/init

# running /etc/init.d/rcS for mounting /proc and /sys file system

::sysinit:/etc/init.d/rcS

A script at /etc/init.d/rcS, which mounts both proc and sys is

#!/bin/sh

# just dummy to mount /proc and /sys

mount -vt proc proc proc
mount -vt sysfs sysfs sys

echo ‘done_again’

/bin/sh

Thats it, we build a tiny embedded system.

Running ‘hello world’ on target,

A simple hello.c program,

#include <stdlib.h>
#include <stdio.h>

int main (void)
{
printf( “Hello world!\n” );
return EXIT_SUCCESS;
}

Compile this by Cross – compiler arm-linux-gcc,

$ arm-linux-gcc hello.c -o hello
$ file hello

hello: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

Copy the binary at root file system of target. Start executing binary,

$ ./hello

You will first encounter a not found error caused by the absence of the ld-uClibc.so.0
executable, which is the dynamic linker required to execute any program compiled with shared libraries. Using the find command (see examples in your command memento sheet), look for this file in the toolchain install directory, and copy it to the lib/ directory on the target. Then, running the executable again and see that the loader executes and finds out which shared libraries are missing. Similarly, find these libraries in the toolchain and copy them to lib/ on the target.

As a final stage, you will see,

Hello World!

Enjoy…!

Advertisements

2 thoughts on “How to build Tiny embedded system using busybox for ARM target

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s