Following is a writeup on how to compile Linux kernel& BusyBox for ARM architecture and to load a simple device driver on the emulated system.
Ubuntu Linux machine with build utils and build essentials like make etc.
Working internet Connection.
The Shell script myEmu.sh in my repository automates the below outlined process and boots up a linux kernel running on ARM processor (of course this is NOT a silent run, passwords have to be entered and menuconfigs configured).
wget https://www.kernel.org/pub/linux/kernel/v3.0/linux-3.10.tar.bz2
sudo apt-get install gcc-arm-linux-gnueabi
tar xjvf linux-3.10.tar.bz2
Set environment variables to tell the Linux Build system to build for ARM and use a specific cross-compiler.
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
Note the hyphen at the end, the CROSS_COMPILE env variable is a prefix added to the default compiler to get the cross compiler.
cd linux-3.10
make vexpress_defconfig
This creates a .config hidden file containing all the build configurations.
make -j 4 all
The -j 4 option is to enable parallelism during compilation. Once the Build is Complete, the linux Kernel Image for ARM architecture is saved as zImage under linux-3.10/arch/arm/boot/
wget http://www.busybox.net/downloads/busybox-1.21.1.tar.bz2
tar xjvf busybox-1.21.1.tar.bz2
cd busybox-1.21.1
make defconfig
Additionally use a GUI driven build configuration settings page to tell BusyBox to compile everything statically and leave out certain unwanted and troublesome modules.
make menuconfig
Traverse in the GUI
Network Utilities==> Omit the Setup RPC Utilities (Optional, compiling with RPC might fail on some systems.
If you are getting an error that curses.h is missing install ncurses-dev package.
sudo apt-get install libncurses5-dev
make -j 4 install
Once the build is complete, a folder named _install is created. This folder contains a bare structure of the linux root file system. As you can see some important folder like proc, dev, sys etc are missing. So lets go ahead and create them.
cd _install
mkdir proc sys dev etc etc/init.d
It is not enough that we just create the special directories, we have to tell the kernel to mount special services to their respective directories.
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
/sbin/mdev -s
/sbin/init is usually the first program run by the linux kernel and its default behaviour is to execute the /etc/init.d/rcS file.
chmod +x etc/init.d/rcS
Since we are planning to install our simple memory driver on the emulated ARM Linux system, copy the driver files to any folder in this location, preferably create a new one.
mkdir memDrive/
cp <path to driver files> memDriver/
find . | cpio -o --format=newc > ../rootfs.img
The root FileSystem should be create by the name rootfs.img inside the busybox-1.21.1 folder.
sudo apt-get install qemu
qemu-system-arm -M vexpress-a9 -m 256M -kernel linux-3.10/arch/arm/boot/zImage -initrd busybox-1.21.1/rootfs.img -append "root=/dev/ram rdinit=/sbin/init"
A QEMU window should open up with kernel initialization messages and finally a message asking, press Enter to activate console. When you hit enter a root prompt is received and now you are running Linux Kernel on an emulated ARM processor.
mknod /dev/mymem c 60 0
cd memDriver/
insmod memory.ko
printk messages in module_init function should be now seen in dmesg|tail This should enable us to now read/write a single byte of data from/to memory.
echo -n 4 > /dev/mymem
cat /dev/mymem