diff options
author | viric <viric@viric.name> | 2015-07-29 14:13:57 +0200 |
---|---|---|
committer | viric <viric@viric.name> | 2015-07-29 14:13:57 +0200 |
commit | 982ce5ed589987bff22019e19f6feddf3609cb58 (patch) | |
tree | 67e1f8b286b3a0069de78dd58ca2651297a30e2d | |
parent | f5954509122160ed8209a3158e49ae054c12fcf8 (diff) | |
parent | df86813d9727aa3a9e3dcc45347f97b71bd01599 (diff) |
Merge pull request #8978 from dezgeg/pr-arm-images
ARM SD card image expressions
9 files changed, 328 insertions, 16 deletions
diff --git a/nixos/lib/make-ext4-fs.nix b/nixos/lib/make-ext4-fs.nix new file mode 100644 index 000000000000..23839ea487db --- /dev/null +++ b/nixos/lib/make-ext4-fs.nix @@ -0,0 +1,88 @@ +# Builds an ext4 image containing a populated /nix/store with the closure +# of store paths passed in the storePaths parameter. The generated image +# is sized to only fit its contents, with the expectation that a script +# resizes the filesystem at boot time. +{ pkgs +, storePaths +, volumeLabel +}: + +pkgs.stdenv.mkDerivation { + name = "ext4-fs.img"; + + buildInputs = with pkgs; [e2fsprogs libfaketime perl]; + + # For obtaining the closure of `storePaths'. + exportReferencesGraph = + map (x: [("closure-" + baseNameOf x) x]) storePaths; + + buildCommand = + '' + # Add the closures of the top-level store objects. + storePaths=$(perl ${pkgs.pathsFromGraph} closure-*) + + # Also include a manifest of the closures in a format suitable + # for nix-store --load-db. + printRegistration=1 perl ${pkgs.pathsFromGraph} closure-* > nix-path-registration + + # Make a crude approximation of the size of the target image. + # If the script starts failing, increase the fudge factors here. + numInodes=$(find $storePaths | wc -l) + numDataBlocks=$(du -c -B 4096 --apparent-size $storePaths | awk '$2 == "total" { print int($1 * 1.03) }') + bytes=$((2 * 4096 * $numInodes + 4096 * $numDataBlocks)) + echo "Creating an EXT4 image of $bytes bytes (numInodes=$numInodes, numDataBlocks=$numDataBlocks)" + + truncate -s $bytes $out + faketime "1970-01-01 00:00:00" mkfs.ext4 -L ${volumeLabel} -U 44444444-4444-4444-8888-888888888888 $out + + # Populate the image contents by piping a bunch of commands to the `debugfs` tool from e2fsprogs. + # For example, to copy /nix/store/abcd...efg-coreutils-8.23/bin/sleep: + # cd /nix/store/abcd...efg-coreutils-8.23/bin + # write /nix/store/abcd...efg-coreutils-8.23/bin/sleep sleep + # sif sleep mode 040555 + # sif sleep gid 30000 + # In particular, debugfs doesn't handle absolute target paths; you have to 'cd' in the virtual + # filesystem first. Likewise the intermediate directories must already exist (using `find` + # handles that for us). And when setting the file's permissions, the inode type flags (__S_IFDIR, + # __S_IFREG) need to be set as well. + ( + echo write nix-path-registration nix-path-registration + echo mkdir nix + echo cd /nix + echo mkdir store + + # XXX: This explodes in exciting ways if anything in /nix/store has a space in it. + find $storePaths -printf '%y %f %h %m\n'| while read -r type file dir perms; do + # echo "TYPE=$type DIR=$dir FILE=$file PERMS=$perms" >&2 + + echo "cd $dir" + case $type in + d) + echo "mkdir $file" + echo sif $file mode $((040000 | 0$perms)) # magic constant is __S_IFDIR + ;; + f) + echo "write $dir/$file $file" + echo sif $file mode $((0100000 | 0$perms)) # magic constant is __S_IFREG + ;; + l) + echo "symlink $file $(readlink "$dir/$file")" + ;; + *) + echo "Unknown entry: $type $dir $file $perms" >&2 + exit 1 + ;; + esac + + echo sif $file gid 30000 # chgrp to nixbld + done + ) | faketime "1970-01-01 00:00:00" debugfs -w $out -f /dev/stdin > errorlog 2>&1 + + # The debugfs tool doesn't terminate on error nor exit with a non-zero status. Check manually. + if egrep -q 'Could not allocate|File not found' errorlog; then + cat errorlog + echo "--- Failed to create EXT4 image of $bytes bytes (numInodes=$numInodes, numDataBlocks=$numDataBlocks) ---" + return 1 + fi + ''; +} diff --git a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix new file mode 100644 index 000000000000..0ca57a4635f4 --- /dev/null +++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix @@ -0,0 +1,40 @@ +{ config, lib, pkgs, ... }: + +let + extlinux-conf-builder = + import ../../system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix { + inherit pkgs; + }; +in +{ + imports = [ + ../../profiles/minimal.nix + ../../profiles/installation-device.nix + ./sd-image.nix + ]; + + assertions = lib.singleton { + assertion = pkgs.stdenv.system == "armv7l-linux"; + message = "sd-image-armv7l-multiplatform.nix can be only built natively on ARMv7; " + + "it cannot be cross compiled"; + }; + + boot.loader.grub.enable = false; + boot.loader.generic-extlinux-compatible.enable = true; + + # FIXME: change this to linuxPackages_latest once v4.2 is out + boot.kernelPackages = pkgs.linuxPackages_testing; + boot.kernelParams = ["console=ttyS0,115200n8" "console=ttyAMA0,115200n8" "console=tty0"]; + + # FIXME: fix manual evaluation on ARM + services.nixosManual.enable = lib.mkOverride 0 false; + + # FIXME: this probably should be in installation-device.nix + users.extraUsers.root.initialHashedPassword = ""; + + sdImage = { + populateBootCommands = '' + ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./boot + ''; + }; +} diff --git a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix new file mode 100644 index 000000000000..199a252ad2b5 --- /dev/null +++ b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix @@ -0,0 +1,46 @@ +{ config, lib, pkgs, ... }: + +let + extlinux-conf-builder = + import ../../system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix { + inherit pkgs; + }; +in +{ + imports = [ + ../../profiles/minimal.nix + ../../profiles/installation-device.nix + ./sd-image.nix + ]; + + assertions = lib.singleton { + assertion = pkgs.stdenv.system == "armv6l-linux"; + message = "sd-image-raspberrypi.nix can be only built natively on ARMv6; " + + "it cannot be cross compiled"; + }; + + # Needed by RPi firmware + nixpkgs.config.allowUnfree = true; + + boot.loader.grub.enable = false; + boot.loader.generic-extlinux-compatible.enable = true; + + boot.kernelPackages = pkgs.linuxPackages_rpi; + + # FIXME: fix manual evaluation on ARM + services.nixosManual.enable = lib.mkOverride 0 false; + + # FIXME: this probably should be in installation-device.nix + users.extraUsers.root.initialHashedPassword = ""; + + sdImage = { + populateBootCommands = '' + for f in bootcode.bin fixup.dat start.elf; do + cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/$f boot/ + done + cp ${pkgs.ubootRaspberryPi}/u-boot.bin boot/u-boot-rpi.bin + echo 'kernel u-boot-rpi.bin' > boot/config.txt + ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./boot + ''; + }; +} diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix new file mode 100644 index 000000000000..12b4f3045614 --- /dev/null +++ b/nixos/modules/installer/cd-dvd/sd-image.nix @@ -0,0 +1,127 @@ +# This module creates a bootable SD card image containing the given NixOS +# configuration. The generated image is MBR partitioned, with a FAT /boot +# partition, and ext4 root partition. The generated image is sized to fit +# its contents, and a boot script automatically resizes the root partition +# to fit the device on the first boot. +# +# The derivation for the SD image will be placed in +# config.system.build.sdImage + +{ config, lib, pkgs, ... }: + +with lib; + +let + rootfsImage = import ../../../lib/make-ext4-fs.nix { + inherit pkgs; + inherit (config.sdImage) storePaths; + volumeLabel = "NIXOS_SD"; + }; +in +{ + options.sdImage = { + storePaths = mkOption { + type = with types; listOf package; + example = literalExample "[ pkgs.stdenv ]"; + description = '' + Derivations to be included in the Nix store in the generated SD image. + ''; + }; + + bootSize = mkOption { + type = types.int; + default = 128; + description = '' + Size of the /boot partition, in megabytes. + ''; + }; + + populateBootCommands = mkOption { + example = literalExample "'' cp \${pkgs.myBootLoader}/u-boot.bin boot/ ''"; + description = '' + Shell commands to populate the ./boot directory. + All files in that directory are copied to the + /boot partition on the SD image. + ''; + }; + }; + + config = { + fileSystems = { + "/boot" = { + device = "/dev/disk/by-label/NIXOS_BOOT"; + fsType = "vfat"; + }; + "/" = { + device = "/dev/disk/by-label/NIXOS_SD"; + fsType = "ext4"; + }; + }; + + sdImage.storePaths = [ config.system.build.toplevel ]; + + system.build.sdImage = pkgs.stdenv.mkDerivation { + name = "sd-image-${pkgs.stdenv.system}.img"; + + buildInputs = with pkgs; [ dosfstools e2fsprogs mtools libfaketime utillinux ]; + + buildCommand = '' + # Create the image file sized to fit /boot and /, plus 4M of slack + rootSizeBlocks=$(du -B 512 --apparent-size ${rootfsImage} | awk '{ print $1 }') + bootSizeBlocks=$((${toString config.sdImage.bootSize} * 1024 * 1024 / 512)) + imageSize=$((rootSizeBlocks * 512 + bootSizeBlocks * 512 + 4096 * 1024)) + truncate -s $imageSize $out + + # type=b is 'W95 FAT32', type=83 is 'Linux'. + sfdisk $out <<EOF + label: dos + label-id: 0x2178694e + + start=1M, size=$bootSizeBlocks, type=b, bootable + type=83 + EOF + + # Copy the rootfs into the SD image + eval $(partx $out -o START,SECTORS --nr 2 --pairs) + dd conv=notrunc if=${rootfsImage} of=$out seek=$START count=$SECTORS + + # Create a FAT32 /boot partition of suitable size into bootpart.img + eval $(partx $out -o START,SECTORS --nr 1 --pairs) + truncate -s $((SECTORS * 512)) bootpart.img + faketime "1970-01-01 00:00:00" mkfs.vfat -i 0x2178694e -n NIXOS_BOOT bootpart.img + + # Populate the files intended for /boot + mkdir boot + ${config.sdImage.populateBootCommands} + + # Copy the populated /boot into the SD image + (cd boot; mcopy -bpsvm -i ../bootpart.img ./* ::) + dd conv=notrunc if=bootpart.img of=$out seek=$START count=$SECTORS + ''; + }; + + boot.postBootCommands = '' + # On the first boot do some maintenance tasks + if [ -f /nix-path-registration ]; then + # Figure out device names for the boot device and root filesystem. + rootPart=$(readlink -f /dev/disk/by-label/NIXOS_SD) + bootDevice=$(lsblk -npo PKNAME $rootPart) + + # Resize the root partition and the filesystem to fit the disk + echo ",+," | sfdisk -N2 --no-reread $bootDevice + ${pkgs.parted}/bin/partprobe + ${pkgs.e2fsprogs}/bin/resize2fs $rootPart + + # Register the contents of the initial Nix store + ${config.nix.package}/bin/nix-store --load-db < /nix-path-registration + + # nixos-rebuild also requires a "system" profile and an /etc/NIXOS tag. + touch /etc/NIXOS + ${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system + + # Prevents this from running on later boots. + rm -f /nix-path-registration + fi + ''; + }; +} diff --git a/nixos/modules/services/misc/rogue.nix b/nixos/modules/services/misc/rogue.nix index ed8da8a518ff..aae02e384c97 100644 --- a/nixos/modules/services/misc/rogue.nix +++ b/nixos/modules/services/misc/rogue.nix @@ -52,6 +52,7 @@ in TTYPath = "/dev/${cfg.tty}"; TTYReset = true; TTYVTDisallocate = true; + WorkingDirectory = "/tmp"; Restart = "always"; }; }; 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 index 261192c6d24e..c5c250c14cea 100644 --- 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 @@ -3,6 +3,7 @@ pkgs.substituteAll { src = ./extlinux-conf-builder.sh; isExecutable = true; - inherit (pkgs) bash; path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep]; + inherit (pkgs) bash; + kernelDTB = pkgs.stdenv.platform.kernelDTB or false; } 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 index 8f2a496de8b6..b9a42b2a196d 100644 --- 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 @@ -75,8 +75,10 @@ addEntry() { 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 + if [ -n "@kernelDTB@" ]; then + # XXX UGLY: maybe the system config should have a top-level "dtbs" entry? + copyToKernelsDir $(readlink -m "$path/kernel/../dtbs"); dtbs=$result + fi timestampEpoch=$(stat -L -c '%Z' $path) @@ -93,7 +95,9 @@ addEntry() { fi echo " LINUX ../nixos/$(basename $kernel)" echo " INITRD ../nixos/$(basename $initrd)" - echo " FDTDIR ../nixos/$(basename $dtbs)" + if [ -n "@kernelDTB@" ]; then + echo " FDTDIR ../nixos/$(basename $dtbs)" + fi echo " APPEND systemConfig=$path init=$path/init $extraParams" } @@ -105,20 +109,24 @@ cat > $tmpFile <<EOF # Change this to e.g. nixos-42 to temporarily boot to an older configuration. DEFAULT nixos-default +MENU TITLE ------------------------------------------------------------ TIMEOUT $timeout -$(addEntry $default default) EOF -# Add up to $numGenerations generations of the system profile to the menu, -# in reverse (most recent to least recent) order. -for generation in $( - (cd /nix/var/nix/profiles && ls -d system-*-link) \ - | sed 's/system-\([0-9]\+\)-link/\1/' \ - | sort -n -r \ - | head -n $numGenerations); do - link=/nix/var/nix/profiles/system-$generation-link - addEntry $link $generation -done >> $tmpFile +addEntry $default default >> $tmpFile + +if [ "$numGenerations" -gt 0 ]; then + # Add up to $numGenerations generations of the system profile to the menu, + # in reverse (most recent to least recent) order. + for generation in $( + (cd /nix/var/nix/profiles && ls -d system-*-link) \ + | sed 's/system-\([0-9]\+\)-link/\1/' \ + | sort -n -r \ + | head -n $numGenerations); do + link=/nix/var/nix/profiles/system-$generation-link + addEntry $link $generation + done >> $tmpFile +fi mv -f $tmpFile $target/extlinux/extlinux.conf diff --git a/pkgs/os-specific/linux/kernel/common-config.nix b/pkgs/os-specific/linux/kernel/common-config.nix index cb7423f293a4..7063017b3a8c 100644 --- a/pkgs/os-specific/linux/kernel/common-config.nix +++ b/pkgs/os-specific/linux/kernel/common-config.nix @@ -338,6 +338,7 @@ with stdenv.lib; X86_MCE y # Linux containers. + NAMESPACES? y # Required by 'unshare' used by 'nixos-install' RT_GROUP_SCHED? y CGROUP_DEVICE? y ${if versionAtLeast version "3.6" then '' diff --git a/pkgs/os-specific/linux/kernel/linux-rpi.nix b/pkgs/os-specific/linux/kernel/linux-rpi.nix index 67a51dc767df..02b297081315 100644 --- a/pkgs/os-specific/linux/kernel/linux-rpi.nix +++ b/pkgs/os-specific/linux/kernel/linux-rpi.nix @@ -7,7 +7,7 @@ let in import ./generic.nix (args // rec { version = "3.18.y-${rev}"; - modDirVersion = "3.18.7-v7"; + modDirVersion = "3.18.7"; src = fetchurl { url = "https://api.github.com/repos/raspberrypi/linux/tarball/${rev}"; |