First off, what is kexec? - It is a system call that enables you to load and boot into another kernel from currently running kernel. That effectively means; doing reboot without going through the whole POST/Firmware load process.

To use kexec we can rely on systemd to handle process for us. The only work we need to do is to install kexec-tools package and adjust some configs

sudo apt-get update
sudo apt-get install kexec-tools

Since Ubuntu usually relies on booting from grub we can tweak some settings to default to loading default grub kernel when we run kexec. That is usually set to latest kernel we have installed and is automatically adjusted after system upgrade. Contents of my /etc/default/kexec are as follows:

# Defaults for kexec initscript
# sourced by /etc/init.d/kexec and /etc/init.d/kexec-load

# Load a kexec kernel (true/false)
LOAD_KEXEC=true

# Kernel and initrd image
KERNEL_IMAGE="/vmlinuz"
INITRD="/initrd.img"

# If empty, use current /proc/cmdline
APPEND=""

# Load the default kernel from grub config (true/false)
USE_GRUB_CONFIG=true

Now, in order to reboot via kexec you can simply use:

sudo systemctl start kexec.target

In one article on Oracle blog I have found a script which is basically a wrapper around this and allows you to specify desired kernel version you’d like to boot into. Since script was most likely written on Oracle Linux or some kind of RedHat derivative it is not working properly on Ubuntu, so here’s my slightly updated version:

#!/bin/bash
 
[[ "$1" != '-' ]] && kernel="$1"
shift
if [[ "$1" == '-' ]]; then
    reuse=--reuse-cmdline
    shift
fi
[[ $# == 0 ]] && reuse=--reuse-cmdline
kernel="${kernel:-$(uname -r)}"
kargs="/boot/vmlinuz-$kernel --initrd=/boot/initrd.img-$kernel"
 
kexec -l -t bzImage $kargs $reuse --append="$*" && systemctl kexec