 013c7fa4ba
			
		
	
	
		013c7fa4ba
		
			
		
	
	
	
	
		
			
			'./*' produces arguments ordered by inode. efiDir produces, reliably, ./EFI, so just make all the directories known explicitly.
		
			
				
	
	
		
			664 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			664 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
| # This module creates a bootable ISO image containing the given NixOS
 | ||
| # configuration.  The derivation for the ISO image will be placed in
 | ||
| # config.system.build.isoImage.
 | ||
| 
 | ||
| { config, lib, pkgs, ... }:
 | ||
| 
 | ||
| with lib;
 | ||
| 
 | ||
| let
 | ||
|   /**
 | ||
|    * Given a list of `options`, concats the result of mapping each options
 | ||
|    * to a menuentry for use in grub.
 | ||
|    *
 | ||
|    *  * defaults: {name, image, params, initrd}
 | ||
|    *  * options: [ option... ]
 | ||
|    *  * option: {name, params, class}
 | ||
|    */
 | ||
|   menuBuilderGrub2 =
 | ||
|   defaults: options: lib.concatStrings
 | ||
|     (
 | ||
|       map
 | ||
|       (option: ''
 | ||
|         menuentry '${defaults.name} ${
 | ||
|         # Name appended to menuentry defaults to params if no specific name given.
 | ||
|         option.name or (if option ? params then "(${option.params})" else "")
 | ||
|         }' ${if option ? class then " --class ${option.class}" else ""} {
 | ||
|           linux ${defaults.image} ${defaults.params} ${
 | ||
|             option.params or ""
 | ||
|           }
 | ||
|           initrd ${defaults.initrd}
 | ||
|         }
 | ||
|       '')
 | ||
|       options
 | ||
|     )
 | ||
|   ;
 | ||
| 
 | ||
|   /**
 | ||
|    * Given a `config`, builds the default options.
 | ||
|    */
 | ||
|   buildMenuGrub2 = config:
 | ||
|     buildMenuAdditionalParamsGrub2 config ""
 | ||
|   ;
 | ||
| 
 | ||
|   /**
 | ||
|    * Given a `config` and params to add to `params`, build a set of default options.
 | ||
|    * Use this one when creating a variant (e.g. hidpi)
 | ||
|    */
 | ||
|   buildMenuAdditionalParamsGrub2 = config: additional:
 | ||
|   let
 | ||
|     finalCfg = {
 | ||
|       name = "NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel}";
 | ||
|       params = "init=${config.system.build.toplevel}/init ${additional} ${toString config.boot.kernelParams}";
 | ||
|       image = "/boot/${config.system.boot.loader.kernelFile}";
 | ||
|       initrd = "/boot/initrd";
 | ||
|     };
 | ||
|   in
 | ||
|     menuBuilderGrub2
 | ||
|     finalCfg
 | ||
|     [
 | ||
|       { class = "installer"; }
 | ||
|       { class = "nomodeset"; params = "nomodeset"; }
 | ||
|       { class = "copytoram"; params = "copytoram"; }
 | ||
|       { class = "debug";     params = "debug"; }
 | ||
|     ]
 | ||
|   ;
 | ||
| 
 | ||
|   # Timeout in syslinux is in units of 1/10 of a second.
 | ||
|   # 0 is used to disable timeouts.
 | ||
|   syslinuxTimeout = if config.boot.loader.timeout == null then
 | ||
|       0
 | ||
|     else
 | ||
|       max (config.boot.loader.timeout * 10) 1;
 | ||
| 
 | ||
| 
 | ||
|   max = x: y: if x > y then x else y;
 | ||
| 
 | ||
|   # The configuration file for syslinux.
 | ||
| 
 | ||
|   # Notes on syslinux configuration and UNetbootin compatiblity:
 | ||
|   #   * Do not use '/syslinux/syslinux.cfg' as the path for this
 | ||
|   #     configuration. UNetbootin will not parse the file and use it as-is.
 | ||
|   #     This results in a broken configuration if the partition label does
 | ||
|   #     not match the specified config.isoImage.volumeID. For this reason
 | ||
|   #     we're using '/isolinux/isolinux.cfg'.
 | ||
|   #   * Use APPEND instead of adding command-line arguments directly after
 | ||
|   #     the LINUX entries.
 | ||
|   #   * COM32 entries (chainload, reboot, poweroff) are not recognized. They
 | ||
|   #     result in incorrect boot entries.
 | ||
| 
 | ||
|   baseIsolinuxCfg = ''
 | ||
|     SERIAL 0 38400
 | ||
|     TIMEOUT ${builtins.toString syslinuxTimeout}
 | ||
|     UI vesamenu.c32
 | ||
|     MENU TITLE NixOS
 | ||
|     MENU BACKGROUND /isolinux/background.png
 | ||
|     MENU RESOLUTION 800 600
 | ||
|     MENU CLEAR
 | ||
|     MENU ROWS 6
 | ||
|     MENU CMDLINEROW -4
 | ||
|     MENU TIMEOUTROW -3
 | ||
|     MENU TABMSGROW  -2
 | ||
|     MENU HELPMSGROW -1
 | ||
|     MENU HELPMSGENDROW -1
 | ||
|     MENU MARGIN 0
 | ||
| 
 | ||
|     #                                FG:AARRGGBB  BG:AARRGGBB   shadow
 | ||
|     MENU COLOR BORDER       30;44      #00000000    #00000000   none
 | ||
|     MENU COLOR SCREEN       37;40      #FF000000    #00E2E8FF   none
 | ||
|     MENU COLOR TABMSG       31;40      #80000000    #00000000   none
 | ||
|     MENU COLOR TIMEOUT      1;37;40    #FF000000    #00000000   none
 | ||
|     MENU COLOR TIMEOUT_MSG  37;40      #FF000000    #00000000   none
 | ||
|     MENU COLOR CMDMARK      1;36;40    #FF000000    #00000000   none
 | ||
|     MENU COLOR CMDLINE      37;40      #FF000000    #00000000   none
 | ||
|     MENU COLOR TITLE        1;36;44    #00000000    #00000000   none
 | ||
|     MENU COLOR UNSEL        37;44      #FF000000    #00000000   none
 | ||
|     MENU COLOR SEL          7;37;40    #FFFFFFFF    #FF5277C3   std
 | ||
| 
 | ||
|     DEFAULT boot
 | ||
| 
 | ||
|     LABEL boot
 | ||
|     MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel}
 | ||
|     LINUX /boot/${config.system.boot.loader.kernelFile}
 | ||
|     APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}
 | ||
|     INITRD /boot/${config.system.boot.loader.initrdFile}
 | ||
| 
 | ||
|     # A variant to boot with 'nomodeset'
 | ||
|     LABEL boot-nomodeset
 | ||
|     MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (nomodeset)
 | ||
|     LINUX /boot/${config.system.boot.loader.kernelFile}
 | ||
|     APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} nomodeset
 | ||
|     INITRD /boot/${config.system.boot.loader.initrdFile}
 | ||
| 
 | ||
|     # A variant to boot with 'copytoram'
 | ||
|     LABEL boot-copytoram
 | ||
|     MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (copytoram)
 | ||
|     LINUX /boot/${config.system.boot.loader.kernelFile}
 | ||
|     APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} copytoram
 | ||
|     INITRD /boot/${config.system.boot.loader.initrdFile}
 | ||
| 
 | ||
|     # A variant to boot with verbose logging to the console
 | ||
|     LABEL boot-debug
 | ||
|     MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (debug)
 | ||
|     LINUX /boot/${config.system.boot.loader.kernelFile}
 | ||
|     APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} loglevel=7
 | ||
|     INITRD /boot/${config.system.boot.loader.initrdFile}
 | ||
|   '';
 | ||
| 
 | ||
|   isolinuxMemtest86Entry = ''
 | ||
|     LABEL memtest
 | ||
|     MENU LABEL Memtest86+
 | ||
|     LINUX /boot/memtest.bin
 | ||
|     APPEND ${toString config.boot.loader.grub.memtest86.params}
 | ||
|   '';
 | ||
| 
 | ||
|   isolinuxCfg = concatStringsSep "\n"
 | ||
|     ([ baseIsolinuxCfg ] ++ optional config.boot.loader.grub.memtest86.enable isolinuxMemtest86Entry);
 | ||
| 
 | ||
|   # Setup instructions for rEFInd.
 | ||
|   refind =
 | ||
|     if targetArch == "x64" then
 | ||
|       ''
 | ||
|       # Adds rEFInd to the ISO.
 | ||
|       cp -v ${pkgs.refind}/share/refind/refind_x64.efi $out/EFI/boot/
 | ||
|       ''
 | ||
|     else
 | ||
|       "# No refind for ${targetArch}"
 | ||
|   ;
 | ||
| 
 | ||
|   grubMenuCfg = ''
 | ||
|     #
 | ||
|     # Menu configuration
 | ||
|     #
 | ||
| 
 | ||
|     insmod gfxterm
 | ||
|     insmod png
 | ||
|     set gfxpayload=keep
 | ||
| 
 | ||
|     # Fonts can be loaded?
 | ||
|     # (This font is assumed to always be provided as a fallback by NixOS)
 | ||
|     if loadfont (hd0)/EFI/boot/unicode.pf2; then
 | ||
|       # Use graphical term, it can be either with background image or a theme.
 | ||
|       # input is "console", while output is "gfxterm".
 | ||
|       # This enables "serial" input and output only when possible.
 | ||
|       # Otherwise the failure mode is to not even enable gfxterm.
 | ||
|       if test "\$with_serial" == "yes"; then
 | ||
|         terminal_output gfxterm serial
 | ||
|         terminal_input  console serial
 | ||
|       else
 | ||
|         terminal_output gfxterm
 | ||
|         terminal_input  console
 | ||
|       fi
 | ||
|     else
 | ||
|       # Sets colors for the non-graphical term.
 | ||
|       set menu_color_normal=cyan/blue
 | ||
|       set menu_color_highlight=white/blue
 | ||
|     fi
 | ||
| 
 | ||
|     ${ # When there is a theme configured, use it, otherwise use the background image.
 | ||
|     if (!isNull config.isoImage.grubTheme) then ''
 | ||
|       # Sets theme.
 | ||
|       set theme=(hd0)/EFI/boot/grub-theme/theme.txt
 | ||
|       # Load theme fonts
 | ||
|       $(find ${config.isoImage.grubTheme} -iname '*.pf2' -printf "loadfont (hd0)/EFI/boot/grub-theme/%P\n")
 | ||
|     '' else ''
 | ||
|       if background_image (hd0)/EFI/boot/efi-background.png; then
 | ||
|         # Black background means transparent background when there
 | ||
|         # is a background image set... This seems undocumented :(
 | ||
|         set color_normal=black/black
 | ||
|         set color_highlight=white/blue
 | ||
|       else
 | ||
|         # Falls back again to proper colors.
 | ||
|         set menu_color_normal=cyan/blue
 | ||
|         set menu_color_highlight=white/blue
 | ||
|       fi
 | ||
|     ''}
 | ||
|   '';
 | ||
| 
 | ||
|   # The EFI boot image.
 | ||
|   # Notes about grub:
 | ||
|   #  * Yes, the grubMenuCfg has to be repeated in all submenus. Otherwise you
 | ||
|   #    will get white-on-black console-like text on sub-menus. *sigh*
 | ||
|   efiDir = pkgs.runCommand "efi-directory" {} ''
 | ||
|     mkdir -p $out/EFI/boot/
 | ||
| 
 | ||
|     # ALWAYS required modules.
 | ||
|     MODULES="fat iso9660 part_gpt part_msdos \
 | ||
|              normal boot linux configfile loopback chain halt \
 | ||
|              efifwsetup efi_gop \
 | ||
|              ls search search_label search_fs_uuid search_fs_file \
 | ||
|              gfxmenu gfxterm gfxterm_background gfxterm_menu test all_video loadenv \
 | ||
|              exfat ext2 ntfs btrfs hfsplus udf \
 | ||
|              videoinfo png \
 | ||
|              echo serial \
 | ||
|             "
 | ||
| 
 | ||
|     echo "Building GRUB with modules:"
 | ||
|     for mod in $MODULES; do
 | ||
|       echo " - $mod"
 | ||
|     done
 | ||
| 
 | ||
|     # Modules that may or may not be available per-platform.
 | ||
|     echo "Adding additional modules:"
 | ||
|     for mod in efi_uga; do
 | ||
|       if [ -f ${pkgs.grub2_efi}/lib/grub/${pkgs.grub2_efi.grubTarget}/$mod.mod ]; then
 | ||
|         echo " - $mod"
 | ||
|         MODULES+=" $mod"
 | ||
|       fi
 | ||
|     done
 | ||
| 
 | ||
|     # Make our own efi program, we can't rely on "grub-install" since it seems to
 | ||
|     # probe for devices, even with --skip-fs-probe.
 | ||
|     ${pkgs.grub2_efi}/bin/grub-mkimage -o $out/EFI/boot/boot${targetArch}.efi -p /EFI/boot -O ${pkgs.grub2_efi.grubTarget} \
 | ||
|       $MODULES
 | ||
|     cp ${pkgs.grub2_efi}/share/grub/unicode.pf2 $out/EFI/boot/
 | ||
| 
 | ||
|     cat <<EOF > $out/EFI/boot/grub.cfg
 | ||
| 
 | ||
|     # If you want to use serial for "terminal_*" commands, you need to set one up:
 | ||
|     #   Example manual configuration:
 | ||
|     #    → serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
 | ||
|     # This uses the defaults, and makes the serial terminal available.
 | ||
|     set with_serial=no
 | ||
|     if serial; then set with_serial=yes ;fi
 | ||
|     export with_serial
 | ||
|     clear
 | ||
|     set timeout=10
 | ||
|     ${grubMenuCfg}
 | ||
| 
 | ||
|     #
 | ||
|     # Menu entries
 | ||
|     #
 | ||
| 
 | ||
|     ${buildMenuGrub2 config}
 | ||
|     submenu "HiDPI, Quirks and Accessibility" --class hidpi --class submenu {
 | ||
|       ${grubMenuCfg}
 | ||
|       submenu "Suggests resolution @720p" --class hidpi-720p {
 | ||
|         ${grubMenuCfg}
 | ||
|         ${buildMenuAdditionalParamsGrub2 config "video=1280x720@60"}
 | ||
|       }
 | ||
|       submenu "Suggests resolution @1080p" --class hidpi-1080p {
 | ||
|         ${grubMenuCfg}
 | ||
|         ${buildMenuAdditionalParamsGrub2 config "video=1920x1080@60"}
 | ||
|       }
 | ||
| 
 | ||
|       # Some laptop and convertibles have the panel installed in an
 | ||
|       # inconvenient way, rotated away from the keyboard.
 | ||
|       # Those entries makes it easier to use the installer.
 | ||
|       submenu "" {return}
 | ||
|       submenu "Rotate framebuffer Clockwise" --class rotate-90cw {
 | ||
|         ${grubMenuCfg}
 | ||
|         ${buildMenuAdditionalParamsGrub2 config "fbcon=rotate:1"}
 | ||
|       }
 | ||
|       submenu "Rotate framebuffer Upside-Down" --class rotate-180 {
 | ||
|         ${grubMenuCfg}
 | ||
|         ${buildMenuAdditionalParamsGrub2 config "fbcon=rotate:2"}
 | ||
|       }
 | ||
|       submenu "Rotate framebuffer Counter-Clockwise" --class rotate-90ccw {
 | ||
|         ${grubMenuCfg}
 | ||
|         ${buildMenuAdditionalParamsGrub2 config "fbcon=rotate:3"}
 | ||
|       }
 | ||
| 
 | ||
|       # As a proof of concept, mainly. (Not sure it has accessibility merits.)
 | ||
|       submenu "" {return}
 | ||
|       submenu "Use black on white" --class accessibility-blakconwhite {
 | ||
|         ${grubMenuCfg}
 | ||
|         ${buildMenuAdditionalParamsGrub2 config "vt.default_red=0xFF,0xBC,0x4F,0xB4,0x56,0xBC,0x4F,0x00,0xA1,0xCF,0x84,0xCA,0x8D,0xB4,0x84,0x68 vt.default_grn=0xFF,0x55,0xBA,0xBA,0x4D,0x4D,0xB3,0x00,0xA0,0x8F,0xB3,0xCA,0x88,0x93,0xA4,0x68 vt.default_blu=0xFF,0x58,0x5F,0x58,0xC5,0xBD,0xC5,0x00,0xA8,0xBB,0xAB,0x97,0xBD,0xC7,0xC5,0x68"}
 | ||
|       }
 | ||
| 
 | ||
|       # Serial access is a must!
 | ||
|       submenu "" {return}
 | ||
|       submenu "Serial console=ttyS0,115200n8" --class serial {
 | ||
|         ${grubMenuCfg}
 | ||
|         ${buildMenuAdditionalParamsGrub2 config "console=ttyS0,115200n8"}
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     menuentry 'rEFInd' --class refind {
 | ||
|       # UUID is hard-coded in the derivation.
 | ||
|       search --set=root --no-floppy --fs-uuid 1234-5678
 | ||
|       chainloader (\$root)/EFI/boot/refind_x64.efi
 | ||
|     }
 | ||
|     menuentry 'Firmware Setup' --class settings {
 | ||
|       fwsetup
 | ||
|       clear
 | ||
|       echo ""
 | ||
|       echo "If you see this message, your EFI system doesn't support this feature."
 | ||
|       echo ""
 | ||
|     }
 | ||
|     menuentry 'Shutdown' --class shutdown {
 | ||
|       halt
 | ||
|     }
 | ||
|     EOF
 | ||
| 
 | ||
|     ${refind}
 | ||
|   '';
 | ||
| 
 | ||
|   efiImg = pkgs.runCommand "efi-image_eltorito" { buildInputs = [ pkgs.mtools pkgs.libfaketime ]; }
 | ||
|     # Be careful about determinism: du --apparent-size,
 | ||
|     #   dates (cp -p, touch, mcopy -m, faketime for label), IDs (mkfs.vfat -i)
 | ||
|     ''
 | ||
|       mkdir ./contents && cd ./contents
 | ||
|       cp -rp "${efiDir}"/EFI .
 | ||
|       mkdir ./boot
 | ||
|       cp -p "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}" \
 | ||
|         "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}" ./boot/
 | ||
|       touch --date=@0 ./EFI ./boot
 | ||
| 
 | ||
|       usage_size=$(du -sb --apparent-size . | tr -cd '[:digit:]')
 | ||
|       # Make the image 110% as big as the files need to make up for FAT overhead
 | ||
|       image_size=$(( ($usage_size * 110) / 100 ))
 | ||
|       # Make the image fit blocks of 1M
 | ||
|       block_size=$((1024*1024))
 | ||
|       image_size=$(( ($image_size / $block_size + 1) * $block_size ))
 | ||
|       echo "Usage size: $usage_size"
 | ||
|       echo "Image size: $image_size"
 | ||
|       truncate --size=$image_size "$out"
 | ||
|       ${pkgs.libfaketime}/bin/faketime "2000-01-01 00:00:00" ${pkgs.dosfstools}/sbin/mkfs.vfat -i 12345678 -n EFIBOOT "$out"
 | ||
|       mcopy -psvm -i "$out" ./EFI ./boot ::
 | ||
|       # Verify the FAT partition.
 | ||
|       ${pkgs.dosfstools}/sbin/fsck.vfat -vn "$out"
 | ||
|     ''; # */
 | ||
| 
 | ||
|   # Name used by UEFI for architectures.
 | ||
|   targetArch =
 | ||
|     if pkgs.stdenv.isi686 then
 | ||
|       "ia32"
 | ||
|     else if pkgs.stdenv.isx86_64 then
 | ||
|       "x64"
 | ||
|     else if pkgs.stdenv.isAarch64 then
 | ||
|       "aa64"
 | ||
|     else
 | ||
|       throw "Unsupported architecture";
 | ||
| 
 | ||
|   # Syslinux (and isolinux) only supports x86-based architectures.
 | ||
|   canx86BiosBoot = pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64;
 | ||
| 
 | ||
| in
 | ||
| 
 | ||
| {
 | ||
|   options = {
 | ||
| 
 | ||
|     isoImage.isoName = mkOption {
 | ||
|       default = "${config.isoImage.isoBaseName}.iso";
 | ||
|       description = ''
 | ||
|         Name of the generated ISO image file.
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|     isoImage.isoBaseName = mkOption {
 | ||
|       default = "nixos";
 | ||
|       description = ''
 | ||
|         Prefix of the name of the generated ISO image file.
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|     isoImage.compressImage = mkOption {
 | ||
|       default = false;
 | ||
|       description = ''
 | ||
|         Whether the ISO image should be compressed using
 | ||
|         <command>bzip2</command>.
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|     isoImage.volumeID = mkOption {
 | ||
|       default = "NIXOS_BOOT_CD";
 | ||
|       description = ''
 | ||
|         Specifies the label or volume ID of the generated ISO image.
 | ||
|         Note that the label is used by stage 1 of the boot process to
 | ||
|         mount the CD, so it should be reasonably distinctive.
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|     isoImage.contents = mkOption {
 | ||
|       example = literalExample ''
 | ||
|         [ { source = pkgs.memtest86 + "/memtest.bin";
 | ||
|             target = "boot/memtest.bin";
 | ||
|           }
 | ||
|         ]
 | ||
|       '';
 | ||
|       description = ''
 | ||
|         This option lists files to be copied to fixed locations in the
 | ||
|         generated ISO image.
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|     isoImage.storeContents = mkOption {
 | ||
|       example = literalExample "[ pkgs.stdenv ]";
 | ||
|       description = ''
 | ||
|         This option lists additional derivations to be included in the
 | ||
|         Nix store in the generated ISO image.
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|     isoImage.includeSystemBuildDependencies = mkOption {
 | ||
|       default = false;
 | ||
|       description = ''
 | ||
|         Set this option to include all the needed sources etc in the
 | ||
|         image. It significantly increases image size. Use that when
 | ||
|         you want to be able to keep all the sources needed to build your
 | ||
|         system or when you are going to install the system on a computer
 | ||
|         with slow or non-existent network connection.
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|     isoImage.makeEfiBootable = mkOption {
 | ||
|       default = false;
 | ||
|       description = ''
 | ||
|         Whether the ISO image should be an efi-bootable volume.
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|     isoImage.makeUsbBootable = mkOption {
 | ||
|       default = false;
 | ||
|       description = ''
 | ||
|         Whether the ISO image should be bootable from CD as well as USB.
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|     isoImage.efiSplashImage = mkOption {
 | ||
|       default = pkgs.fetchurl {
 | ||
|           url = https://raw.githubusercontent.com/NixOS/nixos-artwork/a9e05d7deb38a8e005a2b52575a3f59a63a4dba0/bootloader/efi-background.png;
 | ||
|           sha256 = "18lfwmp8yq923322nlb9gxrh5qikj1wsk6g5qvdh31c4h5b1538x";
 | ||
|         };
 | ||
|       description = ''
 | ||
|         The splash image to use in the EFI bootloader.
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|     isoImage.splashImage = mkOption {
 | ||
|       default = pkgs.fetchurl {
 | ||
|           url = https://raw.githubusercontent.com/NixOS/nixos-artwork/a9e05d7deb38a8e005a2b52575a3f59a63a4dba0/bootloader/isolinux/bios-boot.png;
 | ||
|           sha256 = "1wp822zrhbg4fgfbwkr7cbkr4labx477209agzc0hr6k62fr6rxd";
 | ||
|         };
 | ||
|       description = ''
 | ||
|         The splash image to use in the legacy-boot bootloader.
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|     isoImage.grubTheme = mkOption {
 | ||
|       default = pkgs.nixos-grub2-theme;
 | ||
|       type = types.nullOr (types.either types.path types.package);
 | ||
|       description = ''
 | ||
|         The grub2 theme used for UEFI boot.
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|     isoImage.appendToMenuLabel = mkOption {
 | ||
|       default = " Installer";
 | ||
|       example = " Live System";
 | ||
|       description = ''
 | ||
|         The string to append after the menu label for the NixOS system.
 | ||
|         This will be directly appended (without whitespace) to the NixOS version
 | ||
|         string, like for example if it is set to <literal>XXX</literal>:
 | ||
| 
 | ||
|         <para><literal>NixOS 99.99-pre666XXX</literal></para>
 | ||
|       '';
 | ||
|     };
 | ||
| 
 | ||
|   };
 | ||
| 
 | ||
|   config = {
 | ||
| 
 | ||
|     boot.loader.grub.version = 2;
 | ||
| 
 | ||
|     # Don't build the GRUB menu builder script, since we don't need it
 | ||
|     # here and it causes a cyclic dependency.
 | ||
|     boot.loader.grub.enable = false;
 | ||
| 
 | ||
|     environment.systemPackages = [ pkgs.grub2 pkgs.grub2_efi ]
 | ||
|       ++ optional canx86BiosBoot pkgs.syslinux
 | ||
|     ;
 | ||
| 
 | ||
|     # In stage 1 of the boot, mount the CD as the root FS by label so
 | ||
|     # that we don't need to know its device.  We pass the label of the
 | ||
|     # root filesystem on the kernel command line, rather than in
 | ||
|     # `fileSystems' below.  This allows CD-to-USB converters such as
 | ||
|     # UNetbootin to rewrite the kernel command line to pass the label or
 | ||
|     # UUID of the USB stick.  It would be nicer to write
 | ||
|     # `root=/dev/disk/by-label/...' here, but UNetbootin doesn't
 | ||
|     # recognise that.
 | ||
|     boot.kernelParams =
 | ||
|       [ "root=LABEL=${config.isoImage.volumeID}"
 | ||
|         "boot.shell_on_fail"
 | ||
|       ];
 | ||
| 
 | ||
|     fileSystems."/" =
 | ||
|       { fsType = "tmpfs";
 | ||
|         options = [ "mode=0755" ];
 | ||
|       };
 | ||
| 
 | ||
|     # Note that /dev/root is a symlink to the actual root device
 | ||
|     # specified on the kernel command line, created in the stage 1
 | ||
|     # init script.
 | ||
|     fileSystems."/iso" =
 | ||
|       { device = "/dev/root";
 | ||
|         neededForBoot = true;
 | ||
|         noCheck = true;
 | ||
|       };
 | ||
| 
 | ||
|     # In stage 1, mount a tmpfs on top of /nix/store (the squashfs
 | ||
|     # image) to make this a live CD.
 | ||
|     fileSystems."/nix/.ro-store" =
 | ||
|       { fsType = "squashfs";
 | ||
|         device = "/iso/nix-store.squashfs";
 | ||
|         options = [ "loop" ];
 | ||
|         neededForBoot = true;
 | ||
|       };
 | ||
| 
 | ||
|     fileSystems."/nix/.rw-store" =
 | ||
|       { fsType = "tmpfs";
 | ||
|         options = [ "mode=0755" ];
 | ||
|         neededForBoot = true;
 | ||
|       };
 | ||
| 
 | ||
|     fileSystems."/nix/store" =
 | ||
|       { fsType = "unionfs-fuse";
 | ||
|         device = "unionfs";
 | ||
|         options = [ "allow_other" "cow" "nonempty" "chroot=/mnt-root" "max_files=32768" "hide_meta_files" "dirs=/nix/.rw-store=rw:/nix/.ro-store=ro" ];
 | ||
|       };
 | ||
| 
 | ||
|     boot.initrd.availableKernelModules = [ "squashfs" "iso9660" "uas" ];
 | ||
| 
 | ||
|     boot.blacklistedKernelModules = [ "nouveau" ];
 | ||
| 
 | ||
|     boot.initrd.kernelModules = [ "loop" ];
 | ||
| 
 | ||
|     # Closures to be copied to the Nix store on the CD, namely the init
 | ||
|     # script and the top-level system configuration directory.
 | ||
|     isoImage.storeContents =
 | ||
|       [ config.system.build.toplevel ] ++
 | ||
|       optional config.isoImage.includeSystemBuildDependencies
 | ||
|         config.system.build.toplevel.drvPath;
 | ||
| 
 | ||
|     # Create the squashfs image that contains the Nix store.
 | ||
|     system.build.squashfsStore = pkgs.callPackage ../../../lib/make-squashfs.nix {
 | ||
|       storeContents = config.isoImage.storeContents;
 | ||
|     };
 | ||
| 
 | ||
|     # Individual files to be included on the CD, outside of the Nix
 | ||
|     # store on the CD.
 | ||
|     isoImage.contents =
 | ||
|       [
 | ||
|         { source = config.boot.kernelPackages.kernel + "/" + config.system.boot.loader.kernelFile;
 | ||
|           target = "/boot/" + config.system.boot.loader.kernelFile;
 | ||
|         }
 | ||
|         { source = config.system.build.initialRamdisk + "/" + config.system.boot.loader.initrdFile;
 | ||
|           target = "/boot/" + config.system.boot.loader.initrdFile;
 | ||
|         }
 | ||
|         { source = config.system.build.squashfsStore;
 | ||
|           target = "/nix-store.squashfs";
 | ||
|         }
 | ||
|         { source = config.isoImage.efiSplashImage;
 | ||
|           target = "/EFI/boot/efi-background.png";
 | ||
|         }
 | ||
|         { source = config.isoImage.splashImage;
 | ||
|           target = "/isolinux/background.png";
 | ||
|         }
 | ||
|         { source = pkgs.writeText "version" config.system.nixos.label;
 | ||
|           target = "/version.txt";
 | ||
|         }
 | ||
|       ] ++ optionals canx86BiosBoot [
 | ||
|         { source = pkgs.substituteAll  {
 | ||
|             name = "isolinux.cfg";
 | ||
|             src = pkgs.writeText "isolinux.cfg-in" isolinuxCfg;
 | ||
|             bootRoot = "/boot";
 | ||
|           };
 | ||
|           target = "/isolinux/isolinux.cfg";
 | ||
|         }
 | ||
|         { source = "${pkgs.syslinux}/share/syslinux";
 | ||
|           target = "/isolinux";
 | ||
|         }
 | ||
|       ] ++ optionals config.isoImage.makeEfiBootable [
 | ||
|         { source = efiImg;
 | ||
|           target = "/boot/efi.img";
 | ||
|         }
 | ||
|         { source = "${efiDir}/EFI";
 | ||
|           target = "/EFI";
 | ||
|         }
 | ||
|       ] ++ optionals (config.boot.loader.grub.memtest86.enable && canx86BiosBoot) [
 | ||
|         { source = "${pkgs.memtest86plus}/memtest.bin";
 | ||
|           target = "/boot/memtest.bin";
 | ||
|         }
 | ||
|       ] ++ optionals (!isNull config.isoImage.grubTheme) [
 | ||
|         { source = config.isoImage.grubTheme;
 | ||
|           target = "/EFI/boot/grub-theme";
 | ||
|         }
 | ||
|       ];
 | ||
| 
 | ||
|     boot.loader.timeout = 10;
 | ||
| 
 | ||
|     # Create the ISO image.
 | ||
|     system.build.isoImage = pkgs.callPackage ../../../lib/make-iso9660-image.nix ({
 | ||
|       inherit (config.isoImage) isoName compressImage volumeID contents;
 | ||
|       bootable = canx86BiosBoot;
 | ||
|       bootImage = "/isolinux/isolinux.bin";
 | ||
|       syslinux = if canx86BiosBoot then pkgs.syslinux else null;
 | ||
|     } // optionalAttrs (config.isoImage.makeUsbBootable && canx86BiosBoot) {
 | ||
|       usbBootable = true;
 | ||
|       isohybridMbrImage = "${pkgs.syslinux}/share/syslinux/isohdpfx.bin";
 | ||
|     } // optionalAttrs config.isoImage.makeEfiBootable {
 | ||
|       efiBootable = true;
 | ||
|       efiBootImage = "boot/efi.img";
 | ||
|     });
 | ||
| 
 | ||
|     boot.postBootCommands =
 | ||
|       ''
 | ||
|         # After booting, register the contents of the Nix store on the
 | ||
|         # CD in the Nix database in the tmpfs.
 | ||
|         ${config.nix.package.out}/bin/nix-store --load-db < /nix/store/nix-path-registration
 | ||
| 
 | ||
|         # nixos-rebuild also requires a "system" profile and an
 | ||
|         # /etc/NIXOS tag.
 | ||
|         touch /etc/NIXOS
 | ||
|         ${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
 | ||
|       '';
 | ||
| 
 | ||
|     # Add vfat support to the initrd to enable people to copy the
 | ||
|     # contents of the CD to a bootable USB stick.
 | ||
|     boot.initrd.supportedFilesystems = [ "vfat" ];
 | ||
| 
 | ||
|   };
 | ||
| 
 | ||
| }
 |