What is the best way to setup a test environment while working through Linux Device Drivers?

I have compiled a bzImage for x86 from the latest Linux source using x86_64_defconfig.

I have followed the Gentoo custom initramfs tutorial so that I am booting to an isolated filesystem based on Busybox. I use the exact same init file that they use. The only difference between what I am doing and what they do is that I am running on Ubuntu and download the latest Busybox x86_64 binary instead of using emerge.

On my Ubuntu 16.04 system, I am running

qemu-system-x86_64 -kernel arch/x86/boot/bzImage -append "console=ttyS0" -initrd custom-initramfs.cpio.gz -nographic

where custom-initramfs.cpio.gz refers to the initramfs I built and compressed like in the Gentoo tutorial.

I run all of this and still end up with a kernel error, as seen below

[    2.893799] md: Waiting for all devices to be available before autodetect
[    2.894724] md: If you don't use raid, use raid=noautodetect
[    2.913768] md: Autodetecting RAID arrays.
[    2.914465] md: Scanned 0 and added 0 devices.
[    2.914879] md: autorun ...
[    2.915478] md: ... autorun DONE.
[    2.920719] VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
[    2.921465] Please append a correct "root=" boot option; here are the available partitions:
[    2.922493] 0b00         1048575 sr0  driver: sr
[    2.923069] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[    2.923101] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.8.0-rc1+ #18
[    2.923101] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[    2.923101]  0000000000000000 ffff8800070ffde0 ffffffff81328158 ffff8800066aa000
[    2.923101]  ffffffff81b98e58 ffff8800070ffe60 ffffffff81124120 0000000000000010
[    2.923101]  ffff8800070ffe70 ffff8800070ffe08 ffffffff8112441e ffff8800070ffe78
[    2.923101] Call Trace:
[    2.923101]  [<ffffffff81328158>] dump_stack+0x4d/0x65
[    2.923101]  [<ffffffff81124120>] panic+0xca/0x1fc
[    2.923101]  [<ffffffff8112441e>] ? printk+0x43/0x4b
[    2.923101]  [<ffffffff81f4a364>] mount_block_root+0x175/0x229
[    2.923101]  [<ffffffff81f4a519>] mount_root+0x101/0x10a
[    2.923101]  [<ffffffff81f4a653>] prepare_namespace+0x131/0x169
[    2.923101]  [<ffffffff81f4a03c>] kernel_init_freeable+0x1c0/0x1d5
[    2.923101]  [<ffffffff818e7669>] kernel_init+0x9/0x100
[    2.923101]  [<ffffffff818ed30f>] ret_from_fork+0x1f/0x40
[    2.923101]  [<ffffffff818e7660>] ? rest_init+0x80/0x80
[    2.923101] Kernel Offset: disabled
[    2.923101] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

I am able to boot to initramfs though when booting locally and not using QEMU. This grub menu option works

menuentry 'linux latest' {
    linux /boot/bzImage-latest
    initrd /boot/custom-initramfs.cpio.gz

where bzImage and initramfs refer to the same default x86_64 config kernel image and the custom initramfs built before.

The issue seems to stem from QEMU not having the same access to devices in /dev that the local machine does.

What can I fix to make this work in a QEMU environment? My goal here is just to be able to get through kernel bootup and into some sort of minimal filesystem.

I just made my first device driver patch at work, which was exciting, and I want to continue learning more. Any help would be appreciated!

  • I'm not convinced the initramfs is running, because it should substitute for the kernel's handling of root=, if you have evidence the initramfs is running at all please present it. Note this is nothing to do with /dev. The kernel says it's trying to mount a root filesystem but you (deliberately) haven't told the kernel a root filesystem to use - this is what is meant by "(null)" or unknown-block(0,0).
    – sourcejedi
    Aug 14, 2016 at 18:54
  • Do you have a line that says "Unpacking initramfs..."?
    – sourcejedi
    Aug 14, 2016 at 19:17
  • If an initramfs is running and then stops (sys_exit() of PID 1), it is immediately fatal. (PID 1 is init; exit by init is fatal and causes a kernel panic; if it wants to transition to a different program it must use exec to replace itself). I.e. it doesn't go on to attempt to mount a root fs.
    – sourcejedi
    Aug 14, 2016 at 19:21
  • However reading the kernel documentation, if an /init program doesn't exist in the initramfs, then it will continue and do what you've shown here. Not clear exactly what happens if it exists but is not an executable program file.
    – sourcejedi
    Aug 14, 2016 at 19:23

1 Answer 1


Self- taught kernel hacker here (and still maintain a small part of it).

Maybe not much of a definitive answer, but I'd firstly recommend using a small embedded board such as a raspberry pi, as during kernel development you'll need to use physical hardware sooner or later - software emulation and VMs just don't use the same drivers and code as physical hardware, or add extra layers of complexity when you're trying to figure out how something works that is already complex enough.

However, working on a secondary embedded system will involve using a cross compiler that may also cause issues. If you do have an older x86 system lying around, then use that - get used to setting up the system from scratch, as you will bork it sooner or later and the exercise of doing so isn't a bad thing, as real kernel development will involve developing on less than stable systems (wax on/wax off...).

In the absence of any secondary system to hack on, dual boot your main system and use the second system to work on - but make sure you back up everything, just in case.

Oh, and one final thought - don't use Ubuntu, fedora or any distribution where the user space is likely to change between updates - otherwise you'll end up debugging ghost issues. Use Debian, centos or another stable userspace, at least until you can instinctively spot such issues.

  • Completely agree, don't use ubuntu or similar for kernel devel. You will get issues that come from the OS itself, things you really do not need. I'd just like to add that if you need a very recent kernel (which stable distros like CentOS or Debian often do not have) I had good experience with rolling forward distros (gentoo/arch). Being able to test something quick by simply doing a dirty modprobe into the kernel of your development system has its advantages. A rolling forward distro also keeps your wits about what changes in the kernel's trunck.
    – grochmal
    Aug 14, 2016 at 19:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.