From df86813d9727aa3a9e3dcc45347f97b71bd01599 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Tue, 5 May 2015 06:23:28 +0300 Subject: nixos: Add derivations for SD card installation images on ARM The resulting image can be copied to a SD card with `dd` and is directly bootable by a suitably configured U-Boot. Though depending on the board, some extra steps are required for copying U-Boot itself to the SD card. Inside the image is a partition table, with a FAT32 /boot and a normal writable EXT4 rootfs. It's possible to directly reuse the SD image's partition layout and "install" NixOS on the same SD card by replacing the default configuration.nix and nixos-rebuild, and actually is the preferred way to use these images. To assist in this installation method, the boot scripts on the image automatically resize the rootfs partition to fit the SD card on the first boot. The SD images come in two flavors; one for the ARMv6 Raspberry Pi, and one multiplatform image for all the boards supported by the mainline kernel's multi_v7_defconfig config target. At the moment, these have been tested on: - Raspberry Pi Model B (512MB model) - NVIDIA Jetson TK1 - Linksprite pcDuino3 Nano To build, run: nix-build '' -A config.system.build.sdImage \ -I nixos-config='' --- .../cd-dvd/sd-image-armv7l-multiplatform.nix | 40 +++++++ .../installer/cd-dvd/sd-image-raspberrypi.nix | 46 ++++++++ nixos/modules/installer/cd-dvd/sd-image.nix | 127 +++++++++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix create mode 100644 nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix create mode 100644 nixos/modules/installer/cd-dvd/sd-image.nix (limited to 'nixos/modules/installer/cd-dvd') 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 <