<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>kernel &amp;mdash; musicmatzes blog</title>
    <link>https://beyermatthias.de/tag:kernel</link>
    <description></description>
    <pubDate>Mon, 12 Oct 2026 06:22:04 +0200</pubDate>
    <item>
      <title>Setup for linux kernel dev using qemu</title>
      <link>https://beyermatthias.de/setup-for-linux-kernel-dev-using-qemu</link>
      <description>&lt;![CDATA[I could not think of a better title, I&#39;m sorry.&#xA;&#xA;These are notes how to create a kernel which can be booted in qemu and pass a&#xA;drive to it which has loadable kernel modules.&#xA;&#xA;!-- more --&#xA;&#xA;The idea&#xA;&#xA;I wanted to play around with the linux kernel and write a minimal filesystem&#xA;inside the kernel tree. I wanted to boot the kernel in a QEMU, as I do not&#xA;want to mess with my running kernel.&#xA;&#xA;Here are the steps I did (on a debian VM I run on my universitys&#xA;infrastructure).&#xA;&#xA;Setup&#xA;&#xA;sudo apt-get install build-essential bc git gcc&#xA;git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git&#xA;cd linux&#xA;make x8664defconfig&#xA;make kvmconfig&#xA;make menuconfig&#xA;&#xA;The last step brings up the kernel configuration interface, which I used to&#xA;enable SATA&#xA;(Device Drivers -  Serial ATA and Parallel ATA drivers (libata) -  Generic ATA support)&#xA;support which is needed to be able to mount a device into the qemu instance,&#xA;where we can put things to play around with in the VM.&#xA;&#xA;I then did a make -j 16 (if you have not 8 cores, use a lower number).&#xA;&#xA;While the kernel compiled, I created a busybox initramfs. I used&#xA;this blog article for how to do it.&#xA;I&#39;ll dump in the commands from the blog article, for detailed information, go&#xA;and read it, it&#39;s a really good article. I didn&#39;t do the speed-optimizing&#xA;things, as the QEMU boots fast enough for me (~3 seconds).&#xA;&#xA;(I used the latest busybox, but I don&#39;t see why it should work with the one&#xA;from the article, which is about two versions old)&#xA;&#xA;curl http://busybox.net/downloads/busybox-1.23.2.tar.bz2 | tar xjf -&#xA;cd busybox-1.23.2&#xA;mkdir -pv /tmp/obj/busybox-x86&#xA;make O=/tmp/obj/busybox-x86 defconfig&#xA;make O=/tmp/obj/busybox-x86 menuconfig # See below why&#xA;cd /tmp/obj/busybox-x86&#xA;make -j 16&#xA;&#xA;it does not install in your system, so you can execute this without fear&#xA;make install&#xA;&#xA;mkdir -p /tmp/initramfs/x86-busybox&#xA;cd /tmp/initramfs/x86-busybox&#xA;mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin}}&#xA;cp -av /tmp/obj/busybox-x86/install/* .&#xA;&#xA;now edit the init script&#xA;vim init&#xA;&#xA;You have to enable busybox build as static binary (with the menuconfig&#xA;part).&#xA;&#xA;The init script I use:&#xA;&#xA;!/bin/sh&#xA;&#xA;echo &#34;INIT SCRIPT&#34;&#xA;&#xA;mount -t proc none /proc&#xA;mount -t sysfs none /sys&#xA;mount -t debugfs none /sys/kernel/debug&#xA;&#xA;mkdir /tmp&#xA;mount -t tmpfs none /tmp&#xA;&#xA;mdev -s # We need this to find /dev/sda later&#xA;&#xA;echo -e &#34;\nBoot took $(cut -d&#39; &#39; -f1 /proc/uptime) seconds\n&#34;&#xA;&#xA;exec /bin/sh&#xA;&#xA;The init script boots into a /bin/sh. We can now build the initramfs with&#xA;it:&#xA;&#xA;chmod +x init&#xA;find . -print0 \&#xA;    | cpio --null -ov --format=newc \&#xA;    | gzip -9   /tmp/initramfs-busybox-x86.cpio.gz&#xA;&#xA;Try it out (1)&#xA;&#xA;Now we can try it out, whether the kernel boots and we get out shell:&#xA;&#xA;In the kernel tree:&#xA;qemu-system-x8664 \&#xA;    -kernel arch/x8664/boot/bzImage \&#xA;    -initrd /tmp/initramfs-busybox-x86.cpio.gz \&#xA;    -nographic -append &#34;console=ttyS0&#34;&#xA;&#xA;We should see some output like this:&#xA;&#xA;[...]&#xA;[    7.170702] Freeing unused kernel memory: 1200K (ffffffff81f55000 - ffffffff82081000)&#xA;[    7.171539] Write protecting the kernel read-only data: 14336k&#xA;[    7.177328] Freeing unused kernel memory: 816K (ffff880001934000 - ffff880001a00000)&#xA;[    7.219360] Freeing unused kernel memory: 1116K (ffff880001ce9000 - ffff880001e00000)&#xA;INIT SCRIPT&#xA;mount: mounting none on /sys/kernel/config failed: No such file or directory&#xA;mount: mounting none on /tmp failed: No such file or directory&#xA;&#xA;Boot took 7.33 seconds&#xA;&#xA;/bin/sh: can&#39;t access tty; job control turned off&#xA;/ # [    7.630681] input: ImExPS/2 BYD TouchPad as /devices/platform/i8042/serio1/input/input3&#xA;&#xA;/ #&#xA;&#xA;(Yes, the output is slightly messed up... but hey! We just booted a linux&#xA;kernel in a QEMU!&#xA;&#xA;Load the kernel module&#xA;&#xA;We can now create a kernel module in the linux kernel tree:&#xA;&#xA;In the kernel tree&#xA;git checkout -b my-module&#xA;mkdir fs/iamcoolfs/ # because I like filesystems&#xA;cat &lt;EOS  ./fs/iamcoolfs/Kconfig&#xA;config COOLFS&#xA;        tristate &#34;COOLFS support&#34;&#xA;        help&#xA;          Private FS for playing and learning FS programming&#xA;&#xA;          This will definitively eat everything you put into it.&#xA;&#xA;EOS&#xA;cat &lt;EOS  ./fs/iamcoolfs/Makefile&#xA;#&#xA;Makefile for the linux mb-filesystem routines.&#xA;&#xA;obj-$(CONFIGMBFS) += coolfs.o&#xA;EOS&#xA;cat &lt;EOS  ./fs/iamcoolfs/coolfs.c&#xA;include linux/init.h&#xA;include linux/module.h&#xA;&#xA;static int _init coolfsinit(void)&#xA;{&#xA;        prdebug(&#34;cool module loaded\n&#34;);&#xA;        return 0;&#xA;}&#xA;&#xA;static void exit coolfsfini(void)&#xA;{&#xA;        prdebug(&#34;cool module unloaded\n&#34;);&#xA;}&#xA;&#xA;moduleinit(coolfsinit);&#xA;moduleexit(coolfsfini);&#xA;&#xA;MODULELICENSE(&#34;GPL&#34;);&#xA;MODULEAUTHOR(&#34;YOUR NAME GOES HERE&#34;);&#xA;&#xA;EOS&#xA;&#xA;This creates all the files we need for a minimal module. Because I like&#xA;filesystems and I really want to implement a minimal filesystem, I chose to&#xA;create the files in ./fs, but I guess_ it shouldn&#39;t matter.&#xA;&#xA;Make sure you adapt the fs/Kconfig file to find your new module! Put&#xA;&#xA;source &#34;fs/coolfs/Kconfig&#34;&#xA;&#xA;into it.&#xA;&#xA;Now you can execute make menuconfig and find the configuration option for&#xA;your new module.&#xA;We can also simply make M=fs/coolfs to build the module.&#xA;Now we create a (ext2) disk where we can cp the module to, so we can mount&#xA;that disk into our QEMU and use the module there:&#xA;&#xA;dd if=/dev/zero of=/tmp/disk bs=4M count=100&#xA;sudo mkfs.ext2 /tmp/disk # you could also try ext4, for example&#xA;mkdir /tmp/disk-mount&#xA;sudo mount /tmp/disk /tmp/disk-mount&#xA;cp fs/coolfs/coolfs.ko /tmp/disk-mount/&#xA;sudo umount /tmp/disk-mount&#xA;&#xA;Try it out (2)&#xA;&#xA;And when we boot our QEMU now with -hda /tmp/disk, we can find /dev/sda in&#xA;the booted instance and mount that:&#xA;&#xA;In the booted VM&#xA;mkdir sda&#xA;mount /dev/sda ./sda&#xA;ls sda&#xA;&#xA;Happy FS dev!&#xA;&#xA;tags:  #c #linux #open source #programming #software #testing #kernel&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>I could not think of a better title, I&#39;m sorry.</p>

<p>These are notes how to create a kernel which can be booted in qemu and pass a
drive to it which has loadable kernel modules.</p>



<h1 id="the-idea" id="the-idea">The idea</h1>

<p>I wanted to play around with the linux kernel and write a minimal filesystem
inside the kernel tree. I wanted to boot the kernel in a QEMU, as I do not
want to mess with my running kernel.</p>

<p>Here are the steps I did (on a debian VM I run on my universitys
infrastructure).</p>

<h1 id="setup" id="setup">Setup</h1>

<pre><code class="language-bash">sudo apt-get install build-essential bc git gcc
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
make x86_64_defconfig
make kvmconfig
make menuconfig
</code></pre>

<p>The last step brings up the kernel configuration interface, which I used to
enable SATA
(<code>Device Drivers -&gt; Serial ATA and Parallel ATA drivers (libata) -&gt; Generic ATA support</code>)
support which is needed to be able to mount a device into the qemu instance,
where we can put things to play around with in the VM.</p>

<p>I then did a <code>make -j 16</code> (if you have not 8 cores, use a lower number).</p>

<p>While the kernel compiled, I created a busybox initramfs. I used
<a href="https://mgalgs.github.io/2015/05/16/how-to-build-a-custom-linux-kernel-for-qemu-2015-edition.html">this blog article for how to do it</a>.
I&#39;ll dump in the commands from the blog article, for detailed information, go
and read it, it&#39;s a really good article. I didn&#39;t do the speed-optimizing
things, as the QEMU boots fast enough for me (~3 seconds).</p>

<p>(I used the latest busybox, but I don&#39;t see why it should work with the one
from the article, which is about two versions old)</p>

<pre><code class="language-bash">curl http://busybox.net/downloads/busybox-1.23.2.tar.bz2 | tar xjf -
cd busybox-1.23.2
mkdir -pv /tmp/obj/busybox-x86
make O=/tmp/obj/busybox-x86 defconfig
make O=/tmp/obj/busybox-x86 menuconfig # See below why
cd /tmp/obj/busybox-x86
make -j 16

# it does not install in your system, so you can execute this without fear
make install

mkdir -p /tmp/initramfs/x86-busybox
cd /tmp/initramfs/x86-busybox
mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin}}
cp -av /tmp/obj/busybox-x86/_install/* .

# now edit the init script
vim init
</code></pre>

<p>You have to enable busybox build as static binary (with the <code>menuconfig</code>
part).</p>

<p>The <code>init</code> script I use:</p>

<pre><code class="language-bash">#!/bin/sh

echo &#34;INIT SCRIPT&#34;

mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug

mkdir /tmp
mount -t tmpfs none /tmp

mdev -s # We need this to find /dev/sda later

echo -e &#34;\nBoot took $(cut -d&#39; &#39; -f1 /proc/uptime) seconds\n&#34;

exec /bin/sh
</code></pre>

<p>The <code>init</code> script boots into a <code>/bin/sh</code>. We can now build the initramfs with
it:</p>

<pre><code class="language-bash">chmod +x init
find . -print0 \
    | cpio --null -ov --format=newc \
    | gzip -9 &gt; /tmp/initramfs-busybox-x86.cpio.gz
</code></pre>

<h1 id="try-it-out-1" id="try-it-out-1">Try it out (1)</h1>

<p>Now we can try it out, whether the kernel boots and we get out shell:</p>

<pre><code class="language-bash"># In the kernel tree:
qemu-system-x86_64 \
    -kernel arch/x86_64/boot/bzImage \
    -initrd /tmp/initramfs-busybox-x86.cpio.gz \
    -nographic -append &#34;console=ttyS0&#34;
</code></pre>

<p>We should see some output like this:</p>

<pre><code>[...]
[    7.170702] Freeing unused kernel memory: 1200K (ffffffff81f55000 - ffffffff82081000)
[    7.171539] Write protecting the kernel read-only data: 14336k
[    7.177328] Freeing unused kernel memory: 816K (ffff880001934000 - ffff880001a00000)
[    7.219360] Freeing unused kernel memory: 1116K (ffff880001ce9000 - ffff880001e00000)
INIT SCRIPT
mount: mounting none on /sys/kernel/config failed: No such file or directory
mount: mounting none on /tmp failed: No such file or directory

Boot took 7.33 seconds

/bin/sh: can&#39;t access tty; job control turned off
/ # [    7.630681] input: ImExPS/2 BYD TouchPad as /devices/platform/i8042/serio1/input/input3

/ #
</code></pre>

<p>(Yes, the output is slightly messed up... but hey! We just booted a linux
kernel in a QEMU!</p>

<h1 id="load-the-kernel-module" id="load-the-kernel-module">Load the kernel module</h1>

<p>We can now create a kernel module in the linux kernel tree:</p>

<pre><code class="language-bash"># In the kernel tree
git checkout -b my-module
mkdir fs/iamcoolfs/ # because I like filesystems
cat &lt;&lt;EOS &gt; ./fs/iamcoolfs/Kconfig
config COOL_FS
        tristate &#34;COOLFS support&#34;
        help
          Private FS for playing and learning FS programming

          This will definitively eat everything you put into it.

EOS
cat &lt;&lt;EOS &gt; ./fs/iamcoolfs/Makefile
#
# Makefile for the linux mb-filesystem routines.
#

obj-$(CONFIG_MB_FS) += coolfs.o
EOS
cat &lt;&lt;EOS &gt; ./fs/iamcoolfs/coolfs.c
#include &lt;linux/init.h&gt;
#include &lt;linux/module.h&gt;

static int __init coolfs_init(void)
{
        pr_debug(&#34;cool module loaded\n&#34;);
        return 0;
}

static void __exit coolfs_fini(void)
{
        pr_debug(&#34;cool module unloaded\n&#34;);
}

module_init(coolfs_init);
module_exit(coolfs_fini);

MODULE_LICENSE(&#34;GPL&#34;);
MODULE_AUTHOR(&#34;&lt;YOUR NAME GOES HERE&gt;&#34;);

EOS
</code></pre>

<p>This creates all the files we need for a minimal module. Because I like
filesystems and I really want to implement a minimal filesystem, I chose to
create the files in <code>./fs</code>, but I <em>guess</em> it shouldn&#39;t matter.</p>

<p>Make sure you adapt the <code>fs/Kconfig</code> file to find your new module! Put</p>

<pre><code>source &#34;fs/coolfs/Kconfig&#34;
</code></pre>

<p>into it.</p>

<p>Now you can execute <code>make menuconfig</code> and find the configuration option for
your new module.
We can also simply <code>make M=fs/coolfs</code> to build the module.
Now we create a (ext2) disk where we can <code>cp</code> the module to, so we can mount
that disk into our QEMU and use the module there:</p>

<pre><code class="language-bash">dd if=/dev/zero of=/tmp/disk bs=4M count=100
sudo mkfs.ext2 /tmp/disk # you could also try ext4, for example
mkdir /tmp/disk-mount
sudo mount /tmp/disk /tmp/disk-mount
cp fs/coolfs/coolfs.ko /tmp/disk-mount/
sudo umount /tmp/disk-mount
</code></pre>

<h1 id="try-it-out-2" id="try-it-out-2">Try it out (2)</h1>

<p>And when we boot our QEMU now with <code>-hda /tmp/disk</code>, we can find <code>/dev/sda</code> in
the booted instance and mount that:</p>

<pre><code class="language-bash"># In the booted VM
mkdir sda
mount /dev/sda ./sda
ls sda
</code></pre>

<p>Happy FS dev!</p>

<p>tags:  <a href="https://beyermatthias.de/tag:c" class="hashtag"><span>#</span><span class="p-category">c</span></a> <a href="https://beyermatthias.de/tag:linux" class="hashtag"><span>#</span><span class="p-category">linux</span></a> <a href="https://beyermatthias.de/tag:open" class="hashtag"><span>#</span><span class="p-category">open</span></a> source <a href="https://beyermatthias.de/tag:programming" class="hashtag"><span>#</span><span class="p-category">programming</span></a> <a href="https://beyermatthias.de/tag:software" class="hashtag"><span>#</span><span class="p-category">software</span></a> <a href="https://beyermatthias.de/tag:testing" class="hashtag"><span>#</span><span class="p-category">testing</span></a> <a href="https://beyermatthias.de/tag:kernel" class="hashtag"><span>#</span><span class="p-category">kernel</span></a></p>
]]></content:encoded>
      <guid>https://beyermatthias.de/setup-for-linux-kernel-dev-using-qemu</guid>
      <pubDate>Tue, 01 Nov 2016 16:37:55 +0100</pubDate>
    </item>
  </channel>
</rss>