···
drivesCmdLine = drives: concatStringsSep "\\\n " (imap1 driveCmdline drives);
-
# Creates a device name from a 1-based a numerical index, e.g.
-
# * `driveDeviceName 1` -> `/dev/vda`
-
# * `driveDeviceName 2` -> `/dev/vdb`
-
let letter = elemAt lowerChars (idx - 1);
-
in if cfg.qemu.diskInterface == "scsi" then
-
lookupDriveDeviceName = driveName: driveList:
-
(findSingle (drive: drive.name == driveName)
-
(throw "Drive ${driveName} not found")
-
(throw "Multiple drives named ${driveName}") driveList).device;
-
imap1 (idx: drive: drive // { device = driveDeviceName idx; });
# Shell script to start the VM.
···
NIX_DISK_IMAGE=$(readlink -f "''${NIX_DISK_IMAGE:-${toString config.virtualisation.diskImage}}") || test -z "$NIX_DISK_IMAGE"
if test -n "$NIX_DISK_IMAGE" && ! test -e "$NIX_DISK_IMAGE"; then
echo "Disk image do not exist, creating the virtualisation disk image..."
-
# If we are using a bootloader and default filesystems layout.
-
# We have to reuse the system image layout as a backing image format (CoW)
-
# So we can write on the top of it.
-
# If we are not using the default FS layout, potentially, we are interested into
-
# performing operations in postDeviceCommands or at early boot on the raw device.
-
# We can still boot through QEMU direct kernel boot feature.
-
# CoW prevent size to be attributed to an image.
-
# FIXME: raise this issue to upstream.
-
${qemu}/bin/qemu-img create \
-
${concatStringsSep " \\\n" ([ "-f qcow2" ]
-
++ optional (cfg.useBootLoader && cfg.useDefaultFilesystems) "-F qcow2 -b ${systemImage}/nixos.qcow2"
-
++ optional (!(cfg.useBootLoader && cfg.useDefaultFilesystems)) "-o size=${toString config.virtualisation.diskSize}M"
-
++ [ ''"$NIX_DISK_IMAGE"'' ])}
echo "Virtualisation disk image created."
···
${pkgs.erofs-utils}/bin/mkfs.erofs \
-U eb176051-bd15-49b7-9e6b-462e0b467019 \
···
regInfo = pkgs.closureInfo { rootPaths = config.virtualisation.additionalPaths; };
# System image is akin to a complete NixOS install with
# a boot partition and root partition.
systemImage = import ../../lib/make-disk-image.nix {
···
additionalPaths = [ regInfo ];
partitionTableType = selectPartitionTableLayout { inherit (cfg) useDefaultFilesystems useEFIBoot; };
# Bootloader should be installed on the system image only if we are booting through bootloaders.
# Though, if a user is not using our default filesystems, it is possible to not have any ESP
···
additionalPaths = [ regInfo ];
partitionTableType = "none";
installBootLoader = false;
···
-
if cfg.useDefaultFilesystems
-
if cfg.useEFIBoot then "efi_bootloading_with_default_fs"
-
else "legacy_bootloading_with_default_fs"
-
if cfg.directBoot.enable then "direct_boot_with_default_fs"
-
suggestedRootDevice = {
-
"efi_bootloading_with_default_fs" = "${cfg.bootLoaderDevice}2";
-
"legacy_bootloading_with_default_fs" = "${cfg.bootLoaderDevice}1";
-
"direct_boot_with_default_fs" = cfg.bootLoaderDevice;
-
# This will enforce a NixOS module type checking error
-
# to ask explicitly the user to set a rootDevice.
-
# As it will look like `rootDevice = lib.mkDefault null;` after
-
}.${bootConfiguration};
···
virtualisation.bootLoaderDevice =
-
default = lookupDriveDeviceName "root" cfg.qemu.drives;
-
defaultText = literalExpression ''lookupDriveDeviceName "root" cfg.qemu.drives'';
-
The disk to be used for the boot filesystem.
-
By default, it is the same disk as the root filesystem.
virtualisation.bootPartition =
type = types.nullOr types.path;
-
default = if cfg.useEFIBoot then "${cfg.bootLoaderDevice}1" else null;
-
defaultText = literalExpression ''if cfg.useEFIBoot then "''${cfg.bootLoaderDevice}1" else null'';
-
The boot partition to be used to mount /boot filesystem.
-
In legacy boots, this should be null.
-
By default, in EFI boot, it is the first partition of the boot device.
virtualisation.rootDevice =
type = types.nullOr types.path;
-
The disk or partition to be used for the root filesystem.
-
By default (read the source code for more details):
-
- under EFI with a bootloader: 2nd partition of the boot disk
-
- in legacy boot with a bootloader: 1st partition of the boot disk
-
- in direct boot (i.e. without a bootloader): whole disk
-
In case you are not using a default boot device or a default filesystem, you have to set explicitly your root device.
···
type = types.listOf (types.submodule driveOpts);
description = lib.mdDoc "Drives passed to qemu.";
-
apply = addDeviceNames;
···
# FIXME: make a sense of this mess wrt to multiple ESP present in the system, probably use boot.efiSysMountpoint?
boot.loader.grub.device = mkVMOverride (if cfg.useEFIBoot then "nodev" else cfg.bootLoaderDevice);
boot.loader.grub.gfxmodeBios = with cfg.resolution; "${toString x}x${toString y}";
-
virtualisation.rootDevice = mkDefault suggestedRootDevice;
boot.initrd.kernelModules = optionals (cfg.useNixStoreImage && !cfg.writableStore) [ "erofs" ];
boot.loader.supportsInitrdSecrets = mkIf (!cfg.useBootLoader) (mkVMOverride false);
-
boot.initrd.extraUtilsCommands = lib.mkIf (cfg.useDefaultFilesystems && !config.boot.initrd.systemd.enable)
-
# We need mke2fs in the initrd.
-
copy_bin_and_libs ${pkgs.e2fsprogs}/bin/mke2fs
-
boot.initrd.postDeviceCommands = lib.mkIf (cfg.useDefaultFilesystems && !config.boot.initrd.systemd.enable)
-
# If the disk image appears to be empty, run mke2fs to
-
FSTYPE=$(blkid -o value -s TYPE ${cfg.rootDevice} || true)
-
PARTTYPE=$(blkid -o value -s PTTYPE ${cfg.rootDevice} || true)
-
if test -z "$FSTYPE" -a -z "$PARTTYPE"; then
-
mke2fs -t ext4 ${cfg.rootDevice}
boot.initrd.postMountCommands = lib.mkIf (!config.boot.initrd.systemd.enable)
# Mark this as a NixOS machine.
···
driveExtraOpts.cache = "writeback";
driveExtraOpts.werror = "report";
deviceExtraOpts.bootindex = "1";
(mkIf cfg.useNixStoreImage [{
···
"/tmp" = lib.mkIf config.boot.tmp.useTmpfs {
···
options = [ "mode=1777" "strictatime" "nosuid" "nodev" "size=${toString config.boot.tmp.tmpfsSize}" ];
"/nix/${if cfg.writableStore then ".ro-store" else "store"}" = lib.mkIf cfg.useNixStoreImage {
-
device = "${lookupDriveDeviceName "nix-store" cfg.qemu.drives}";
···
"/boot" = lib.mkIf (cfg.useBootLoader && cfg.bootPartition != null) {
-
device = cfg.bootPartition; # 1 for e.g. `vda1`, as created in `systemImage`
noCheck = true; # fsck fails on a r/o filesystem