diff --git a/doc/manual/running.xml b/doc/manual/running.xml
index 858372c1acac..e50099707cc5 100644
--- a/doc/manual/running.xml
+++ b/doc/manual/running.xml
@@ -101,9 +101,25 @@ doing:
$ shutdown
-This is equivalent to running systemctl poweroff.
-Likewise, reboot (a.k.a. systemctl
-reboot) will reboot the system.
+This is equivalent to running systemctl
+poweroff.
+
+To reboot the system, run
+
+
+$ reboot
+
+
+which is equivalent to systemctl reboot.
+Alternatively, you can quickly reboot the system using
+kexec, which bypasses the BIOS by directly loading
+the new kernel into memory:
+
+
+$ systemctl kexec
+
+
+
The machine can be suspended to RAM (if supported) using
systemctl suspend, and suspended to disk using
diff --git a/lib/test-driver/Machine.pm b/lib/test-driver/Machine.pm
index c56e650ed361..a28214ea934f 100644
--- a/lib/test-driver/Machine.pm
+++ b/lib/test-driver/Machine.pm
@@ -232,9 +232,9 @@ sub connect {
$self->start;
- local $SIG{ALRM} = sub { die "timed out waiting for the guest to connect\n"; };
+ local $SIG{ALRM} = sub { die "timed out waiting for the VM to connect\n"; };
alarm 300;
- readline $self->{socket} or die;
+ readline $self->{socket} or die "the VM quit before connecting\n";
alarm 0;
$self->log("connected to guest root shell");
diff --git a/modules/module-list.nix b/modules/module-list.nix
index 717828fbd70d..08acd213355e 100644
--- a/modules/module-list.nix
+++ b/modules/module-list.nix
@@ -235,6 +235,7 @@
./system/activation/activation-script.nix
./system/activation/top-level.nix
./system/boot/kernel.nix
+ ./system/boot/kexec.nix
./system/boot/loader/efi-boot-stub/efi-boot-stub.nix
./system/boot/loader/efi.nix
./system/boot/loader/generations-dir/generations-dir.nix
diff --git a/modules/system/boot/kexec.nix b/modules/system/boot/kexec.nix
new file mode 100644
index 000000000000..b7821f9509f1
--- /dev/null
+++ b/modules/system/boot/kexec.nix
@@ -0,0 +1,21 @@
+{ config, pkgs, ... }:
+
+{
+ environment.systemPackages = [ pkgs.kexectools ];
+
+ systemd.services."prepare-kexec" =
+ { description = "Preparation for kexec";
+ wantedBy = [ "kexec.target" ];
+ before = [ "systemd-kexec.service" ];
+ unitConfig.DefaultDependencies = false;
+ serviceConfig.Type = "oneshot";
+ path = [ pkgs.kexectools ];
+ script =
+ ''
+ p=$(readlink -f /nix/var/nix/profiles/system)
+ if ! [ -d $p ]; then exit 1; fi
+ exec kexec --load $p/kernel --initrd=$p/initrd --append="$(cat $p/kernel-params) init=$p/init"
+ '';
+ };
+
+}
\ No newline at end of file
diff --git a/modules/system/boot/systemd.nix b/modules/system/boot/systemd.nix
index 900cbfd0cd51..5ad8cdbcb18b 100644
--- a/modules/system/boot/systemd.nix
+++ b/modules/system/boot/systemd.nix
@@ -129,6 +129,7 @@ let
"umount.target"
"final.target"
"kexec.target"
+ "systemd-kexec.service"
# Password entry.
"systemd-ask-password-console.path"
diff --git a/tests/default.nix b/tests/default.nix
index a94ad0695106..36a2a2d608b8 100644
--- a/tests/default.nix
+++ b/tests/default.nix
@@ -10,6 +10,7 @@ with import ../lib/testing.nix { inherit system minimal; };
installer = makeTests (import ./installer.nix);
ipv6 = makeTest (import ./ipv6.nix);
kde4 = makeTest (import ./kde4.nix);
+ #kexec = makeTest (import ./kexec.nix);
login = makeTest (import ./login.nix {});
latestKernel.login = makeTest (import ./login.nix ({ config, pkgs, ... }: { boot.kernelPackages = pkgs.linuxPackages_latest; }));
misc = makeTest (import ./misc.nix);
diff --git a/tests/kexec.nix b/tests/kexec.nix
new file mode 100644
index 000000000000..b8da332b919b
--- /dev/null
+++ b/tests/kexec.nix
@@ -0,0 +1,18 @@
+# Test whether fast reboots via kexec work.
+
+{ pkgs, ... }:
+
+{
+
+ machine = { config, pkgs, ... }:
+ { virtualisation.vlans = [ ]; };
+
+ testScript =
+ ''
+ $machine->waitForUnit("multi-user.target");
+ $machine->execute("systemctl kexec &");
+ $machine->{connected} = 0;
+ $machine->waitForUnit("multi-user.target");
+ '';
+
+}