Compiling the Linux kernel and creating a bootable ISO
This revision is from 2024/01/22 08:59. 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 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