top of page

Build the Linux kernel and Busybox and run them on QEMU


Check out [link] for more streamlined instructions

What the Post is About

This post is a condensed version of Mitchel Humpherys excellent post @ link. Like Mitchel's post, this post gives step-by-step instructions for building a minimal custom Linux kernel, creating a busybox based userland and booting it on an emulator (QEMU). This post just builds the allnoconfig + custom config; the smallest config.

Why is it Useful?

Of the many reasons, building a minimal Linux kernel and booting it on an emulator allows developers to quickly build additional Linux kernel features.

Set Up

Everything was built in an Oracle VM VirtualBox running on Windows 7, Version 5.1.30 r118389 (Qt5.6.2) with 4 GB of RAM and a 64 GB disk (the VM's config) running Ubuntu 16.04.2. VirtualBox was running on a T460. If you need help setting up this environment click here (just install 16.04.02 instead of 16.04.01).

Get the Packages


1. Open a Terminal

2. Create a workspace

3. Download and extract the Linux kernel and BusyBox

1 min 23 secs for kernel, 2 secs for BusyBox

4. Create a minimal userland

  • -pv: p means don't output an error and quit if the directory exist and v means print a message for each created directory.

  • 0= means put output here

5. Enable static linking in BusyBox

5.1 Press enter on Busybox Settings --->

5.2 Press the down arrow until you hit Build BusyBox as a static binary (no shared libs).

5.3 Press Y

5.4 Select Exit twice and hit Enter to Save (cursor will be on Yes).

6. Build BusyBox

make -j2 took about 2 min, the time to make install was negligible.

7. Build the directory structure of the initramfs

-av: a means -dR --preserve=all, v means explain what is being done

-dR --preserve=all:

d means --no-dereference --preserve=links

R means copy directories recursively

--preserve=all means

Note: Need additional info about /dev nodes from link.

8. Create init and make it executable

Edit init

Paste this in

Make the file executable

9. Create the initramfs (big thanks to

Warning: you _have_ to use find . if you use find with a absolute path you'll encode absolute paths and the kernel will not find your init. Scroll down to see the error.

find - search for files in a directory hierarchy

$TOP: starts looking for files in $TOP. Since no filter is specified, all the files will be returned

-print0: print the fill filename followed by a NULL instead of a newline

cpio - copy files to and from archives

-o: Create the archive (run in copy-out mode)

-v: Verbosely list the files processed

-H newc: Use given archive FORMAT

newc: The new (SVR4) portable format, which supports file systems having more than 65536 i-nodes. (4294967295 bytes)

gzip - compress or expand files

Check it. Run:

You should see something like:

To check the contents do:

Then to re-create from _this_ directory do:

10. Config the kernel with the minimal config

11. Re-enable config options for QEMU

nconfig: Pseudo-graphical menu based on ncurses (doc from link)

12. Turn these options on

Debug fs is not needed for QEMU. Its included because building a debug interface is a good way to start to work with the kernel.

Early printk is also not required but it helps see the kernel boot up.

13. Make the Linux kernel

At the end of the log you should see:

14. Launch the kernel

To Exit QEMU (this didn't work for me)

Type Ctl-a c then type “quit” at the qemu monitor shell.

15. To build the initramfs into the kernel (which I had to do since I kept getting a "can't find init error)

Run a kernel config:

Set this field to where your initramfs is (note: not using $TOP here):

Then kick off QEMU with:

When ever you change the initramfs you need to rebuild the kernel.


Enabling early printk's allowed me to see:

I then add init=/bin/sh and called the kernel:

I got:

When I extract the cpio built using Mitchel Humphery's cpio creation I noticed that the paths started were absolute!


I looked back at Michel's original instructions:

...I had changed to use an absolute path in the find call:

Look at the output from:

Versus the output from:


See the full paths! Garrrh!

So when creating cpio archives for initramfs', cd into the initramfs and use find . otherwise you may see:


This write up also forgos the use of '$' before commands so that you can copy and paste the commands directly into your terminal.

Google Internet speed test:

40.2 Mbps download, 5.18 Mbps upload, Latency 32 ms

BusyBox is at link.


Tux from link (found via Google image search).


bottom of page