Merge pull request #8978 from dezgeg/pr-arm-images
ARM SD card image expressions
This commit is contained in:
commit
982ce5ed58
88
nixos/lib/make-ext4-fs.nix
Normal file
88
nixos/lib/make-ext4-fs.nix
Normal file
|
@ -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
|
||||||
|
'';
|
||||||
|
}
|
|
@ -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
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
46
nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
Normal file
46
nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
Normal file
|
@ -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
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
127
nixos/modules/installer/cd-dvd/sd-image.nix
Normal file
127
nixos/modules/installer/cd-dvd/sd-image.nix
Normal file
|
@ -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
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
|
@ -52,6 +52,7 @@ in
|
||||||
TTYPath = "/dev/${cfg.tty}";
|
TTYPath = "/dev/${cfg.tty}";
|
||||||
TTYReset = true;
|
TTYReset = true;
|
||||||
TTYVTDisallocate = true;
|
TTYVTDisallocate = true;
|
||||||
|
WorkingDirectory = "/tmp";
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
pkgs.substituteAll {
|
pkgs.substituteAll {
|
||||||
src = ./extlinux-conf-builder.sh;
|
src = ./extlinux-conf-builder.sh;
|
||||||
isExecutable = true;
|
isExecutable = true;
|
||||||
inherit (pkgs) bash;
|
|
||||||
path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep];
|
path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep];
|
||||||
|
inherit (pkgs) bash;
|
||||||
|
kernelDTB = pkgs.stdenv.platform.kernelDTB or false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,8 +75,10 @@ addEntry() {
|
||||||
|
|
||||||
copyToKernelsDir "$path/kernel"; kernel=$result
|
copyToKernelsDir "$path/kernel"; kernel=$result
|
||||||
copyToKernelsDir "$path/initrd"; initrd=$result
|
copyToKernelsDir "$path/initrd"; initrd=$result
|
||||||
# XXX UGLY: maybe the system config should have a top-level "dtbs" entry?
|
if [ -n "@kernelDTB@" ]; then
|
||||||
copyToKernelsDir $(readlink -m "$path/kernel/../dtbs"); dtbs=$result
|
# 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)
|
timestampEpoch=$(stat -L -c '%Z' $path)
|
||||||
|
|
||||||
|
@ -93,7 +95,9 @@ addEntry() {
|
||||||
fi
|
fi
|
||||||
echo " LINUX ../nixos/$(basename $kernel)"
|
echo " LINUX ../nixos/$(basename $kernel)"
|
||||||
echo " INITRD ../nixos/$(basename $initrd)"
|
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"
|
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.
|
# Change this to e.g. nixos-42 to temporarily boot to an older configuration.
|
||||||
DEFAULT nixos-default
|
DEFAULT nixos-default
|
||||||
|
|
||||||
|
MENU TITLE ------------------------------------------------------------
|
||||||
TIMEOUT $timeout
|
TIMEOUT $timeout
|
||||||
$(addEntry $default default)
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Add up to $numGenerations generations of the system profile to the menu,
|
addEntry $default default >> $tmpFile
|
||||||
# in reverse (most recent to least recent) order.
|
|
||||||
for generation in $(
|
if [ "$numGenerations" -gt 0 ]; then
|
||||||
(cd /nix/var/nix/profiles && ls -d system-*-link) \
|
# Add up to $numGenerations generations of the system profile to the menu,
|
||||||
| sed 's/system-\([0-9]\+\)-link/\1/' \
|
# in reverse (most recent to least recent) order.
|
||||||
| sort -n -r \
|
for generation in $(
|
||||||
| head -n $numGenerations); do
|
(cd /nix/var/nix/profiles && ls -d system-*-link) \
|
||||||
link=/nix/var/nix/profiles/system-$generation-link
|
| sed 's/system-\([0-9]\+\)-link/\1/' \
|
||||||
addEntry $link $generation
|
| sort -n -r \
|
||||||
done >> $tmpFile
|
| 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
|
mv -f $tmpFile $target/extlinux/extlinux.conf
|
||||||
|
|
||||||
|
|
|
@ -338,6 +338,7 @@ with stdenv.lib;
|
||||||
X86_MCE y
|
X86_MCE y
|
||||||
|
|
||||||
# Linux containers.
|
# Linux containers.
|
||||||
|
NAMESPACES? y # Required by 'unshare' used by 'nixos-install'
|
||||||
RT_GROUP_SCHED? y
|
RT_GROUP_SCHED? y
|
||||||
CGROUP_DEVICE? y
|
CGROUP_DEVICE? y
|
||||||
${if versionAtLeast version "3.6" then ''
|
${if versionAtLeast version "3.6" then ''
|
||||||
|
|
|
@ -7,7 +7,7 @@ let
|
||||||
in import ./generic.nix (args // rec {
|
in import ./generic.nix (args // rec {
|
||||||
version = "3.18.y-${rev}";
|
version = "3.18.y-${rev}";
|
||||||
|
|
||||||
modDirVersion = "3.18.7-v7";
|
modDirVersion = "3.18.7";
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "https://api.github.com/repos/raspberrypi/linux/tarball/${rev}";
|
url = "https://api.github.com/repos/raspberrypi/linux/tarball/${rev}";
|
||||||
|
|
Loading…
Reference in a new issue