Skip to content

Instantly share code, notes, and snippets.

@l-0-l
Last active May 14, 2024 16:53
Show Gist options
  • Save l-0-l/453a4edacbe532d10101d65c2b7cceab to your computer and use it in GitHub Desktop.
Save l-0-l/453a4edacbe532d10101d65c2b7cceab to your computer and use it in GitHub Desktop.
Set up a Linux kernel development environment

Setup a Linux kernel development environment easily with virtme-ng.

The instructions cover cloning and building Linux kernel and the useful qemu wrapper virtme-ng. After performing these actions, a virtual machine is started with the newly built Linux kernel and the current local rootfs - same user and files. This allows building and testing kernel modules and user-space apps with a custom/specific kernel.

The kernel compilation phase can be made very simple with virtme-ng itself, so be sure to check out its capabilities by running vng --help after installing it. Here the kernel building instructions more manual and detailed to radically reduce the build time by removing certain features you normally don't care about in such a setup.

While virtme-ng makes it easy to run a kernel on the local root filesystem for debugging, it is not your original system. In most cases today your Linux runs with systemd init, which is quite a complex environment. The virtme-ng prroject relaces your init with a simplified and small init written in Rust, so don't expect using systemd's features like systemctl. This environment won't be suitable for testing of kernel features or modules in relation to systemd and will not allow you to fully use your rootfs as usual.

Caution

In the following setup the kernel runs inside a VM, so if your kernel gets stuck it won't affect the physical machine. Nevertheless, the file system is the original one on your physical disk, so any changes are permanent. Treat it with care.

Note

Everything is done in CLI, no graphical environment is involved. Tested on:

  • Native Debian 12 Bookworm, x86-64
  • Windows WSL2, Ubuntu 22.04, x86-64

Setup the work directory, we'll put it under home:

mkdir ~/work && cd ~/work

Have the necessary packages for kernel build installed. This is not a comprehensive list. Adapt to other package managers as required.

sudo apt update
sudo apt install git build-essential libncurses-dev bison flex libssl-dev libelf-dev bc dwarves

Download and build virtme-ng.

Your distro may have it in the package manager, check out the full instructions here.

git clone --recurse-submodules https://github.com/arighi/virtme-ng.git
cd virtme-ng
sudo apt install python3-pip python3-argcomplete flake8 pylint cargo rustc qemu-system-x86
BUILD_VIRTME_NG_INIT=1 pip3 install --break-system-packages --verbose -r requirements.txt .

Note

Use updated setuptools to avoid build errors: python3 -m pip install --upgrade setuptools

Update the path to include the ~/.local/bin directory:

source ~/.profile

Go back to the work directory:

cd ~/work

Get the kernel sources. There are many methods, here are two:

Stable (check out https://kernel.org/ for stable version links):

wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.28.tar.xz
tar xf linux-6.6.28.tar.xz
cd linux-6.6.28

Linus vanilla:

Check the tags to find the preferred version (here we're after version 6.6, for example).
git ls-remote --tags https://github.com/torvalds/linux.git | grep 6.6$
Say we want the v6.6, clone it with the tag observed previously.
git clone --branch v6.6 --depth 1 https://github.com/torvalds/linux.git
cd linux

Configure the kernel:

This is where things become flexible. We'll be running in a VM with a very self-contained init system, so the kernel configuration should depend on what you want to test or debug.

Option 1

To have your kernel as similar to the currently running one, a local config file must be obtained. Here are some examples (as this is distro-dependant), one should work on modern Linux distros:

  • cp /boot/config-$(uname -r) .config
  • zcat /proc/config.gz > .config Then prepare it for the build, as the new kernel version is probably different:
make olddefconfig

Option 2

For a quick start, to vastly improve kernel build time, the following removes many kernel features that may be skipped for the purpose of this build. Begin with either the full config like in option 1, or with a minimal one by running make defconfig. Then, two lists are provided in the attached disable.conf and enable.conf files. After creating or downloading them in the kernel directory, run the following commands to apply the changes.

Note

While many more features can be removed keeping the kernel functional in a virtual machine, curate the list depending on your goals or skip this entirely.

while read -r line; do scripts/config --disable "$line"; done < disable.conf
while read -r line; do scripts/config --enable "$line"; done < enable.conf
make olddefconfig

Tip

To change anything manually in the configuration at this point:

make menuconfig

Build it:

This can take anywhere between 5 minutes and 2 hours depending on previous choices and the HW.

make -j$(nproc) && make modules

I prefer to install the modules locally and then reference this custom location in the kernel module Makefile, to keep things encapsulated. Instead you may choose to install them as usual by make modules_install.

mkdir -p modules && make modules_install INSTALL_MOD_PATH=modules

Run it:

Do it in the current kernel directory. Most arguments are quite obvious, feel free to adjust as needed. If vng can't be found, verify you have souced the profile with source ~/.profile or call it directly with ~/.local/bin/vng.

vng --cpus 2 --memory 2G --rw --pwd --user $USER --name my_machine --net user

Tip

To exit the VM at any stage, press Ctrl+d or Ctrl+a followed by x. For more VM keyboard shortcuts see https://www.qemu.org/docs/master/system/mux-chardev.html

Kindly contribute to this guide by correcting mistakes, adding other distros you tested it on, and curating the kernel configs to diasble and enable. Good luck!

CONFIG_USB
CONFIG_BT
CONFIG_DRM
CONFIG_WLAN
CONFIG_MAC80211
CONFIG_WIRELESS_EXT
CONFIG_AGP
CONFIG_VGA_ARB
CONFIG_SOUND
CONFIG_SND
CONFIG_SCSI
CONFIG_ATA
CONFIG_JFS
CONFIG_REISERFS
CONFIG_XFS
CONFIG_BTRFS
CONFIG_INPUT_JOYSTICK
CONFIG_INPUT_MOUSE
CONFIG_FB
CONFIG_HID
CONFIG_DECNET
CONFIG_IPX
CONFIG_ATALK
CONFIG_X25
CONFIG_AX25
CONFIG_ACPI
CONFIG_THERMAL
CONFIG_I2C
CONFIG_RAID
CONFIG_ISDN
CONFIG_ACCESSIBILITY
CONFIG_CRYPTO
CONFIG_HWMON
CONFIG_INPUT_TOUCHSCREEN
CONFIG_TOUCHSCREEN_DMI
CONFIG_INPUT_LEDS
CONFIG_INPUT_FF_MEMLESS
CONFIG_INPUT_SPARSEKMAP
CONFIG_INPUT_MATRIXKMAP
CONFIG_INPUT_VIVALDIFMAP
CONFIG_INPUT_MOUSEDEV
CONFIG_INPUT_MOUSEDEV_PSAUX
CONFIG_INPUT_JOYDEV
CONFIG_INPUT_EVDEV
CONFIG_INPUT_TABLET
CONFIG_INPUT_PCSPKR
CONFIG_INPUT_APANEL
CONFIG_INPUT_ATLAS_BTNS
CONFIG_INPUT_ATI_REMOTE2
CONFIG_INPUT_KEYSPAN_REMOTE
CONFIG_INPUT_POWERMATE
CONFIG_INPUT_YEALINK
CONFIG_INPUT_CM109
CONFIG_INPUT_AXP20X_PEK
CONFIG_INPUT_UINPUT
CONFIG_INPUT_XEN_KBDDEV_FRONTEND
CONFIG_INPUT_IDEAPAD_SLIDEBAR
CONFIG_INPUT_SOC_BUTTON_ARRAY
CONFIG_USB_PWC_INPUT_EVDEV
CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV
CONFIG_PCMCIA
CONFIG_INFINIBAND
CONFIG_SSB_POSSIBLE
CONFIG_BCMA_POSSIBLE
CONFIG_ARCH_HIBERNATION_POSSIBLE
CONFIG_ARCH_SUSPEND_POSSIBLE
CONFIG_ACPI_REV_OVERRIDE_POSSIBLE
CONFIG_SSB_PCIHOST_POSSIBLE
CONFIG_SSB_PCMCIAHOST_POSSIBLE
CONFIG_SSB_SDIOHOST_POSSIBLE
CONFIG_SSB_DRIVER_PCICORE_POSSIBLE
CONFIG_BCMA_HOST_PCI_POSSIBLE
CONFIG_IIO
CONFIG_DAX
CONFIG_CXL
CONFIG_NFC
CONFIG_HAMRADIO
CONFIG_XEN
CONFIG_INPUT_TOUCHSCREEN
CONFIG_MOUSE_APPLETOUCH
CONFIG_HID_ACCUTOUCH
CONFIG_HID_KEYTOUCH
CONFIG_HID_MULTITOUCH
CONFIG_USB_STORAGE_ONETOUCH
CONFIG_USB_SPEEDTOUCH
CONFIG_WIRELESS
CONFIG_FIREWIRE
CONFIG_FIREWIRE_OHCI
CONFIG_FIREWIRE_NET
CONFIG_FIREWIRE_NOSY
CONFIG_WIREGUARD
CONFIG_FIREWIRE
CONFIG_NUMA
CONFIG_AMD_NUMA
CONFIG_ARCH_SUPPORTS_NUMA_BALANCING
CONFIG_MODULE_SIG
CONFIG_SIGNATURE
CONFIG_INTEGRITY
CONFIG_CHECK_SIGNATURE
CONFIG_MODULE_SIG
CONFIG_SECURITY
CONFIG_VIDEO_DEV
CONFIG_VGA_CONSOLE
CONFIG_USB
CONFIG_HIBERNATION
CONFIG_SUSPEND
CONFIG_HOTPLUG_SMT
CONFIG_OSF_PARTITION
CONFIG_AMIGA_PARTITION
CONFIG_ATARI_PARTITION
CONFIG_MAC_PARTITION
CONFIG_MINIX_SUBPARTITION
CONFIG_SOLARIS_X86_PARTITION
CONFIG_LDM_PARTITION
CONFIG_SGI_PARTITION
CONFIG_ULTRIX_PARTITION
CONFIG_SUN_PARTITION
CONFIG_KARMA_PARTITION
CONFIG_IPV6
CONFIG_CAN
CONFIG_HOTPLUG_PCI
CONFIG_CARDBUS
CONFIG_CXL
CONFIG_CXL_BUS
CONFIG_PCCARD
CONFIG_MTD
CONFIG_PARPORT
CONFIG_GNSS
CONFIG_MD
CONFIG_TARGET_CORE
CONFIG_VIRTUALIZATION
CONFIG_SPECULATION_MITIGATIONS
CONFIG_PM
CONFIG_CPU_IDLE
CONFIG_SECCOMP
CONFIG_HARDENED_USERCOPY
CONFIG_RANDOMIZE_KSTACK_OFFSET
CONFIG_MODULE_DEBUG
CONFIG_DEBUG_SPINLOCK
CONFIG_FRAME_POINTER
CONFIG_KGDB
CONFIG_X86_X2APIC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment