I am back to doing some kernel hacking. I am building my kernel as I write this post. Every time I try to build a kernel, I have to setup the whole environment again which requires a bunch of google searches and skimming a bunch of tutorials. I am writing this post to consolidate all of that so that the next time I pick this up, I don’t have to search everywhere.
Getting the source
From kenrel.org or from apt-get
both work.
$ apt-get source linux-image-$(uname -r)
Building the kernel
$ tar -xvf linux_3.13.0.orig.tar.gz
$ cd linux-3.13.0/
$ make bzImage
$ make_modules
This should give you a kernel image in ./arch/x86_64/boot/bzImage
. Now we need to create
an initrd which we will boot into. For this I use busybox. Make sure you have the statically
linked version of the busybox
binary and place it in the root of the kernel source.
Building the initrd
Save the following script in the root of the kernel source with the filename create_initrd.sh
.
This will build the scafollding of our initrd
mkdir -p initramfs/bin
mkdir -p initramfs/etc
touch initramfs/init
touch initramfs/etc/fstab
cp busybox initramfs/bin
cd initramfs/bin
ln -s busybox sh
The resultant directory structure will be:
initramfs
├── bin
│ ├── busybox
│ └── sh -> busybox
├── etc
│ └── fstab
├── init
Edit the fstab
file and add the following lines
proc /proc proc rw,noexec,nosuid,nodev 0 0
sysfs /sys sysfs rw,noexec,nosuid,nodev 0 0
Edit the init
file and add the following lines
#!/bin/sh
# Mount things needed by this script
mount -t proc proc /proc
mount -t sysfs sysfs /sys
# Create all the symlinks to /bin/busybox
busybox --install -s
# Create device nodes
mknod /dev/null c 1 3
mknod /dev/tty c 5 0
mdev -s
create a file build_initrd.sh
which will be run everytime there is an update
to initrd. This may be useful if you add your program to initrd and want to
run the kernel with the new program. This goes in the root of your kernel source
cd initramfs
find . | cpio -H newc -o > ../initramfs.cpio
cd ..
cat initramfs.cpio | gzip > initramfs.igz
Running the kernel with KVM
Finally we are ready with our kernel and initrd. Create the file run_kernel.sh
which will run the kenrnel in your terminal.
kvm -kernel arch/x86_64/boot/bzImage \
-initrd initramfs.gz \
-chardev stdio,id=stdio,mux=on \
-device virtio-serial-pci \
-device virtconsole,chardev=stdio \
-mon chardev=stdio \
-display none \
-append 'console=hvc0'\
-s
Debugging using remote gdb
The above command uses KVM to run the kernel and displays the output in the
current terminal. It also starts a gdb server for debugging which is listening
on port tcp:1234
. You can use a remote gdb
to debug.
$ gdb vmlinux
(gdb) set architecture i386:x86-64
(gdb) target remote :1234
That’s it. Once the kernel is up and running, you can attach the debugger and
debug. If you want to add any modules, throw them in the initramfs directory,
update the init
script to load them when the kernel boots up, rebuild the
initramfs and you are set.
References
[1] http://jootamam.net/howto-initramfs-image.htm
[2] https://blog.nelhage.com/2013/12/lightweight-linux-kernel-development-with-kvm/