Saturday 16 September 2023

Building and Running the Linux Kernel Using Qemu: In a Nutshell

xb@dnxb:~$ sudo apt update
# Install the necessary packages for building the Linux kernel:
xb@dnxb:~$ sudo apt-get install build-essential libncurses5-dev bison flex libssl-dev libelf-dev
# libvirt-bin is now split into libvirt-daemon-system and libvirt-clients.
xb@dnxb:~$ sudo apt install qemu-kvm qemu virt-manager virt-viewer libvirt-daemon-system libvirt-clients

# To resolve the error "pahole (pahole) is not available" while making the kernel.
xb@dnxb:~$ sudo apt install dwarves
# Test in Ubuntu, not using Linux source at github
xb@dnxb:~$ sudo apt install linux-source
# After the installation, the source is typically located in `/usr/src/`
xb@dnxb:~$ cd /usr/src/
# You'll need to modify the subsequent commands "...5.4.0..." based on the latest version.
xb@dnxb:/usr/src$ cd linux-source-5.4.0
xb@dnxb:/usr/src/linux-source-5.4.0$ cp linux-source-5.4.0.tar.bz2 ~/Downloads/
xb@dnxb:/usr/src/linux-source-5.4.0$ cd ~/Downloads/

# OR use `pv linux-source-5.4.0.tar.bz2 | tar -xjf-` to monitor the extraction progress.
xb@dnxb:~/Downloads$ tar xjf linux-source-5.4.0.tar.bz2
# ... If you use Nautilus for extraction, you need to copy it from /usr/src/ to a regular user path before extracting.
# ... However, when using Nautilus, you might need to eliminate any redundant directories that were created by mistake. Eliminate them early, as changes in directory timestamps seem to slow down the remaking process.
# e.g. xb@dnxb:~/Downloads/redundant_folder/linux-source-5.4.0$

# To fix `No rule to make target 'debian/canonical-certs.pem', needed by 'certs/x509_certificate_list'. Stop.` when make kernel from Ubuntu:
xb@dnxb:~/Downloads/linux-source-5.4.0$ cp -r /usr/src/linux-source-5.4.0/debian ./
xb@dnxb:~/Downloads/linux-source-5.4.0$ cp -r /usr/src/linux-source-5.4.0/debian.master ./

# As an initial modification trial, add "hello world" after `pr_notice("%s", linux_banner);`:
xb@dnxb:~/Downloads/linux-source-5.4.0$ grep -i hello init/main.c -C 2
pr_notice("%s", linux_banner);
pr_notice("Hello, World! from the Kernel by hole\n");

# ARCH=x86_64 is optional, while the default ARCH=x86 lets you toggle off the 64-bit kernel in the menu.
# Just click <Exit> then [Save]. If re-edit main.c to add print, no need run this:
xb@dnxb:~/Downloads/linux-source-5.4.0$ make menuconfig ARCH=x86_64
xb@dnxb:~/Downloads/linux-source-5.4.0$ make -j$(nproc) ARCH=x86_64
# If you re-edit main.c to add a print, you don't need to run `make modules`, just `make -j$(nproc) ARCH=x86_64 && make bzImage -j$(nproc) ARCH=x86_64`
# "Section mismatch" warnings can be safely ignored.
# Can type '?' to see details if seeing "[N/m/y/?] (NEW) ?", simply "y"
xb@dnxb:~/Downloads/linux-source-5.4.0$ make modules -j$(nproc) ARCH=x86_64
xb@dnxb:~/Downloads/linux-source-5.4.0$ make bzImage -j$(nproc) ARCH=x86_64

# Despite the ARCH=x86_64 setting, the kernel image path is ./arch/x86/boot/bzImage.
# The reason is the unified source code for x86 and x86_64 in the Linux kernel.
# x86 covering both x86 & x86_64 through scripts/subarch.include and .config .
# The x86_64 path is simply a symbolic link to x86.
# Use the x86 path to qemu as it's the real location for the kernel image.
xb@dnxb:~/Downloads/linux-source-5.4.0$ file ./arch/x86_64/boot/bzImage
./arch/x86_64/boot/bzImage: symbolic link to ../../x86/boot/bzImage
xb@dnxb:~/Downloads/linux-source-5.4.0$ realpath ./arch/x86/boot/bzImage

# Create an Initramfs:
# For a simple test, you can create a very basic initramfs that only has a /init script. Here's an example:
# replace 'hole' with your preferred directory name
xb@dnxb:~/Downloads/linux-source-5.4.0$ mkdir hole; cd hole/
xb@dnxb:~/Downloads/linux-source-5.4.0/hole$ mkdir -p myinitramfs
xb@dnxb:~/Downloads/linux-source-5.4.0/hole$ cd myinitramfs/
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ mkdir -p bin sbin etc tmp proc sys usr/bin usr/sbin
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ echo -e '#!/bin/sh\nmount -t proc none /proc\nmount -t sysfs none /sys\nexec /bin/sh' > init
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ chmod +x init
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ cd ..

# You can visit to get the latest version. You'll need to modify the subsequent commands "...1.36.1..." based on the latest version:
xb@dnxb:~/Downloads/linux-source-5.4.0/hole$ wget
xb@dnxb:~/Downloads/linux-source-5.4.0/hole$ tar xjf busybox-1.36.1.tar.bz2
xb@dnxb:~/Downloads/linux-source-5.4.0/hole$ cd busybox-1.36.1/
# Load the default configuration:
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/busybox-1.36.1$ make defconfig
# "Settings" -> "Build Options" -> "Build static binary (no shared libs)" and press 'Y' otherwise will get "Kernel panic - not syncing: No working init found." after boot kernel.
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/busybox-1.36.1$ make menuconfig
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/busybox-1.36.1$ make -j$(nproc)

# Now, create the initramfs archive. CPIO is the preferred method because it effectively duplicates a file system, backs it up, and preserves unique file features like hardlinks and FIFOs:
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/busybox-1.36.1$ cd ../myinitramfs
# Use BusyBox as the shell program for initramfs:
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ cp ../busybox-1.36.1/busybox bin/
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ cd bin/
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs/bin$ ln -s busybox sh
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs/bin$ ln -s busybox mount
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs/bin$ cd ..
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ find . | cpio -H newc -o | gzip > ../myinitramfs.cpio.gz
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ cd ../..

# Boot the kernel with qemu. You might need to press Enter to access the shell. To exit, use "Ctrl+a", release it, then press "x". If there's an issue, use killall qemu-system-x86_64.
# append "panic=10" will reboot 10 seconds after kernel panic
xb@dnxb:~/Downloads/linux-source-5.4.0$ qemu-system-x86_64 -kernel /home/xiaobai/Downloads/linux-source-5.4.0/arch/x86/boot/bzImage -initrd /home/xiaobai/Downloads/linux-source-5.4.0/myinitramfs.cpio.gz -append "console=ttyS0 earlyprintk=serial,ttyS0,115200 debug" -nographic

No comments:

Post a Comment