K22: Virtual Machine (VM) and Kernel Installation Instructions

For kernel development and experimentation in this class, you will be working with Linux inside a controlled environment on your own machine using a Linux VM. This guide explains how to get a recent Ubuntu distribution and run a VM with it, as well as how to obtain, compile, install, and run a recent Linux kernel inside that VM. Finally, we will create and run our first kernel patch!

Setting up a VMWare VM

The steps detailed in this section are a strong recommendation from us, based on what we used on our own machines and found to work reliably. Feel free to use and setup any VM of your liking, as long as (1) you can make it boot with a recent Ubuntu distribution, and most importantly (2) be able to obtain, edit, patch, compile, install, and run a patched (modified) kernel.

We will not reply to quests about how to replicate a step X detailed here in the set up Y of your choosing.

Download and Install VMware

In what follows in this section, we will be describing steps regarding using VMware Workstation as the hypervisor and assume you are running it on a Linux-based system.

1) Create an account at Broadcom.com. (Your username is your email!)

2) Log in to Broadcom Support Portal.

3) To use the free edition of VMware Workstation Pro, go to Download VMware Workstation Pro (Free) page and download the latest release. (You have to download and save the .bundle file on your computer.)

On your local machine

4) Navigate the folder where the VMware Workstation bundle installer is located. (By default, it is at the Downloads directory.)

5) Make the file executable and run the corresponding installer for your system.

$ chmod +x VMware-Workstation-Full-####-####.architecture.bundle 
$ sudo ./VMware-Workstation-Full-####-####.architecture.bundle

6) Follow the instructions displayed on the screen to complete the installation.

7) After the installation finishes, reboot your machine.

Download Ubuntu Linux

We will work with Ubuntu 25.04; we have also tested Ubuntu 22.04 and found it to work reliably; but that’s about it, and the same disclaimer as above applies regarding your choosing of an OS distribution.

Create a VM

Now we are ready to create a Linux VM.

1) Run VMware at the background with the command: /usr/bin/vmware &.

2) To create a new VM using the Ubuntu ISO image that you downloaded, go to the top-left corner, click File, and then select New Virtual Machine.

3) In the Virtual Machine Configuration window, select Typical (recommended).

4) In the Install operating system from: window, choose Use ISO image and provide the path to the ISO image you downloaded. Fill in the required information in the Personalize Linux section.

Warning: This password will be used to log into the VM, so make sure to remember it!

5) In the Virtual Machine Name window, leave everything as is, and click Next.

6) In the Disk Size section, choose a size of at least 32 GB and select Store virtual disk as a single file.

7) In the final section, click Customize Hardware and configure the following settings

8) Click close and after the configuration click Finish to create your new VM.

Some notes for the Ubuntu installation:

Finally click Install.

After a while, hopefully your VM is ready! Make sure you can boot and log into it before proceeding to the next section.

Enable Clipboard Sharing (Host ↔ Guest)

To enable clipboard sharing between the host and the guest virtual machine, open a terminal in the VM and run:

$ sudo apt update && sudo apt install open-vm-tools open-vm-tools-desktop
$ sudo systemctl enable --now open-vm-tools

Afterwards, log out of your session and log back in. Clipboard sharing between the host and the guest should now be enabled.

Kernel Compilation & Installation

Warning: all the steps of this sub-section must be run inside the VM!

Preparation

Boot up the VM and from a shell inside the VM execute the following commands to install the required dependencies for building the kernel:

$ sudo apt update
$ sudo apt install build-essential git bc python3 bison flex rsync libelf-dev libncurses-dev dwarves libdw-dev gawk libssl-dev openssh-server htop universal-ctags python3-ply python3-git

Next, clone the source code for Linux kernel v6.14.

$ git clone --depth=1 --branch v6.14 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git linux-6.14
$ cd linux-6.14

Warning: all subsequent commands from this guide should be run from the root directory of the kernel source!

Read the first lines of the Makefile to verify you downloaded the correct kernel version:

$ head -n5 Makefile
# SPDX-License-Identifier: GPL-2.0
VERSION = 6
PATCHLEVEL = 14
SUBLEVEL = 0
EXTRAVERSION =

Kernel Configuration

Before building the kernel, you must configure it by selecting the features, drivers and other options that will be included in the compiled kernel. This configuration is stored in the .config file in the root directory of the kernel source.

We will remove any existing configuration files and create our own based on the configuration file of the kernel currently in use.

Warning: it would be a good idea to run this step using a stable stock kernel, such as the one provided by default by your distribution, to ensure you proceed with a proper configuration.

$ make mrproper
$ make olddefconfig

A .config file should now be visible in the current directory. This file holds kernel build options, each set to a specific value. You can view its contents with cat .config. There are two main approaches to edit the configuration file:

scripts/config --set-str <option> <value>  # set an option
scripts/config --state <option>            # read an option

Make the following changes to your configuration file:

$ scripts/config --set-str CONFIG_LOCALVERSION "-k22"
$ scripts/config --set-str SYSTEM_TRUSTED_KEYS ""
$ scripts/config --set-str SYSTEM_REVOCATION_KEYS ""

The first command gives your kernel a custom name to distinguish it from other installed kernels. You should expect your custom kernel to have a name similar to 6.14.0-k22. The latter commands instruct the kernel not to enforce built-in signature verification of modules/firmware against specific trusted keys.

Finally, run the following command to disable unused kernel modules from your configuration file, reducing kernel compilation time:

yes '' | make localmodconfig

Kernel Build

Warning: run this step as non-root user!

Build the kernel using all cores allocated to the VM with:

$ make -j`nproc`

Depending on the amount of available cores and the capabilities of your machine, this step may take a while.

Kernel Installation

Install your custom kernel and kernel modules with:

$ sudo make modules_install && sudo make install

If all goes well, you must be able to verify that the following 3 files are in /boot:

$ ls /boot | grep "k22"
initrd.img-6.14.0-k22
System.map-6.14.0-k22
vmlinuz-6.14.0-k22

Booting the Custom Kernel

Before rebooting the machine, we need to modify the bootloader’s (GRUB) configuration file to allow us to select the kernel we want to boot with.

Open /etc/default/grub as root with a text editor and:

Save and close the file and then run:

$ sudo update-grub

Reboot the machine and from the GRUB menu select Advanced Options for Ubuntu . Choose the kernel post-fixed with -k22. You can always select the Ubuntu option from the GRUB menu to boot with the stock kernel, which is recommended for development.

Once the VM boots up, verify you are running your custom kernel with:

$ uname -r
6.14.0-k22

Our First Kernel Patch

We will now make our first Linux kernel patch to get used to the kernel development workflow. We need the kernel to print a Hello World message whenever the VM boots (i.e., when the kernel starts). This message should be displayed in the kernel message buffer, used by the kernel to display useful messages, such as:

To do this, we will edit the start_kernel() function in the init/main.c file. This is the C entry point of the Linux kernel and is called by the architecture-specific assembly start up code, after the CPU and basic hardware have been initialized. The function “ends” with a call to rest_init(), which performs the remaining initializations and calls into the scheduler. Therefore rest_init() should never return.

We will print a log message in start_kernel(), just before rest_init() is called. The logging function we will use is called printk(). It works similar to printf but its messages are all printed to the kernel message buffer.

Insert the following line of code just before the call to rest_init():

printk(KERN_INFO "I miss Alexis Delis\n");

Warning: this step should be performed in your custom kernel tree inside the VM!

Make sure you save the file, re-build and re-install the kernel with the following commands:

$ make -j`nproc`
$ sudo make modules_install && sudo make install

Note: You do not need to re-configure the kernel every time you make a change. However you should re-compile any changed files and re-install the modified kernel using the commands above whenever you are ready to test your changes.

Reboot the machine and once again select your custom -k22 kernel from the GRUB menu. The new kernel may show a -dirty suffix, which is normal. Run the following command to search the kernel logs for your custom message:

$ sudo dmesg | grep "Delis"
[    0.148119] I miss Alexis Delis