Compiling the Linux kernel and creating a bootable ISO

This revision is from 2024/01/22 09:06. You can Restore it.

Guide to compile the Linux kernel from source, make the file system from BusyBox and then run it using QEMU. Make a bootable ISO of it and boot it on a computer.

The Linux Kernel

At first, compile the Linux kernel, https://kernel.org/ and grab the latest Linux kernel.

wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.7.1.tar.xz
tar xf linux-6.7.1.tar.xz
cd linux-6.7.1.tar.xz

General preparation environment to compile the kernel...

sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev
sudo apt-get install grub2 xorriso debootstrap

To configure the kernel:

make defconfig

This will create the default config file for compiling Linux. Then run

make menuconfig

to enter a TUI to edit the config file. One thing for older devices is unchecking 64 bit kernel. Use make -j $(nproc) to compile using all the CPU cores.

# Example: Using 4 parallel jobs
make -j4

After compiling, you should get the arch/x86/boot/bzImage . If not, check the make file log.

BusyBox

Next use BusyBox to create a minimal file system. Get the source code and extract it.

wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar xf busybox-1.36.1.tar.bz2
cd busybox-1.36.1

Run...

make defconfig

to make a default configuration for the BusyBox. Then...

make menuconfig

to bring the TUI and edit the configs. The option which you must edit is located in Settings, and then Build static binary (no shared libs). The reason to enable this option is we do not want to compile Glibc into the Linux distro.

Use..

make -j $(nproc)

to compile BusyBox. To check if the compiled file is fine, use command...

file busybox

The file must be statically linked.

Creating The File System

Create the file system which contains BusyBox. Run make install . This will create a folder called _install and change directory to _install and you will see a hierarchy like Linux file system.

In this directory, run the following command to create the folders needed for kernel.

mkdir dev proc sys

Now create a file called init and open it with a text editor. Copy and paste the following data to it:

#!/bin/sh
mount -t devtmpfs none /dev
mount -t proc none /proc
mount -t sysfs none /sys
echo "Welcome to my Linux!"
exec /bin/sh

Then make the script executable with...

chmod +x init

Done. BusyBox made one executable which is capable of providing us a lot of Linux utilities such as sh , echo , vi and so on. With make install we made a filesystem hierarchy which contains these programs as links to BusyBox executable. Next, we make a shell script called init. This script will be ran after kernel loads. At first, it mounts dev, proc and sys directories. It then prints a welcome message and runs sh to open a shell.

You can put ANY executable as init file as long as it is statically linked. You might also want to mount dev, sys and proc directories when the program starts using mount.h header. Last thing we need to do is to create the filesystem itself... To do so, run these commands inside _install directory.

find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz

This will make the file initramfs.cpio.gz in upper directory.

Testing The Compiled Kernel With QEMU

Before creating the ISO file let us check if the kernel is fine or not. To do so, we use QEMU. Just run the following command: (make sure that you change the path of bzImage and initramfs)

qemu-system-x86_64 -kernel bzImage -initrd initramfs.cpio.gz
qemu-system-x86_64 -kernel ../../linux-6.7.1/arch/x86/boot/bzImage -initrd ../initramfs.cpio.gz

QEMU runs the our Linux kernel.

Running our Linux in QEMU

Now that we know that our kernel boots, we can create a bootable ISO for it.

Creating a Bootable ISO

Create a folder somewhere with any name. I name it iso, then create a folder called boot in it and inside boot create a folder called grub. Then copy bzImage and initramfs.cpio.gz into the boot folder.

mkdir iso
mkdir iso/boot
mkdir iso/boot/grub
cp ../linux-6.7.1/arch/x86_64/boot/bzImage boot/
cp ../busybox-1.36.1/initramfs.cpio.gz  boot/

Creating the Grub Config File

We will use grub-mkrescue to create our bootable ISO. But before doing so, we have to know if our current host is booted with UEFI or BIOS. To do so, check if the folder /sys/firmware/efi exists on your system or not. If it does, your computer uses UEFI otherwise it’s BIOS. So why knowing this is important? The grub-mkrescue uses the currently installed grub stuff to create the ISO image. This means that if your operating system is booted in BIOS, the chances are that the ISO created from grub-mkrescue does not support UEFI at all. In some cases, UEFI motherboards support booting BIOS images using CMS. But that is not always the case. If you want to make images for BIOS from UEFI host or vice versa, I suggest you to create a Debian virtual machine in VirtualBox. VirtualBox supports both BIOS and UEFI in it’smotherboard settings. After choosing the appropriate one, install Debian (net install is sufficient) and move the folder which contains boot and grub folders to virtual machine. Then continue reading the guide to configure the grub and create the ISO file.

Now we have to configure grub itself. Create a file named grub.cfg in grub folder of the boot folder. If your host is booted using BIOS (and thus the output ISO is BIOS too) put these lines in the config file:

set default=0
set timeout=10
menuentry 'myos' --class os {
insmod gzio
insmod part_msdos
linux /boot/bzImage
initrd /boot/initramfs.cpio.gz
}

If you are using UEFI, put these lines in it:

set default=0
set timeout=10
# Load EFI video drivers. This device is EFI so keep the
# video mode while booting the linux kernel.
insmod efi_gop
insmod font
if loadfont /boot/grub/fonts/unicode.pf2
then
insmod gfxterm
set gfxmode=auto
set gfxpayload=keep
terminal_output gfxterm
fi
menuentry 'myos' --class os {
insmod gzio
insmod part_msdos
linux /boot/bzImage
initrd /boot/initramfs.cpio.gz
}

At last run this command to create the ISO file. Replace the last argument with the folder name which you created at first step.

grub-mkrescue -o myos.iso iso/

Testing The ISO With VirtualBox

Before testing the ISO on a real computer, boot it in VirtualBox. To do so, make a new virtual machine and choose the ISO you have just created as the content of optical disk. Start the operating system. You must see the grub menu and then the operating system must boot. Do not forget the select EFI in motherboard settings if needed.

Method 2

Set Up the Build Environment:

sudo apt update
sudo apt install build-essential bison flex libncurses-dev xorriso

Create a Directory Structure:

mkdir -p ~/custom_linux/fs/
mkdir -p ~/custom_linux/fs/{bin,sbin,etc,dev,proc,sys,tmp,var,lib/init/rw}

Build and configure the kernel, download the Linux kernel source code from kernel.org and extract the source code and configure it:

# Replace with updated version numbers when required
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.7.1.tar.xz
tar -xvf linux-6.7.1.tar.xz 
cd linux-6.7.1
make defconfig
make menuconfig
make

After the build completes, you should have a bzImage in the arch/x86_64/boot directory.

# Set hostname
echo "yourhostname" > /etc/hostname

# Set root password
passwd

# Install required packages (customize as needed)
apt-get update

# Install kernel and initrd
apt-get install -y linux-generic

# Update grub
update-grub

# Exit the chroot environment
exit

Create ISO Structure:

cp -r ~/custom_linux/rootfs/boot ~/custom_linux/iso/

Create GRUB Configuration:

Create a file ~/custom_linux/iso/boot/grub/grub.cfg with the following content:

Important: replace <kernel-version> with the appropriate kernel version. And replace the root= with your partition

cat << EOF > ~/custom_linux/iso/boot/grub/grub.cfg
set timeout=10
set default=0

menuentry "Boot to Bash" {
    linux /boot/vmlinuz-5.4.0-26-generic root=/dev/sda ro
    initrd /boot/initrd.img-5.4.0-26-generic
}
EOF

Install GRUB:

sudo chmod +r /home/x/custom_linux/iso/boot/vmlinuz-5.4.0-26-generic
sudo grub-mkrescue --output=custom_linux.iso ~/custom_linux/iso

Test the ISO: Use a virtual machine or a tool like QEMU to test the generated ISO.

qemu-system-x86_64 -cdrom custom_linux.iso -m 512M

  

📝 📜 ⏱️ ⬆️