For ncurses-based graphical utility
$ make menuconfig
To create a config file absed on the defaults for the host architecture
$ make defconfig
The configuration is stored in the project root in a file named .config
.
Config file validation (always run it) before building.
$ make oldconfig
Once the configuration is set the build can be started
$ make -j8 > /dev/null
Some old kernel versions can not be easily built using the latest GCC versions.
A simple solution to build with a given GCC version without installing installing it in the host system can be to use docker.
This is the command line I've used to build the kernel 2.6 using gcc 4:
$ docker run -v `pwd`:/build gcc:4 /bin/bash -c 'cd build && make'
To run the kernel on QEMU
$ qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage
After a while you'll get the following kernel panic message
[ 1.568246] VFS: Unable to mount root fs via NFS, trying floppy.
[ 1.571268] VFS: Cannot open root device "(null)" or unknown-block(2,0)
[ 1.571730] Please append a correct "root=" boot option; here are the available partitions:
[ 1.572751] 0b00 1048575 sr0 driver: sr
[ 1.573342] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(2,0)
[ 1.574196] Pid: 1, comm: swapper Not tainted 2.6.34 #3
In short it means that it cannot find a valid root filesystem.
For fast experiments it is convenient to have a filesystem that we are able to modify quickly. We can put all the stuff we need in a initramfs image.
Initramfs content can be easily populated using the gen_init_cpio
utility
built within the kernel.
The utility parses a script enumerating the files and directories we want to copy from the host to the initrd filesystem.
For example (file named initrd_script
):
dir /bin 0755 0 0
nod /dev/zero 0666 0 0 c 1 5
To generate the initrd image
$ usr/gen_init_cpio initrd_script | gzip > initramfs.img
Let's try to boot by specifying the initramfs as our initrd image to qemu:
$ qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -initrd initramfs.img
Unfortunately we get another kernel panic, this time due to the missing
foundamental executale: init
.
Init
is the first program run by the kernel. Its main requirement is that it
shall never exit.
Let's build a dummy init that just prints hello world forever.
void main(void)
{
while (1) {
printf("Hello world\n");
sleep(3);
}
}
We need to build the application as static and with a compiler that is compatible with the one used to build the kernel (we use docker again).
$ docker run -v `pwd`:/build gcc:4 \
/bin/bash -c 'cd build && gcc -static myinit.c -o myinit'
Modify the initrd_script
by adding the init file:
file /init myinit 0755 0 0
dir /bin 0755 0 0
nod /dev/zero 0666 0 0 c 1 5
Rebuild the initrd filesystem and run the kernel.
Dummy Linux is the most trivial usable system every.
Its main purpose is to give to the user the opportunity do easily debug some kernel functionality by triggering a particular syscall from the user code.
It is mainly composed of an init program that just spawns a very simple interactive shell
The shell is capable to start other binary files that you can add to the system. The only requirement is that your programs shall be built as static binaries.
The updated initrd script can be downloaded here
From the BusyBox sources root:
$ mkdir build
$ BUILD=`pwd`/build
Create a minimal default config
$ make O=$BUILD defconfig
Edit the config for fine tuning
$ make O=$BUILD menuconfig
From the menu config, enable static linking
Busybox Settings --> Build Options -> Build static binary [X]
Build Busybox
$ cd $BUILD
$ make -j2
$ make install
Build the directory structure of the initramfs
$ mkdir $BUILD/initramfs
$ cd $BUILD/initramfs
$ mkdir -pv {bin,dev,sbin,etc,proc,sys/kernel/debug,usr/{bin,sbin},lib,lib64,mnt/root,root}
$ cp -av $BUILD/_install/* $BUILD/initramfs
$ sudo cp -av /dev/{null,console,tty,sda1} $BUILD/initramfs/dev/
Create a "mini" init as a shell script
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug
echo -e "\nB U S Y L I N U X\n"
while true; do
/bin/sh
done
And make it executable
$ chmod +x $BUILD/init
Create the initramfs
$ cd $BUILD/initramfs
$ find . | cpio -H newc -o > ../initramfs.cpio
$ cd ..
$ cat initramfs.cpio | gzip > initramfs.img
Then modify the qemu initrd option and start as usual.
If you are building using docker remember to map the volume containing the BusyBox sources and not just the build folder. For example:
$ docker run -v '/home/davxy/busybox':'/home/davxy/busybox' gcc:4 \
/bin/bash -c 'cd /home/davxy/busybox/build && make -j2'
Proudly self-hosted on a cheap Raspberry Pi