<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Xabier Etxezarreta]]></title><description><![CDATA[Low-level thoughts on high-level problems. Linux kernel, C, Rust, and everything in between. Living in Ring 0 so you don't have to.]]></description><link>https://blog.xetxezarreta.com</link><image><url>https://substackcdn.com/image/fetch/$s_!yikH!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe47a7e43-691f-4a53-8c1e-8a010c11e2c2_1280x1280.png</url><title>Xabier Etxezarreta</title><link>https://blog.xetxezarreta.com</link></image><generator>Substack</generator><lastBuildDate>Mon, 25 May 2026 13:47:39 GMT</lastBuildDate><atom:link href="https://blog.xetxezarreta.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Xabier Etxezarreta]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[xetxezarreta@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[xetxezarreta@substack.com]]></itunes:email><itunes:name><![CDATA[Xabier Etxezarreta]]></itunes:name></itunes:owner><itunes:author><![CDATA[Xabier Etxezarreta]]></itunes:author><googleplay:owner><![CDATA[xetxezarreta@substack.com]]></googleplay:owner><googleplay:email><![CDATA[xetxezarreta@substack.com]]></googleplay:email><googleplay:author><![CDATA[Xabier Etxezarreta]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Building and Booting Your Own Linux Kernel on Windows with WSL2 and QEMU]]></title><description><![CDATA[A step-by-step guide to downloading the source, compiling under WSL2, and running your custom kernel in a virtual environment without breaking your host system.]]></description><link>https://blog.xetxezarreta.com/p/building-and-booting-your-own-linux</link><guid isPermaLink="false">https://blog.xetxezarreta.com/p/building-and-booting-your-own-linux</guid><dc:creator><![CDATA[Xabier Etxezarreta]]></dc:creator><pubDate>Sat, 21 Mar 2026 08:43:52 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1ErS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>Introduction</h3><p>The Linux kernel is the heart of millions of devices, from the phone in your pocket to the servers powering the web. For many developers and tech enthusiasts, the kernel feels like a &#8220;black box&#8221;, complex and untouchable.</p><p>But it&#8217;s just code. And you can compile it yourself.</p><p>Historically, learning to develop kernels required a second machine for testing because a single mistake could result in an unbootable system. Today, thanks to Windows Subsystem for Linux 2 (WSL2) and virtualization/emulation tools like QEMU, you can build and test custom kernels safely, quickly, and entirely within your Windows environment.</p><p>Whether you are aiming to become a kernel contributor, curious about how operating systems work, this guide will take you from zero to booting your own custom Linux kernel.</p><h3>The Architecture of Our Laboratory</h3><p>Before we start typing commands, let&#8217;s understand how our tools fit together:</p><ol><li><p><strong>Windows Host:</strong> Your main operating system.</p></li><li><p><strong>WSL2 (Ubuntu):</strong> WSL2 actually runs a real Linux kernel inside a lightweight utility VM. We will use this as our <strong>Build Environment</strong>. We will download the tools and source code here because Linux code compiles best on Linux.</p></li><li><p><strong>QEMU:</strong> A machine emulator. Instead of replacing the WSL2 kernel (which could break your WSL setup), we will use QEMU inside WSL2 to create a sandbox virtual machine. We will boot our newly compiled kernel inside this sandbox.</p></li></ol><h3>Phase 1: Prepping the Build Environment</h3><p>I will assume you are using Ubuntu inside WSL2. If you haven&#8217;t enabled it yet, simply open PowerShell as Administrator, run <code>wsl --install</code>, and restart your machine.</p><h4>1. Resource Allocation (Optional but Recommended)</h4><p>Compiling a kernel is computationally heavy. By default, WSL2 might not use all your CPU cores or RAM. You can create a file named <code>.wslconfig</code> in your Windows user folder (e.g., <code>C:\Users\YourName\.wslconfig</code>) to give WSL2 more power:</p><pre><code><code>[wsl2]
memory=8GB
processors=4</code></code></pre><blockquote><p><em>(Restart WSL via PowerShell with </em><code>wsl --shutdown</code><em> for this to take effect).</em></p></blockquote><h4>2. Create the Virtual Machine</h4><pre><code><code>wsl --install --name kernel-dev</code></code></pre><h4>3. Installing Dependencies</h4><p>Open your WSL2 terminal and update your package lists:</p><pre><code><code>sudo apt update &amp;&amp; sudo apt upgrade -y</code></code></pre><p>Next, install the required toolchain. This includes compilers (<code>gcc</code>, <code>make</code>), parsers (<code>bison</code>, <code>flex</code>), libraries for the configuration UI (<code>libncurses-dev</code>), and our emulator (<code>qemu-system-x86</code>):</p><pre><code><code>sudo apt install -y build-essential libncurses-dev bison flex libssl-dev libelf-dev \
qemu-system-x86 qemu-utils fdisk busybox-static git wget cpio</code></code></pre><h3>Phase 2: Acquiring the Source Code</h3><p>Kernel source code lives on <a href="https://www.kernel.org/">kernel.org</a>. You&#8217;ll see several branches:</p><ul><li><p><strong>Mainline:</strong> The bleeding edge. Where new features land first.</p></li><li><p><strong>Stable:</strong> Latest stable version for general use.</p></li><li><p><strong>Longterm:</strong> Maintained for years, highly stable.</p></li></ul><p>We will use a git clone of the <strong>Stable</strong> tree. We use the <code>--depth 1</code> flag to download only the very latest snapshot of the code, ignoring decades of git history. This saves gigabytes of space and network bandwidth.</p><pre><code><code># Move to your home directory
cd ~

# Create a workspace
mkdir kernel-dev
cd kernel-dev

# Clone the stable branch (this may take a few minutes)
# --depth 1: Creates a "shallow" clone (no history).
# --branch linux-rolling-stable: Targets the auto-updating stable release.
git clone --depth 1 --branch linux-rolling-stable https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git

# Move into the source directory
cd linux</code></code></pre><h3>Phase 3: Configuration (<code>menuconfig</code>)</h3><p>The Linux kernel is incredibly modular. It supports thousands of different hardware devices, file systems, and networking protocols. Before compiling, you have to tell the build system exactly what to include.</p><h4>1. The Default Configuration</h4><p>Since we are building a basic kernel to run in a QEMU virtual machine (which emulates standard x86_64 hardware), we can start with a default template.</p><pre><code><code>make x86_64_defconfig</code></code></pre><p>This generates a hidden file called <code>.config</code> containing thousands of default settings.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hzDr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11ce6c6e-42dc-481d-8547-7777c7c154ca_880x533.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hzDr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11ce6c6e-42dc-481d-8547-7777c7c154ca_880x533.png 424w, https://substackcdn.com/image/fetch/$s_!hzDr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11ce6c6e-42dc-481d-8547-7777c7c154ca_880x533.png 848w, https://substackcdn.com/image/fetch/$s_!hzDr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11ce6c6e-42dc-481d-8547-7777c7c154ca_880x533.png 1272w, https://substackcdn.com/image/fetch/$s_!hzDr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11ce6c6e-42dc-481d-8547-7777c7c154ca_880x533.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hzDr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11ce6c6e-42dc-481d-8547-7777c7c154ca_880x533.png" width="880" height="533" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/11ce6c6e-42dc-481d-8547-7777c7c154ca_880x533.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:533,&quot;width&quot;:880,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:66297,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.xetxezarreta.com/i/191656802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11ce6c6e-42dc-481d-8547-7777c7c154ca_880x533.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hzDr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11ce6c6e-42dc-481d-8547-7777c7c154ca_880x533.png 424w, https://substackcdn.com/image/fetch/$s_!hzDr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11ce6c6e-42dc-481d-8547-7777c7c154ca_880x533.png 848w, https://substackcdn.com/image/fetch/$s_!hzDr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11ce6c6e-42dc-481d-8547-7777c7c154ca_880x533.png 1272w, https://substackcdn.com/image/fetch/$s_!hzDr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11ce6c6e-42dc-481d-8547-7777c7c154ca_880x533.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>2. Customizing the Kernel</h4><p>Now, let&#8217;s customize it. Run:</p><pre><code><code>make menuconfig</code></code></pre><p>This launches an older, terminal-based graphical interface. Use your arrow keys to navigate and the Enter key to select.</p><ul><li><p><code>[*]</code><strong> vs </strong><code>[M]</code><strong> vs </strong><code>[ ]</code><strong>:</strong> As you browse, you&#8217;ll see these brackets.</p><ul><li><p><code>[*]</code> means the feature is built directly into the core kernel image.</p></li><li><p><code>[M]</code> means it&#8217;s compiled as a separate &#8220;Module&#8221; that can be loaded later.</p></li><li><p><code>[ ]</code> means it is entirely excluded.</p></li></ul></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1ErS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1ErS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png 424w, https://substackcdn.com/image/fetch/$s_!1ErS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png 848w, https://substackcdn.com/image/fetch/$s_!1ErS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png 1272w, https://substackcdn.com/image/fetch/$s_!1ErS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1ErS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png" width="880" height="533" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:533,&quot;width&quot;:880,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:63981,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.xetxezarreta.com/i/191656802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1ErS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png 424w, https://substackcdn.com/image/fetch/$s_!1ErS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png 848w, https://substackcdn.com/image/fetch/$s_!1ErS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png 1272w, https://substackcdn.com/image/fetch/$s_!1ErS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F503098a2-749a-4e3a-bf97-f976c80cb5e1_880x533.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Let&#8217;s brand your kernel:</strong></p><ol><li><p>Navigate to <strong>General setup</strong>.</p></li><li><p>Go down to <strong>Local version - append to kernel release</strong>.</p></li><li><p>Press Enter and type a custom string, like <code>-custom-kernel</code>.</p></li><li><p>Press Enter to confirm, use the right arrow to select <code>&lt;Save&gt;</code>, press Enter, then <code>&lt;Exit&gt;</code> until you are back in the terminal.</p></li></ol><h3>Phase 4: The Compilation</h3><p>We are going to compile the <code>bzImage</code> (Big Zipped Image), which is the final, compressed kernel executable.</p><p>To speed up the compilation, use the <code>-j</code> flag followed by the number of CPU cores available to WSL. The <code>nproc</code> command detects this automatically.</p><pre><code><code>make -j$(nproc) bzImage</code></code></pre><p>Your CPU usage will spike to 100%. Depending on your hardware, this will take anywhere from 2 to 20 minutes.</p><p><strong>What is happening?</strong> The compiler is turning millions of lines of C code into raw binary instructions. If it finishes successfully, you will see a message at the bottom looking something like this:</p><blockquote><p><code>Kernel: arch/x86/boot/bzImage is ready</code></p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!c3XK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb6400c2-9094-49f1-b0c8-6f6751a4c9b2_880x533.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!c3XK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb6400c2-9094-49f1-b0c8-6f6751a4c9b2_880x533.png 424w, https://substackcdn.com/image/fetch/$s_!c3XK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb6400c2-9094-49f1-b0c8-6f6751a4c9b2_880x533.png 848w, https://substackcdn.com/image/fetch/$s_!c3XK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb6400c2-9094-49f1-b0c8-6f6751a4c9b2_880x533.png 1272w, https://substackcdn.com/image/fetch/$s_!c3XK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb6400c2-9094-49f1-b0c8-6f6751a4c9b2_880x533.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!c3XK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb6400c2-9094-49f1-b0c8-6f6751a4c9b2_880x533.png" width="880" height="533" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bb6400c2-9094-49f1-b0c8-6f6751a4c9b2_880x533.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:533,&quot;width&quot;:880,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:90789,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.xetxezarreta.com/i/191656802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb6400c2-9094-49f1-b0c8-6f6751a4c9b2_880x533.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!c3XK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb6400c2-9094-49f1-b0c8-6f6751a4c9b2_880x533.png 424w, https://substackcdn.com/image/fetch/$s_!c3XK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb6400c2-9094-49f1-b0c8-6f6751a4c9b2_880x533.png 848w, https://substackcdn.com/image/fetch/$s_!c3XK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb6400c2-9094-49f1-b0c8-6f6751a4c9b2_880x533.png 1272w, https://substackcdn.com/image/fetch/$s_!c3XK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb6400c2-9094-49f1-b0c8-6f6751a4c9b2_880x533.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Phase 5: Building an Initramfs (The Userspace)</h3><p>A kernel alone cannot do much. Its job is to manage hardware and provide an environment for user programs to run. If a kernel finishes booting and finds no user programs to execute, it throws a &#8220;Kernel Panic&#8221; and halts.</p><p>If you want to see the exact line of code that kills the system when it can't find a program to run, look at <a href="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/init/main.c?h=v6.19.9#n1634">init/main.c</a>. After hardware initialization, the kernel reaches a final block of code where it desperately searches for a file named <code>init</code> or <code>sh</code>. If those <code>if</code> statements fail, it hits the <code>panic()</code> function.</p><pre><code><code>if (!try_to_run_init_process("/sbin/init") ||
    !try_to_run_init_process("/etc/init") ||
    !try_to_run_init_process("/bin/init") ||
    !try_to_run_init_process("/bin/sh"))
    return 0;

panic("No working init found.  Try passing init= option to kernel. "
      "See Linux Documentation/admin-guide/init.rst for guidance.");</code></code></pre><p>To prevent this, we need a Root File System (RootFS). For this tutorial, we will create an <strong>Initramfs</strong> (Initial RAM Filesystem). This is a tiny, temporary file system loaded into RAM that contains just enough tools to let us interact with the kernel.</p><p>We will populate it with <strong>BusyBox</strong>, often called the &#8220;Swiss Army Knife of Embedded Linux.&#8221; It bundles tiny versions of common tools (<code>ls</code>, <code>echo</code>, <code>cat</code>, <code>sh</code>) into a single executable.</p><h4>1. Setup the Directory</h4><pre><code><code>cd ~/kernel-dev
mkdir initramfs
cd initramfs
mkdir -p bin dev proc sys</code></code></pre><h4>2. Add BusyBox and the Init Script</h4><p>Copy the static BusyBox binary we installed earlier:</p><pre><code><code>cp /bin/busybox bin/sh</code></code></pre><p>Now, create a script named <code>init</code>. When the kernel finishes booting, it explicitly looks for a file named <code>/init</code> and runs it as Process ID 1.</p><pre><code><code>nano init</code></code></pre><p>Paste the following:</p><pre><code><code>#!/bin/sh
# 1. Mount essential virtual file systems
mount -t proc proc /proc
mount -t sysfs sysfs /sys

# 2. Redirect standard input/output to the serial console
exec 0&lt;/dev/console
exec 1&gt;/dev/console
exec 2&gt;/dev/console

# 3. Print a welcome message
echo "================================================="
echo " SUCCESS! Welcome to your custom Linux Kernel."
echo "================================================="

# 4. Launch a shell so we can type commands
/bin/sh</code></code></pre><p>Save and exit. Make the script executable:</p><pre><code><code>chmod +x init</code></code></pre><h4>3. Package the Initramfs</h4><p>We must package this folder into a <code>cpio</code> archive and compress it:</p><pre><code><code>find . | cpio -o -H newc | gzip &gt; ../initramfs.cpio.gz</code></code></pre><h3>Phase 6: Booting in QEMU</h3><p>We have our brain (the kernel) and our hands (the initramfs). Let&#8217;s put them in a virtual body.</p><p>Navigate back to the Linux source directory:</p><pre><code><code>cd ~/kernel-dev/linux</code></code></pre><p>Run QEMU with the following command:</p><pre><code><code>qemu-system-x86_64 \
  -kernel arch/x86/boot/bzImage \
  -initrd ../initramfs.cpio.gz \
  -nographic \
  -append "console=ttyS0"</code></code></pre><p><strong>Breaking down the command:</strong></p><ul><li><p><code>-system-x86_64</code>: Emulate a x86_64 PC.</p></li><li><p><code>-kernel</code>: Points to the custom kernel we just built.</p></li><li><p><code>-initrd</code>: Points to our custom RAM disk file system.</p></li><li><p><code>-nographic</code>: Disables the graphical window. We want output directly in our WSL terminal.</p></li><li><p><code>-append "console=ttyS0"</code>: Passes a boot argument to the kernel, telling it to send all text output to the serial port (which QEMU maps to our terminal).</p></li></ul><p>If successful, you will see a rapid stream of kernel boot logs. Finally, it will print your welcome message and drop you into a <code>#</code> prompt.</p><p><strong>You are now inside your custom operating system.</strong></p><p>Try proving it&#8217;s yours. Type:</p><pre><code><code>uname -a</code></code></pre><p>You should see your <code>-custom-kernel</code> tag in the output. Try exploring the filesystem with <code>cd </code>and <code>ls.</code></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IENd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a30097d-bb15-454d-82ef-daa04d463052_880x533.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IENd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a30097d-bb15-454d-82ef-daa04d463052_880x533.png 424w, https://substackcdn.com/image/fetch/$s_!IENd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a30097d-bb15-454d-82ef-daa04d463052_880x533.png 848w, https://substackcdn.com/image/fetch/$s_!IENd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a30097d-bb15-454d-82ef-daa04d463052_880x533.png 1272w, https://substackcdn.com/image/fetch/$s_!IENd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a30097d-bb15-454d-82ef-daa04d463052_880x533.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IENd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a30097d-bb15-454d-82ef-daa04d463052_880x533.png" width="880" height="533" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8a30097d-bb15-454d-82ef-daa04d463052_880x533.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:533,&quot;width&quot;:880,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:68976,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.xetxezarreta.com/i/191656802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a30097d-bb15-454d-82ef-daa04d463052_880x533.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IENd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a30097d-bb15-454d-82ef-daa04d463052_880x533.png 424w, https://substackcdn.com/image/fetch/$s_!IENd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a30097d-bb15-454d-82ef-daa04d463052_880x533.png 848w, https://substackcdn.com/image/fetch/$s_!IENd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a30097d-bb15-454d-82ef-daa04d463052_880x533.png 1272w, https://substackcdn.com/image/fetch/$s_!IENd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a30097d-bb15-454d-82ef-daa04d463052_880x533.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Exiting the emulation</h4><p>Because we are in a headless serial console, <code>Ctrl+C</code> won&#8217;t exit the emulator. To kill QEMU, use its escape sequence: Press <code>Ctrl+A</code>, and then press <code>X</code>.</p><h3>Conclusion and Next Steps</h3><p>Congratulations! By using WSL2 for compilation and QEMU for emulation, you&#8217;ve created an environment for OS development. </p><p>Where do you go from here?</p><ol><li><p><strong>Modify Source Code:</strong> Open <code>init/main.c</code> in the Linux source, find the <code>start_kernel()</code> function, and add <code>pr_info("Hello from Substack!\n");</code>. Recompile and watch your message appear in the boot logs.</p></li><li><p><strong>Write a Kernel Module:</strong> Learn how to write a simple &#8220;Hello World&#8221; driver, compile it as a <code>.ko</code> file, and load it into your running QEMU system using <code>insmod</code>.</p></li><li><p><strong>Optimize:</strong> Rerun <code>make menuconfig</code> and turn off network drivers, sound drivers, and file systems you don&#8217;t need. See how small you can make the <code>bzImage</code> file!</p></li></ol><p><strong>Have you ever compiled a kernel before, or did you run into any weird errors following this guide? Drop your experiences in the comments below!</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.xetxezarreta.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>