From 6d176afe5e3664e2a522afcc59c5dc3a5b40c455 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Sat, 2 May 2015 05:56:48 +0300 Subject: [PATCH] generic-extlinux-compatible: Add new bootloader for ARM This module generates a /boot/extlinux/extlinux.conf bootloader configuration file that is supported by e.g. U-Boot: http://git.denx.de/?p=u-boot.git;a=blob;f=doc/README.distro;hb=refs/heads/master With this, all ARM boards supported by U-Boot can be booted in a common way (a single boot file generator, all boards booting via initrd like x86) and with same boot menu functionality as GRUB has. -- sample extlinux.conf file -- # Generated file, all changes will be lost on nixos-rebuild! # Change this to e.g. nixos-42 to temporarily boot to an older configuration. DEFAULT nixos-default TIMEOUT 50 LABEL nixos-default MENU LABEL NixOS - Default LINUX ../nixos/n7vxfk60nb5h0mcbhkwwxhcz2q2nvxzv-linux-4.1.0-rc3-cpufreq-zImage INITRD ../nixos/0ss2zs8sb6d1qn4gblxpwlxkfjsgs5f0-initrd-initrd FDTDIR ../nixos/n7vxfk60nb5h0mcbhkwwxhcz2q2nvxzv-linux-4.1.0-rc3-cpufreq-dtbs APPEND systemConfig=/nix/store/469qvr43ln8bfsnk5lzcz6m6jfcgdd4r-nixos-15.06.git.0b7a7a6M init=/nix/store/469qvr43ln8bfsnk5lzcz6m6jfcgdd4r-nixos-15.06.git.0b7a7a6M/init loglevel=8 console=ttyS0,115200n8 drm.debug=0xf LABEL nixos-71 MENU LABEL NixOS - Configuration 71 (2015-05-17 21:32 - 15.06.git.0b7a7a6M) LINUX ../nixos/n7vxfk60nb5h0mcbhkwwxhcz2q2nvxzv-linux-4.1.0-rc3-cpufreq-zImage INITRD ../nixos/0ss2zs8sb6d1qn4gblxpwlxkfjsgs5f0-initrd-initrd FDTDIR ../nixos/n7vxfk60nb5h0mcbhkwwxhcz2q2nvxzv-linux-4.1.0-rc3-cpufreq-dtbs APPEND systemConfig=/nix/store/469qvr43ln8bfsnk5lzcz6m6jfcgdd4r-nixos-15.06.git.0b7a7a6M init=/nix/store/469qvr43ln8bfsnk5lzcz6m6jfcgdd4r-nixos-15.06.git.0b7a7a6M/init loglevel=8 console=ttyS0,115200n8 drm.debug=0xf --- nixos/modules/module-list.nix | 1 + .../generic-extlinux-compatible/default.nix | 44 ++++++ .../extlinux-conf-builder.nix | 8 ++ .../extlinux-conf-builder.sh | 132 ++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 nixos/modules/system/boot/loader/generic-extlinux-compatible/default.nix create mode 100644 nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix create mode 100644 nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 043b0470edf..3d938869e52 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -411,6 +411,7 @@ ./system/boot/loader/efi.nix ./system/boot/loader/loader.nix ./system/boot/loader/generations-dir/generations-dir.nix + ./system/boot/loader/generic-extlinux-compatible ./system/boot/loader/grub/grub.nix ./system/boot/loader/grub/ipxe.nix ./system/boot/loader/grub/memtest.nix diff --git a/nixos/modules/system/boot/loader/generic-extlinux-compatible/default.nix b/nixos/modules/system/boot/loader/generic-extlinux-compatible/default.nix new file mode 100644 index 00000000000..af39c7bb684 --- /dev/null +++ b/nixos/modules/system/boot/loader/generic-extlinux-compatible/default.nix @@ -0,0 +1,44 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + blCfg = config.boot.loader; + cfg = blCfg.generic-extlinux-compatible; + + timeoutStr = if blCfg.timeout == null then "-1" else toString blCfg.timeout; + + builder = import ./extlinux-conf-builder.nix { inherit pkgs; }; +in +{ + options = { + boot.loader.generic-extlinux-compatible = { + enable = mkOption { + default = false; + type = types.bool; + description = '' + Whether to generate an extlinux-compatible configuration file + under /boot/extlinux.conf. For instance, + U-Boot's generic distro boot support uses this file format. + + See U-boot's documentation + for more information. + ''; + }; + + configurationLimit = mkOption { + default = 20; + example = 10; + type = types.int; + description = '' + Maximum number of configurations in the boot menu. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + system.build.installBootLoader = "${builder} -g ${toString cfg.configurationLimit} -t ${timeoutStr} -c"; + system.boot.loader.id = "generic-extlinux-compatible"; + }; +} diff --git a/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix new file mode 100644 index 00000000000..261192c6d24 --- /dev/null +++ b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix @@ -0,0 +1,8 @@ +{ pkgs }: + +pkgs.substituteAll { + src = ./extlinux-conf-builder.sh; + isExecutable = true; + inherit (pkgs) bash; + path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep]; +} diff --git a/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh new file mode 100644 index 00000000000..8f2a496de8b --- /dev/null +++ b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh @@ -0,0 +1,132 @@ +#! @bash@/bin/sh -e + +shopt -s nullglob + +export PATH=/empty +for i in @path@; do PATH=$PATH:$i/bin; done + +usage() { + echo "usage: $0 -t -c [-d ] [-g ]" >&2 + exit 1 +} + +timeout= # Timeout in centiseconds +default= # Default configuration +target=/boot # Target directory +numGenerations=0 # Number of other generations to include in the menu + +while getopts "t:c:d:g:" opt; do + case "$opt" in + t) # U-Boot interprets '0' as infinite and negative as instant boot + if [ "$OPTARG" -lt 0 ]; then + timeout=0 + elif [ "$OPTARG" = 0 ]; then + timeout=-10 + else + timeout=$((OPTARG * 10)) + fi + ;; + c) default="$OPTARG" ;; + d) target="$OPTARG" ;; + g) numGenerations="$OPTARG" ;; + \?) usage ;; + esac +done + +[ "$timeout" = "" -o "$default" = "" ] && usage + +mkdir -p $target/nixos +mkdir -p $target/extlinux + +# Convert a path to a file in the Nix store such as +# /nix/store/-/file to --. +cleanName() { + local path="$1" + echo "$path" | sed 's|^/nix/store/||' | sed 's|/|-|g' +} + +# Copy a file from the Nix store to $target/nixos. +declare -A filesCopied + +copyToKernelsDir() { + local src=$(readlink -f "$1") + local dst="$target/nixos/$(cleanName $src)" + # Don't copy the file if $dst already exists. This means that we + # have to create $dst atomically to prevent partially copied + # kernels or initrd if this script is ever interrupted. + if ! test -e $dst; then + local dstTmp=$dst.tmp.$$ + cp -r $src $dstTmp + mv $dstTmp $dst + fi + filesCopied[$dst]=1 + result=$dst +} + +# Copy its kernel, initrd and dtbs to $target/nixos, and echo out an +# extlinux menu entry +addEntry() { + local path=$(readlink -f "$1") + local tag="$2" # Generation number or 'default' + + if ! test -e $path/kernel -a -e $path/initrd; then + return + fi + + copyToKernelsDir "$path/kernel"; kernel=$result + copyToKernelsDir "$path/initrd"; initrd=$result + # XXX UGLY: maybe the system config should have a top-level "dtbs" entry? + copyToKernelsDir $(readlink -m "$path/kernel/../dtbs"); dtbs=$result + + timestampEpoch=$(stat -L -c '%Z' $path) + + timestamp=$(date "+%Y-%m-%d %H:%M" -d @$timestampEpoch) + nixosVersion="$(cat $path/nixos-version)" + extraParams="$(cat $path/kernel-params)" + + echo + echo "LABEL nixos-$tag" + if [ "$tag" = "default" ]; then + echo " MENU LABEL NixOS - Default" + else + echo " MENU LABEL NixOS - Configuration $tag ($timestamp - $nixosVersion)" + fi + echo " LINUX ../nixos/$(basename $kernel)" + echo " INITRD ../nixos/$(basename $initrd)" + echo " FDTDIR ../nixos/$(basename $dtbs)" + echo " APPEND systemConfig=$path init=$path/init $extraParams" +} + +tmpFile="$target/extlinux/extlinux.conf.tmp.$$" + +cat > $tmpFile <> $tmpFile + +mv -f $tmpFile $target/extlinux/extlinux.conf + +# Remove obsolete files from $target/nixos. +for fn in $target/nixos/*; do + if ! test "${filesCopied[$fn]}" = 1; then + echo "Removing no longer needed boot file: $fn" + chmod +w -- "$fn" + rm -rf -- "$fn" + fi +done