summary refs log tree commit diff
path: root/nixos/modules/installer
diff options
context:
space:
mode:
authorSamuel Dionne-Riel <samuel@dionne-riel.com>2018-01-11 23:32:56 -0500
committerSamuel Dionne-Riel <samuel@dionne-riel.com>2018-08-24 13:04:56 -0400
commit41e7de42de030e47d273ab143732cdcb3547ab9a (patch)
tree0bc88aaec7217a1900e40335f0952fa435ac212d /nixos/modules/installer
parent2f7d9c9f78ae36bc8eedd3969b131a393aded413 (diff)
downloadnixlib-41e7de42de030e47d273ab143732cdcb3547ab9a.tar
nixlib-41e7de42de030e47d273ab143732cdcb3547ab9a.tar.gz
nixlib-41e7de42de030e47d273ab143732cdcb3547ab9a.tar.bz2
nixlib-41e7de42de030e47d273ab143732cdcb3547ab9a.tar.lz
nixlib-41e7de42de030e47d273ab143732cdcb3547ab9a.tar.xz
nixlib-41e7de42de030e47d273ab143732cdcb3547ab9a.tar.zst
nixlib-41e7de42de030e47d273ab143732cdcb3547ab9a.zip
Use a themed grub for the installer image
This replaces systemd-boot with grub, it is at feature parity, as in it
can do everything systemd-boot did in the previous commit.
Diffstat (limited to 'nixos/modules/installer')
-rw-r--r--nixos/modules/installer/cd-dvd/iso-image.nix279
1 files changed, 228 insertions, 51 deletions
diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix
index 0dbdd39d639a..74fce0d1721d 100644
--- a/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -7,6 +7,63 @@
 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/bzImage";
+      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
@@ -104,60 +161,158 @@ let
       ''
       # Adds rEFInd to the ISO.
       cp -v ${pkgs.refind}/share/refind/refind_x64.efi $out/EFI/boot/
-
-      # Makes it bootable through systemd-boot.
-      # It purposefully does not have a refind configuration file nor theme.
-      cat << EOF > $out/loader/entries/zz-rEFInd.conf
-      title rEFInd rescue bootloader
-      efi /EFI/boot/refind_x64.efi
-      EOF
       ''
     else
       "# No refind for ia32"
   ;
 
+  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
-    cp -v ${pkgs.systemd}/lib/systemd/boot/efi/systemd-boot${targetArch}.efi $out/EFI/boot/boot${targetArch}.efi
-    mkdir -p $out/loader/entries
-
-    cat << EOF > $out/loader/entries/nixos-iso.conf
-    title NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel}
-    linux /boot/${config.system.boot.loader.kernelFile}
-    initrd /boot/${config.system.boot.loader.initrdFile}
-    options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}
-    EOF
-
-    # A variant to boot with 'nomodeset'
-    cat << EOF > $out/loader/entries/nixos-iso-nomodeset.conf
-    title NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel}
-    version nomodeset
-    linux /boot/${config.system.boot.loader.kernelFile}
-    initrd /boot/${config.system.boot.loader.initrdFile}
-    options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} nomodeset
-    EOF
-
-    # A variant to boot with 'copytoram'
-    cat << EOF > $out/loader/entries/nixos-iso-copytoram.conf
-    title NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel}
-    version copytoram
-    linux /boot/${config.system.boot.loader.kernelFile}
-    initrd /boot/${config.system.boot.loader.initrdFile}
-    options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} copytoram
-    EOF
-
-    # A variant to boot with verbose logging to the console
-    cat << EOF > $out/loader/entries/nixos-iso-debug.conf
-    title NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (debug)
-    linux /boot/${config.system.boot.loader.kernelFile}
-    initrd /boot/${config.system.boot.loader.initrdFile}
-    options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} loglevel=7
-    EOF
-
-    cat << EOF > $out/loader/loader.conf
-    default nixos-iso
-    timeout ${builtins.toString config.boot.loader.timeout}
+    mkdir -p $out/EFI/boot/
+
+    MODULES="fat iso9660 part_gpt part_msdos \
+             normal boot linux configfile loopback chain halt \
+             efifwsetup efi_gop efi_uga \
+             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 \
+            "
+    # 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/bootx64.efi -p /EFI/boot -O x86_64-efi \
+      $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}
@@ -276,13 +431,31 @@ in
       '';
     };
 
+    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 bootloader.
+        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.
       '';
     };
 
@@ -400,6 +573,9 @@ in
         { source = "${pkgs.syslinux}/share/syslinux";
           target = "/isolinux";
         }
+        { source = config.isoImage.efiSplashImage;
+          target = "/EFI/boot/efi-background.png";
+        }
         { source = config.isoImage.splashImage;
           target = "/isolinux/background.png";
         }
@@ -413,13 +589,14 @@ in
         { source = "${efiDir}/EFI";
           target = "/EFI";
         }
-        { source = "${efiDir}/loader";
-          target = "/loader";
-        }
       ] ++ optionals config.boot.loader.grub.memtest86.enable [
         { 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;