sane.image: fix so `imgs.moby` includes a working bootloader

This commit is contained in:
Colin 2024-03-30 20:30:04 +00:00
parent a65673847a
commit eff37765ae
2 changed files with 100 additions and 54 deletions

View File

@ -1,12 +1,22 @@
# tow-boot: <https://tow-boot.org>
# docs (pinephone specific): <https://github.com/Tow-Boot/Tow-Boot/tree/development/boards/pine64-pinephoneA64>
# LED and button behavior is defined here: <https://github.com/Tow-Boot/Tow-Boot/blob/development/modules/tow-boot/phone-ux.nix>
# - hold VOLDOWN: enter recovery mode
# - LED will turn aqua instead of yellow
# - recovery mode would ordinarily allow a selection of entries, but for pinephone i guess it doesn't do anything?
# - hold VOLUP: force it to load the OS from eMMC?
# - LED will turn blue instead of yellow
# boot LEDs:
# - yellow = entered tow-boot
# - 10 red flashes => poweroff means tow-boot couldn't boot into the next stage (i.e. distroboot)
# - distroboot: <https://source.denx.de/u-boot/u-boot/-/blob/v2022.04/doc/develop/distro.rst>)
{ config, pkgs, ... }:
{
# we need space in the GPT header to place tow-boot.
# only actually need 1 MB, but better to over-allocate than under-allocate
sane.image.extraGPTPadding = 16 * 1024 * 1024;
sane.image.firstPartGap = 0;
system.build.img = pkgs.runCommand "nixos_full-disk-image.img" {} ''
cp -v ${config.system.build.img-without-firmware}/nixos.img $out
chmod +w $out
dd if=${pkgs.tow-boot-pinephone}/Tow-Boot.noenv.bin of=$out bs=1024 seek=8 conv=notrunc
sane.image.installBootloader = ''
dd if=${pkgs.tow-boot-pinephone}/Tow-Boot.noenv.bin of=$out/nixos.img bs=1024 seek=8 conv=notrunc
'';
}

View File

@ -1,5 +1,15 @@
{ config, lib, pkgs, utils, ... }:
# this builds a disk image which can be flashed onto a HDD, SD card, etc, and boot a working image.
# debug the image by building one of:
# - `nix build '.#imgs.$host' --builders "" -v`
# - `nix build '.#imgs.$host.passthru.{bootFsImg,nixFsImg,withoutBootloader}'`
# then loop-mounting it:
# - `sudo losetup -Pf ./result/nixos.img`
# - `mkdir /tmp/nixos.boot`
# - `sudo mount /dev/loop0p1 /tmp/nixos.boot`, and look inside
#
# TODO: replace mobile-nixos parts with Disko <https://github.com/nix-community/disko>
# or just inline them here.
{ config, lib, pkgs, utils, ... }:
with lib;
let
@ -62,6 +72,14 @@ in
N.B.: setting this to something other than 512B is not well tested.
'';
};
sane.image.installBootloader = mkOption {
default = null;
type = types.nullOr types.str;
description = ''
command which takes the full disk image and installs hw-specific bootloader (u-boot, tow-boot, etc).
for EFI-native systems (most x86_64), can be left empty.
'';
};
};
config = let
# return true if super starts with sub
@ -90,10 +108,52 @@ in
"ext4" = pkgs.imageBuilder.fileSystem.makeExt4;
"btrfs" = pkgs.imageBuilder.fileSystem.makeBtrfs;
};
in
lib.mkIf cfg.enable
{
system.build.img-without-firmware = with pkgs; pkgs.imageBuilder.diskImage.makeGPT {
bootFsImg = fsBuilderMapBoot."${bootFs.fsType}" {
# fs properties
name = "ESP";
partitionID = vfatUuidFromFs bootFs;
# partition properties
partitionLabel = "EFI System";
partitionUUID = "44444444-4444-4444-4444-4444${vfatUuidFromFs bootFs}";
size = cfg.bootPartSize;
inherit (cfg) sectorSize;
blockSize = cfg.sectorSize; # has to be a multiple of sectorSize
populateCommands = let
extras = builtins.toString (builtins.map (d: "cp -R ${d}/* ./") cfg.extraBootFiles);
in ''
echo "running installBootLoader"
${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d .
echo "ran installBootLoader"
${extras}
echo "copied extraBootFiles"
'';
};
nixFsImg = fsBuilderMapNix."${nixFs.fsType}" {
# fs properties
name = "NIXOS_SYSTEM";
partitionID = uuidFromFs nixFs;
# partition properties
partitionLabel = "Linux filesystem";
partitionUUID = uuidFromFs nixFs;
# inherit (cfg) sectorSize; # imageBuilder only supports sectorSize for vfat. btrfs defaults to a 4096B sector size, somehow it abstracts over the drive's sector size?
populateCommands = let
closureInfo = pkgs.buildPackages.closureInfo { rootPaths = config.system.build.toplevel; };
extraRelPaths = builtins.toString (builtins.map (p: "./" + builtins.toString(relPath nixFs.mountPoint p)) cfg.extraDirectories);
in ''
mkdir -p ./${storeRelPath} ${extraRelPaths}
echo "Copying system closure..."
while IFS= read -r path; do
echo " Copying $path"
cp -prf "$path" ./${storeRelPath}
done < "${closureInfo}/store-paths"
echo "Done copying system closure..."
cp -v ${closureInfo}/registration ./nix-path-registration
'';
};
img = (pkgs.imageBuilder.diskImage.makeGPT {
name = "nixos";
diskID = vfatUuidFromFs bootFs;
# leave some space for firmware
@ -102,52 +162,28 @@ in
headerHole = cfg.extraGPTPadding;
partitions = [
(pkgs.imageBuilder.gap cfg.firstPartGap)
(fsBuilderMapBoot."${bootFs.fsType}" {
# fs properties
name = "ESP";
partitionID = vfatUuidFromFs bootFs;
# partition properties
partitionLabel = "EFI System";
partitionUUID = "44444444-4444-4444-4444-4444${vfatUuidFromFs bootFs}";
size = cfg.bootPartSize;
inherit (cfg) sectorSize;
blockSize = cfg.sectorSize; # has to be a multiple of sectorSize
populateCommands = let
extras = builtins.toString (builtins.map (d: "cp -R ${d}/* ./") cfg.extraBootFiles);
in ''
echo "running installBootLoader"
${config.system.build.installBootLoader} ${config.system.build.toplevel} -d .
echo "ran installBootLoader"
${extras}
echo "copied extraBootFiles"
'';
})
(fsBuilderMapNix."${nixFs.fsType}" {
# fs properties
name = "NIXOS_SYSTEM";
partitionID = uuidFromFs nixFs;
# partition properties
partitionLabel = "Linux filesystem";
partitionUUID = uuidFromFs nixFs;
# inherit (cfg) sectorSize; # imageBuilder only supports sectorSize for vfat. btrfs defaults to a 4096B sector size, somehow it abstracts over the drive's sector size?
populateCommands = let
closureInfo = buildPackages.closureInfo { rootPaths = config.system.build.toplevel; };
extraRelPaths = builtins.toString (builtins.map (p: "./" + builtins.toString(relPath nixFs.mountPoint p)) cfg.extraDirectories);
in ''
mkdir -p ./${storeRelPath} ${extraRelPaths}
echo "Copying system closure..."
while IFS= read -r path; do
echo " Copying $path"
cp -prf "$path" ./${storeRelPath}
done < "${closureInfo}/store-paths"
echo "Done copying system closure..."
cp -v ${closureInfo}/registration ./nix-path-registration
'';
})
bootFsImg
nixFsImg
];
}) // {
passthru = {
inherit bootFsImg nixFsImg;
};
};
in
lib.mkIf cfg.enable
{
system.build.img = (if cfg.installBootloader == null then
img
else pkgs.runCommand "nixos-with-bootloader" {} ''
cp -vR ${img} $out
chmod -R +w $out
${cfg.installBootloader}
'') // {
passthru = {
inherit bootFsImg nixFsImg;
withoutBootloader = img;
};
};
system.build.img = lib.mkDefault config.system.build.img-without-firmware;
};
}