First of all, download the Linux kernel source code from kernel.org. You can generally click on the "tarball" link in one of the entries from the kernel.org main page. For example, wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.8.14.tar.xz Then, unpack the tarball with tar xvf linux-<...>.tar.gz For example, tar xvf linux-5.8.14.tar.xz. Now, you can build the kernel: - First of all, configure it with "make <...>config". For example, make defconfig or make menuconfig or similar. Type "make help" for knowing the possible targets. - The configuration is save in a hidden file named ".config", in the current directory (note: the file is hidden because its name starts with "."). - For the experiments in this course, you need to enable the "CONFIG_UEVENT_HELPER" option in the kernel configuration. The easiest way to do this is to edit ".config" (setting CONFIG_UEVENT_HELPER=y") and then run make oldconfig (as an alternative, you could use "make menuconfig" and enable the approprate option, but you have to search for it in all the menus) - Now, you can build the kernel, by simply typing make Notice that the build process can be quite slow, so it is better to parallelize it with make -j where is the number of parallel build processes you want to use. If your system has M cores, set N=M-1. So, on a 4-cores system you can type make -j3 After some time, your kernel image will be in arch/x86_64/boot/bzImage (assuming an x86_64 CPU). You can also build the kernel out-of-tree by using the "O=..." option. For example, tar xvf linux-5.8.14.tar.xz mkdir Build make -C linux-5.8.14 O=$(pwd)/Build defconfig cd Build vi .config ... make oldconfig make -j3 The "O=..." ("O=$(pwd)/Build", in the previous example), allows to specify an _O_utput directory, where all the generated files are stored. If "O=..." is not specified, the output directory is assumed to be the same as the equal directory, and a so-called in-tree build is performed (source files and generated files are placed in the same directory tree). Notice that "O=..." wants an _absolute_ path (not a relative path!), hence the "$(pwd)/" in the previous example. Once you built the kernel, you will find the kernel image in an architecture-dependend path (for example, arch/x86/boot/bzImage for the Intel x86 architecture). This file can be directly tested by using (for example) qemu (and an appropriate initramfs), or can also be installed in a physical or virtual machine. The easiest way to install the generated kernel on the machine where you built it is to type make modules_install make install with administrator's rights (so, it will probably be "sudo make modules_install" and "sudo make install"). In particular, "make install" invokes a distribution-specific script (generally customizable through "/etc/kernel") that can take care of generating an initramfs, copying the kernel in the correct place, and updating the bootloader configuration. On some distributions, the script does not update the bootloader configuration, so a specific command (for example, "update-grub2") needs to be explicitly invoked (but on Debian-based distributions this is not needed). A more advanced way to install the kernel is to generate a proper packet for the distribution you are using (for example, on Debian-based distributions you can generate a .deb package by typing "make bindeb-pkg) and then install it using the standard package manager (on Debian, "apt install ..." or "apt-get install ...").