From 6e9e78b61869bcec02055a0210e8ac569be9f881 Mon Sep 17 00:00:00 2001 From: Samuel Dionne-Riel Date: Sat, 1 Jun 2019 18:03:44 -0400 Subject: [PATCH 1/7] sd-image: Moves `/boot` into rootfs The current FAT32 partition is kept as it is required for the Raspberry Pi family of hardware. It is where the firmware is kept. The partition is kept bootable, and the boot files kept in there until the following commits, to keep all commits of this series individually bootable. --- .../installer/cd-dvd/sd-image-aarch64.nix | 10 ++-- .../cd-dvd/sd-image-armv7l-multiplatform.nix | 12 ++-- .../installer/cd-dvd/sd-image-raspberrypi.nix | 10 ++-- nixos/modules/installer/cd-dvd/sd-image.nix | 55 ++++++++++--------- 4 files changed, 44 insertions(+), 43 deletions(-) diff --git a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix index 5f7194e92a3..eb0bc9da409 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix @@ -27,7 +27,7 @@ in boot.kernelParams = ["cma=32M" "console=ttyS0,115200n8" "console=ttyAMA0,115200n8" "console=tty0"]; sdImage = { - populateBootCommands = let + populateFirmwareCommands = let configTxt = pkgs.writeText "config.txt" '' kernel=u-boot-rpi3.bin @@ -43,10 +43,10 @@ in avoid_warnings=1 ''; in '' - (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/boot/) - cp ${pkgs.ubootRaspberryPi3_64bit}/u-boot.bin boot/u-boot-rpi3.bin - cp ${configTxt} boot/config.txt - ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./boot + (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/firmware/) + cp ${pkgs.ubootRaspberryPi3_64bit}/u-boot.bin firmware/u-boot-rpi3.bin + cp ${configTxt} firmware/config.txt + ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./firmware ''; }; } diff --git a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix index 71448f74c36..02587ba4af0 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix @@ -29,7 +29,7 @@ in boot.kernelParams = ["console=ttyS0,115200n8" "console=ttymxc0,115200n8" "console=ttyAMA0,115200n8" "console=ttyO0,115200n8" "console=ttySAC2,115200n8" "console=tty0"]; sdImage = { - populateBootCommands = let + populateFirmwareCommands = let configTxt = pkgs.writeText "config.txt" '' # Prevent the firmware from smashing the framebuffer setup done by the mainline kernel # when attempting to show low-voltage or overtemperature warnings. @@ -46,11 +46,11 @@ in enable_uart=1 ''; in '' - (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/boot/) - cp ${pkgs.ubootRaspberryPi2}/u-boot.bin boot/u-boot-rpi2.bin - cp ${pkgs.ubootRaspberryPi3_32bit}/u-boot.bin boot/u-boot-rpi3.bin - cp ${configTxt} boot/config.txt - ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./boot + (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/firmware/) + cp ${pkgs.ubootRaspberryPi2}/u-boot.bin firmware/u-boot-rpi2.bin + cp ${pkgs.ubootRaspberryPi3_32bit}/u-boot.bin firmware/u-boot-rpi3.bin + cp ${configTxt} firmware/config.txt + ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./firmware ''; }; } diff --git a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix index 96e06670694..de3385290d2 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix @@ -35,11 +35,11 @@ in kernel=u-boot-rpi1.bin ''; in '' - (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/boot/) - cp ${pkgs.ubootRaspberryPiZero}/u-boot.bin boot/u-boot-rpi0.bin - cp ${pkgs.ubootRaspberryPi}/u-boot.bin boot/u-boot-rpi1.bin - cp ${configTxt} boot/config.txt - ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./boot + (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/firmware/) + cp ${pkgs.ubootRaspberryPiZero}/u-boot.bin firmware/u-boot-rpi0.bin + cp ${pkgs.ubootRaspberryPi}/u-boot.bin firmware/u-boot-rpi1.bin + cp ${configTxt} firmware/config.txt + ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./firmware ''; }; } diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix index 69746a8e979..6b5bccfa2e7 100644 --- a/nixos/modules/installer/cd-dvd/sd-image.nix +++ b/nixos/modules/installer/cd-dvd/sd-image.nix @@ -43,12 +43,12 @@ in ''; }; - bootPartitionID = mkOption { + firmwarePartitionID = mkOption { type = types.string; default = "0x2178694e"; description = '' - Volume ID for the /boot partition on the SD card. This value must be a - 32-bit hexadecimal number. + Volume ID for the /boot/firmware partition on the SD card. This value + must be a 32-bit hexadecimal number. ''; }; @@ -61,29 +61,30 @@ in ''; }; - bootSize = mkOption { + firmwareSize = mkOption { type = types.int; default = 120; description = '' - Size of the /boot partition, in megabytes. + Size of the /boot/firmware partition, in megabytes. ''; }; - populateBootCommands = mkOption { - example = literalExample "'' cp \${pkgs.myBootLoader}/u-boot.bin boot/ ''"; + populateFirmwareCommands = mkOption { + example = literalExample "'' cp \${pkgs.myBootLoader}/u-boot.bin firmware/ ''"; description = '' - Shell commands to populate the ./boot directory. + Shell commands to populate the ./firmware directory. All files in that directory are copied to the - /boot partition on the SD image. + /boot/firmware partition on the SD image. ''; }; }; config = { fileSystems = { - "/boot" = { - device = "/dev/disk/by-label/NIXOS_BOOT"; + "/boot/firmware" = { + device = "/dev/disk/by-label/FIRMWARE"; fsType = "vfat"; + options = [ "nofail" "noauto" ]; }; "/" = { device = "/dev/disk/by-label/NIXOS_SD"; @@ -105,39 +106,39 @@ in echo "${pkgs.stdenv.buildPlatform.system}" > $out/nix-support/system echo "file sd-image $img" >> $out/nix-support/hydra-build-products - # Create the image file sized to fit /boot and /, plus 20M of slack + # Create the image file sized to fit /boot/firmware and /, plus 20M 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 + 20 * 1024 * 1024)) + firmwareSizeBlocks=$((${toString config.sdImage.firmwareSize} * 1024 * 1024 / 512)) + imageSize=$((rootSizeBlocks * 512 + firmwareSizeBlocks * 512 + 20 * 1024 * 1024)) truncate -s $imageSize $img # type=b is 'W95 FAT32', type=83 is 'Linux'. sfdisk $img < Date: Sat, 1 Jun 2019 21:06:03 -0400 Subject: [PATCH 2/7] make-ext4-fs: Allows populating with custom files This will allow adding /boot files to the rootfs. --- nixos/lib/make-ext4-fs.nix | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/nixos/lib/make-ext4-fs.nix b/nixos/lib/make-ext4-fs.nix index 47c6374c81a..932adcd9796 100644 --- a/nixos/lib/make-ext4-fs.nix +++ b/nixos/lib/make-ext4-fs.nix @@ -1,9 +1,14 @@ # 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. +# of store paths passed in the storePaths parameter, in addition to the +# contents of a directory that can be populated with commands. The +# generated image is sized to only fit its contents, with the expectation +# that a script resizes the filesystem at boot time. { pkgs +# List of derivations to be included , storePaths +# Shell commands to populate the ./files directory. +# All files in that directory are copied to the root of the FS. +, populateImageCommands ? "" , volumeLabel , uuid ? "44444444-4444-4444-8888-888888888888" , e2fsprogs @@ -23,13 +28,17 @@ pkgs.stdenv.mkDerivation { buildCommand = '' + ( + mkdir -p ./files + ${populateImageCommands} + ) # Add the closures of the top-level store objects. storePaths=$(cat ${sdClosureInfo}/store-paths) # 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) }') + numInodes=$(find $storePaths ./files | wc -l) + numDataBlocks=$(du -s -c -B 4096 --apparent-size $storePaths ./files | tail -1 | awk '{ print int($1 * 1.03) }') bytes=$((2 * 4096 * $numInodes + 4096 * $numDataBlocks)) echo "Creating an EXT4 image of $bytes bytes (numInodes=$numInodes, numDataBlocks=$numDataBlocks)" @@ -47,6 +56,12 @@ pkgs.stdenv.mkDerivation { echo "copying store paths to image..." cptofs -t ext4 -i $out $storePaths /nix/store/ + ( + echo "copying files to image..." + cd ./files + cptofs -t ext4 -i $out ./* / + ) + # I have ended up with corrupted images sometimes, I suspect that happens when the build machine's disk gets full during the build. if ! fsck.ext4 -n -f $out; then echo "--- Fsck failed for EXT4 image of $bytes bytes (numInodes=$numInodes, numDataBlocks=$numDataBlocks) ---" From 53884e1b94efe183ef6d32758a9f7ceee4aa0b19 Mon Sep 17 00:00:00 2001 From: Samuel Dionne-Riel Date: Sat, 1 Jun 2019 21:14:05 -0400 Subject: [PATCH 3/7] sd-image: Switch /boot to the ext4 partition --- .../modules/installer/cd-dvd/sd-image-aarch64.nix | 5 ++++- .../cd-dvd/sd-image-armv7l-multiplatform.nix | 5 ++++- .../installer/cd-dvd/sd-image-raspberrypi.nix | 5 ++++- nixos/modules/installer/cd-dvd/sd-image.nix | 15 +++++++++++++-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix index eb0bc9da409..49008bef834 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix @@ -46,7 +46,10 @@ in (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/firmware/) cp ${pkgs.ubootRaspberryPi3_64bit}/u-boot.bin firmware/u-boot-rpi3.bin cp ${configTxt} firmware/config.txt - ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./firmware ''; + populateRootCommands = '' + mkdir -p ./files/boot + ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./files/boot + ''; }; } diff --git a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix index 02587ba4af0..dab09241531 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix @@ -50,7 +50,10 @@ in cp ${pkgs.ubootRaspberryPi2}/u-boot.bin firmware/u-boot-rpi2.bin cp ${pkgs.ubootRaspberryPi3_32bit}/u-boot.bin firmware/u-boot-rpi3.bin cp ${configTxt} firmware/config.txt - ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./firmware ''; + populateRootCommands = '' + mkdir -p ./files/boot + ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./files/boot + ''; }; } diff --git a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix index de3385290d2..cb78bbafecf 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix @@ -39,7 +39,10 @@ in cp ${pkgs.ubootRaspberryPiZero}/u-boot.bin firmware/u-boot-rpi0.bin cp ${pkgs.ubootRaspberryPi}/u-boot.bin firmware/u-boot-rpi1.bin cp ${configTxt} firmware/config.txt - ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./firmware ''; + populateRootCommands = '' + mkdir -p ./files/boot + ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./files/boot + ''; }; } diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix index 6b5bccfa2e7..387af9373f4 100644 --- a/nixos/modules/installer/cd-dvd/sd-image.nix +++ b/nixos/modules/installer/cd-dvd/sd-image.nix @@ -14,6 +14,7 @@ with lib; let rootfsImage = pkgs.callPackage ../../../lib/make-ext4-fs.nix ({ inherit (config.sdImage) storePaths; + populateImageCommands = config.sdImage.populateRootCommands; volumeLabel = "NIXOS_SD"; } // optionalAttrs (config.sdImage.rootPartitionUUID != null) { uuid = config.sdImage.rootPartitionUUID; @@ -77,6 +78,16 @@ in /boot/firmware partition on the SD image. ''; }; + + populateRootCommands = mkOption { + example = literalExample "''\${extlinux-conf-builder} -t 3 -c \${config.system.build.toplevel} -d ./files/boot''"; + description = '' + Shell commands to populate the ./files directory. + All files in that directory are copied to the + root (/) partition on the SD image. Use this to + populate the ./files/boot (/boot) directory. + ''; + }; }; config = { @@ -117,8 +128,8 @@ in label: dos label-id: ${config.sdImage.firmwarePartitionID} - start=8M, size=$firmwareSizeBlocks, type=b, bootable - start=${toString (8 + config.sdImage.firmwareSize)}M, type=83 + start=8M, size=$firmwareSizeBlocks, type=b + start=${toString (8 + config.sdImage.firmwareSize)}M, type=83, bootable EOF # Copy the rootfs into the SD image From 8634d5700d34b7ef2cd2b25f1cd5af549c76858c Mon Sep 17 00:00:00 2001 From: Samuel Dionne-Riel Date: Sat, 1 Jun 2019 21:29:20 -0400 Subject: [PATCH 4/7] sd-image: firmware partition reduced to 20MiB --- nixos/modules/installer/cd-dvd/sd-image.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix index 387af9373f4..ec889786de8 100644 --- a/nixos/modules/installer/cd-dvd/sd-image.nix +++ b/nixos/modules/installer/cd-dvd/sd-image.nix @@ -64,7 +64,8 @@ in firmwareSize = mkOption { type = types.int; - default = 120; + # As of 2019-05-31 the Raspberry pi firmware + u-bot takes ~13MiB + default = 20; description = '' Size of the /boot/firmware partition, in megabytes. ''; From 1843e00146439b226d842a370da63e4a3a04d336 Mon Sep 17 00:00:00 2001 From: Samuel Dionne-Riel Date: Sat, 1 Jun 2019 22:54:52 -0400 Subject: [PATCH 5/7] sd-image: Updates comments --- nixos/modules/installer/cd-dvd/sd-image.nix | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix index ec889786de8..1faa657885b 100644 --- a/nixos/modules/installer/cd-dvd/sd-image.nix +++ b/nixos/modules/installer/cd-dvd/sd-image.nix @@ -1,8 +1,12 @@ # 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. +# configuration. The generated image is MBR partitioned, with a FAT +# /boot/firmware 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 firmware partition is built with expectation to hold the Raspberry +# Pi firmware and bootloader, and be removed and replaced with a firmware +# build for the target SoC for other board families. # # The derivation for the SD image will be placed in # config.system.build.sdImage @@ -96,6 +100,9 @@ in "/boot/firmware" = { device = "/dev/disk/by-label/FIRMWARE"; fsType = "vfat"; + # Alternatively, this could be removed from the configuration. + # The filesystem is not needed at runtime, it could be treated + # as an opaque blob instead of a discrete FAT32 filesystem. options = [ "nofail" "noauto" ]; }; "/" = { @@ -125,6 +132,8 @@ in truncate -s $imageSize $img # type=b is 'W95 FAT32', type=83 is 'Linux'. + # The "bootable" partition is where u-boot will look file for the bootloader + # information (dtbs, extlinux.conf file). sfdisk $img < Date: Tue, 4 Jun 2019 21:33:09 -0400 Subject: [PATCH 6/7] sd-image: Pull less slack in the image by accounting for slack The slack, seemingly, accounted for more than the minimum required for slack plus the two partitions. This change makes the gap a somewhat abstracted amount, but is not configurable within the derivation. --- nixos/modules/installer/cd-dvd/sd-image.nix | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix index 1faa657885b..5ee594b2336 100644 --- a/nixos/modules/installer/cd-dvd/sd-image.nix +++ b/nixos/modules/installer/cd-dvd/sd-image.nix @@ -125,10 +125,13 @@ in echo "${pkgs.stdenv.buildPlatform.system}" > $out/nix-support/system echo "file sd-image $img" >> $out/nix-support/hydra-build-products - # Create the image file sized to fit /boot/firmware and /, plus 20M of slack + # Gap in front of the first partition, in MiB + gap=8 + + # Create the image file sized to fit /boot/firmware and /, plus slack for the gap. rootSizeBlocks=$(du -B 512 --apparent-size ${rootfsImage} | awk '{ print $1 }') firmwareSizeBlocks=$((${toString config.sdImage.firmwareSize} * 1024 * 1024 / 512)) - imageSize=$((rootSizeBlocks * 512 + firmwareSizeBlocks * 512 + 20 * 1024 * 1024)) + imageSize=$((rootSizeBlocks * 512 + firmwareSizeBlocks * 512 + gap * 1024 * 1024)) truncate -s $imageSize $img # type=b is 'W95 FAT32', type=83 is 'Linux'. @@ -138,8 +141,8 @@ in label: dos label-id: ${config.sdImage.firmwarePartitionID} - start=8M, size=$firmwareSizeBlocks, type=b - start=${toString (8 + config.sdImage.firmwareSize)}M, type=83, bootable + start=''${gap}M, size=$firmwareSizeBlocks, type=b + start=$((gap + ${toString config.sdImage.firmwareSize}))M, type=83, bootable EOF # Copy the rootfs into the SD image From 288118cdfa35df235b1442ca9e535711ad7bf371 Mon Sep 17 00:00:00 2001 From: Samuel Dionne-Riel Date: Sun, 16 Jun 2019 17:45:48 -0400 Subject: [PATCH 7/7] sd-image: Adds removed options for removed options This will keep configuration configuring the size of the /boot partition still build, while showing the deprecation warning. In 99.9% of cases I assume ignoring the configuration is better, as the sd-image builder already is pretty opinionated in that matter. --- nixos/modules/installer/cd-dvd/sd-image.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix index 5ee594b2336..0c407b19936 100644 --- a/nixos/modules/installer/cd-dvd/sd-image.nix +++ b/nixos/modules/installer/cd-dvd/sd-image.nix @@ -25,6 +25,11 @@ let }); in { + imports = [ + (mkRemovedOptionModule [ "sdImage" "bootPartitionID" ] "The FAT partition for SD image now only holds the Raspberry Pi firmware files. Use firmwarePartitionID to configure that partition's ID.") + (mkRemovedOptionModule [ "sdImage" "bootSize" ] "The boot files for SD image have been moved to the main ext4 partition. The FAT partition now only holds the Raspberry Pi firmware files. Changing its size may not be required.") + ]; + options.sdImage = { imageName = mkOption { default = "${config.sdImage.imageBaseName}-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}.img";