Building Linux Kernel

1) Obtain Linux Source code
——-> 1.1) Obtain as a single file

Kernel is hosted at kernel.org. You can download the latest kernel from
ftp://ftp.kernel.org/pub/linux/kernel/

$ wget -c https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.13.5.tar.xz

——-> 1.2) Clone using git

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git linux-git

2) Configure
——-> 2.1) Old Config

$ make oldconfig

——-> 2.2) Custom Config

$ make menuconfig

3) Building

$ make -j4

4) Installing

# make modules_install install

Advertisements

Building and Booting Linux using Qemu

Previously, we have Built and Booted U-Boot through Qemu.
Now, let us build and boot Linux using Qemu.
Get the latest kernel source from https://www.kernel.org/
I took Stable 3.9.3 as on writing.

mkdir original
mkdir src
cd original
wget -c https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.9.3.tar.xz
cd ../src
tar -xf ../original/linux-3.9.3.tar.xz

Let us define the enviroinment variables that kernel build uses..

export ARCH=arm
export CROSS_COMPILE=arm-none-eabi-

Now, Let us configure this kernel build for Versatile Express.
This config is available at

./arch/arm/configs/vexpress_defconfig

For list of available configs, you can further explore in arch/ directory

make vexpress_defconfig;

Now, We need to make few changes, to make this kernel usable for our
needs in latter times.For this, We can remov module support (for
simplicity) and enabled EABI support as a binary format (allowing also old ABI).
This is necessary to run software compiled with the CodeSourcery toolchain.
Enable

kernel Features ---> Use the ARM EABI to compile the kernel and  
Kernel Features ---> Allow old ABI binaries to run with this kernel 

make menuconfig

We are all set to build the kernel. Now run

make -j4 all

Here, -j4 informs the build to use 4 build Jobs == Number of cores in your machine.
It will take some time to build.

Meanwhile, let us see what is the root file system and why do we need one, and
how to boot the kernel with a simple program.

Here is a definition of Root File System from Linux Information project

	
The root filesystem is the filesystem that is contained on the same 
partition on which the root directory is located, and it is the 
filesystem on which all the other filesystems are mounted (i.e.,
logically attached to the system) as the system is booted up 
(i.e., started up). 

The exact contents of the root filesystem will vary according to the 
computer, but they will include the files that are necessary for 
booting the system and for bringing it up to such a state that
the other filesystems can be mounted as well as tools for fixing a 
broken system and for recovering lost files from backups. The 
contents will include the root directory together with a minimal set 
of subdirectories and files including /boot, /dev, /etc, /bin, /sbin 
and sometimes /tmp (for temporary files).

Hope the kernel would have been built and ready by now.
The build should have completed with a message like,

  OBJCOPY arch/arm/boot/zImage
  Kernel: arch/arm/boot/zImage is ready
rajkumar.r@14:56:56:~/kernel/3_linux_qemu/src/linux-3.9.3$

The kernel will be available at

arch/arm/boot/zImage

Now, we can try to boot the kernel using qemu as below.

qemu-system-arm -M vexpress-a9 -kernel arch/arm/boot/zImage -append\
 "console=tty1"

-M vexpress-a9 : Emulate V Express Board
-kernel arch/arm/boot/zImage : Use this file as kernel
-append "console=tty1" console acts as the tty1
- generall Linux uses tty interface to display console messages

Here, you can read what is tty

But, now, the kernel will end up in panic telling something like,

VFS: Cannot open root device "(null)" or unknown block(0,0): error -6
Please append a correct "root=" boot option;
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown 
block(0,0)

Now, What we discussed about File system comes useful.
As the kernel message is telling, we are missing a root file system. To build
a complete set of root file system is a complex task [ Relatively 😛 ] So, we
are going to generate a simple file system.

Creating a Simple Filesystem :

create file test.c in the src directory with the below content.

#include 

void main() {
	while(1) 
		printf("Hello World!\n");  
}

As the program looks, it will run continouesly as kernel expects the first
program to run forever. Compile this program, using cross compiler for Arm
running Linux
[ This is not same as bare metal toolchain. Bare metal toolchain is for ARM
which has no OS. i.e like arm-none-eabi-, which we have exported while
building kernel.]

arm-none-linux-gnueabi-gcc -static test.c -o test

This will Compile and creates an ELF, staticaly liked to all required code,
in a single binary. We need a Filesystem, but we have a binary file now.
So we need to generate Filesystem using some tool. Before that, we should know,
What is initramfs?

https://wiki.ubuntu.com/Initramfs

initramfs, as the name tells, its the Initial Ram File System. This is
introduced for Linux 2.6 kernel, before which initrd is being used.

From ubuntu Wiki

The key parts of initramfs are:

1) CPIO archive, so no filesystems at all are needed in kernel. 
   The archive is simply unpacked into a ram disk.
2) This unpacking happens before do_basic_setup is called. This means 
   that firmware files are available before in-kernel drivers load.
3) The userspace init is called instead of prepare_namespace. All 
   finding of the root device, and md setup happens in userspace.
4) An initramfs can be built into the kernel directly by adding it to 
   the  ELF archive under the section name .init.ramfs initramfs' can be
   stacked. Providing an initramfs to the kernel using the traditional
   initrd mechanisms causes it to be unpacked along side the initramfs'
   that are built into the kernel.
5) All magic naming of the root device goes away. Integrating udev into 
   the initramfs means that the exact same view of the /dev tree can be 
   used throughout the boot sequence. This should solve the majority of 
   the SATA failures that are seen where an install can succeed, but the
   initrd cannot boot.

This initramfs uses a format called newc. Now, to get the cpio archive,
initramfs from the binary, run the below command.

echo test | cpio -o --format=newc > rootfs

Now, we have the zImage kernel and rootfs – Initramfs. Let us load the kernel

qemu-system-arm -M vexpress-a9 -kernel linux-3.9.3/arch/arm/boot/zImage\
-initrd rootfs -append "root=/dev/ram rdinit=/test"

Here, 

-initrd rootfs : Qemu option which tells, rootfs is the Filesystem 
binary image.

root=/dev/ram and 
rdinit=/test are kernel options passed to the kernel we load.

rdinit=/test tells the kernel to run "test" executable we built as init.

Now, we can see the “hello world” being printed.

Voila!! Done!!

Booting Linux Kernel using Busybox, Qemu, NFS, TFTP and uboot

I am recently trying to bootup the linux kernel to play and have fun with it. But I dont have a physical development board. I am interested to learn secure boot. In the end, I decided to use qemu for virtualization and busybox for root file system to boot the linux kernel. I am not expert in all of the below tools and hence wanted to document the steps and procedures I followed to make it easy and useful in latter times.

The steps I walked through is as below..

  • Cross Compiling
  • Building GNU ARM cross compiler Toolchain for development
  • Bare Metal Programming for ARM
  • Building and booting u-Boot in qemu
  • Connecting Qemu to network
  • TFTP Setup in ubuntu
  • NFS Server setup in ubuntu
  • Building Linux kernel for ARM Versatile PB and booting
  • Building Busybox to get root file system to Linux kernel
  • Booting Linux using u-boot through TFTP
  • Using NFS Root file system for Booted kernel

I will be documenting all of the above process one by one