modules/image.nix: remove dependency on mobile-nixos

the images build, but i have not tried booting them
This commit is contained in:
2025-06-23 02:32:17 +00:00
parent dafa562f51
commit d9c1a97ef6
3 changed files with 238 additions and 81 deletions

View File

@@ -39,7 +39,6 @@ let
"linux-postmarketos-allwinner"
"linux-postmarketos-exynos5"
"linux-postmarketos-pinephonepro"
"mobile-nixos"
"nixpkgs-bootstrap"
"nixpkgs-wayland"
"sops-nix"

View File

@@ -23,12 +23,6 @@ in
default = [];
type = types.listOf types.package;
};
# extra (empty) directories to create in the rootfs.
# for example, /var/log might be required by the boot process, so ensure it exists.
sane.image.extraDirectories = mkOption {
default = [];
type = types.listOf types.str;
};
# the GPT header is fixed to Logical Block Address 1,
# but we can actually put the partition entries anywhere.
@@ -47,9 +41,7 @@ in
sane.image.firstPartGap = mkOption {
# align the first part to 16 MiB.
# do this by inserting a gap of 16 MiB - gptHeaderSize
# and then multiply by 1MiB and subtract 1 because mobile-nixos
# has a bug which will divide this by 1 MiB (and round up)
default = (16 * 1024 * 1024 - 34 * 512) * 1024 * 1024 - 1;
default = 16 * 1024 * 1024 - 34 * 512;
type = types.nullOr types.int;
};
sane.image.platformPartSize = mkOption {
@@ -107,91 +99,276 @@ in
uuidFromFs = fs: builtins.head (builtins.match "/dev/disk/by-uuid/(.+)" fs.device);
vfatUuidFromFs = fs: builtins.replaceStrings ["-"] [""] (uuidFromFs fs);
fsBuilderMapBoot = {
"vfat" = pkgs.mobile-nixos.imageBuilder.fileSystem.makeESP;
};
fsBuilderMapNix = {
"ext4" = pkgs.mobile-nixos.imageBuilder.fileSystem.makeExt4;
"btrfs" = pkgs.mobile-nixos.imageBuilder.fileSystem.makeBtrfs;
};
# TODO: consolidate bootFsImg, nixFsImg builders; split into separate file?
bootFsImg = fsBuilderMapBoot."${bootFs.fsType}" {
# fs properties
name = "ESP";
bootFsImg = pkgs.runCommandNoCC "ESP" {
nativeBuildInputs = with pkgs; [
dosfstools
libfaketime
mtools
];
partitionID = vfatUuidFromFs bootFs;
size = cfg.bootPartSize;
sectorSize = cfg.sectorSize;
# partition properties
partitionLabel = "EFI System";
partitionType = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"; # "EFI"
partitionUUID = "44444444-4444-4444-4444-4444${vfatUuidFromFs bootFs}";
size = cfg.bootPartSize;
inherit (cfg) sectorSize;
blockSize = cfg.sectorSize; # has to be a multiple of sectorSize
} ''
# hoisted (in simplified form) from pkgs.mobile-nixos.imageBuilder.fileSystem.makeESP
mkdir -p $out
mkdir -p files
populateCommands = let
extras = builtins.toString (builtins.map (d: "cp -R ${d}/* ./") cfg.extraBootFiles);
in ''
(
cd files
echo "running installBootLoader"
${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d .
echo "ran installBootLoader"
${extras}
for d in ${lib.escapeShellArgs cfg.extraBootFiles}; do
cp -R $d/* ./
done
echo "copied extraBootFiles"
'';
};
nixFsImg = fsBuilderMapNix."${nixFs.fsType}" {
)
(
set -x
truncate -s $size "$out/partition.img"
)
echo " -> Making filesystem"
faketime -f "1970-01-01 00:00:01" mkfs.vfat \
-F 32 \
-S "$sectorSize" \
-i "$partitionID" \
-n "$partName" \
"$out/partition.img"
echo " -> Copying files"
(
cd files
for f in ./* ./.*; do
if [[ "$f" != "./." && "$f" != "./.." ]]; then
faketime -f "1970-01-01 00:00:01" \
mcopy -psv -i "$out/partition.img" "$f" ::
fi
done
)
echo " -> Checking filesystem"
fsck.vfat -vn "$out/partition.img"
cat >> $out/layout.json <<EOF
{
"partitionType": "$partitionType",
"partitionUUID": "$partitionUUID",
"partitionLabel": "$partitionLabel"
}
EOF
'';
nixFsImg = pkgs.runCommandNoCC "NIXOS_SYSTEM" {
# fs properties
name = "NIXOS_SYSTEM";
nativeBuildInputs = with pkgs; [ btrfs-progs ];
blockSize = cfg.sectorSize;
partitionID = uuidFromFs nixFs;
# partition properties
partitionLabel = "Linux filesystem";
partitionType = "0FC63DAF-8483-4772-8E79-3D69D8477DE4"; # "Linux filesystem data"
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?
} ''
# hoisted (in simplified form) from pkgs.mobile-nixos.imageBuilder.fileSystem.makeBtrfs
sum-lines() {
local acc=0
while read -r number; do
acc=$(( $acc + $number))
done
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 "$acc"
}
compute-minimal-size() {
local size=0
(
cd files
# Size rounded in blocks. This assumes all files are to be rounded to a
# multiple of blockSize.
# Use of `--apparent-size` is to ensure we don't get the block size of the underlying FS.
# Use of `--block-size` is to get *our* block size.
size=$(find . ! -type d -print0 | du --files0-from=- --apparent-size --block-size "$blockSize" | cut -f1 | sum-lines)
echo "Reserving $size sectors for files..." 1>&2
# Adds one blockSize per directory, they do take some place, in the end.
local directories=$(find . -type d | wc -l)
echo "Reserving $directories sectors for directories..." 1>&2
)
size=$(( $directories + $size ))
size=$(( $size * $blockSize))
echo "$size"
}
mkdir -p $out
mkdir -p files
(
cd files
mkdir -p ./${storeRelPath}
echo "Copying system closure..."
while IFS= read -r path; do
echo " Copying $path"
cp -prf "$path" ./${storeRelPath}
done < "${closureInfo}/store-paths"
done < "${pkgs.buildPackages.closureInfo { rootPaths = config.system.build.toplevel; }}/store-paths"
echo "Done copying system closure..."
cp -v ${closureInfo}/registration ./nix-path-registration
'';
};
img = (pkgs.mobile-nixos.imageBuilder.diskImage.makeGPT {
name = "nixos";
diskID = vfatUuidFromFs bootFs;
# leave some space for firmware
# TODO: we'd prefer to turn this into a protected firmware partition, rather than reserving space in the GPT header itself
# Tow-Boot manages to do that; not sure how.
headerHole = cfg.extraGPTPadding;
partitions = [
(pkgs.mobile-nixos.imageBuilder.gap cfg.firstPartGap)
] ++ lib.optionals (cfg.platformPartSize != null) [
{
name = "kernel"; #< TODO: is it safe to rename this?
filename = "${config.system.build.platformPartition}";
# from: <https://www.chromium.org/chromium-os/chromiumos-design-docs/disk-format>
partitionType = "FE3A2A5D-4F32-41A7-B725-ACCC3285A309";
length = cfg.platformPartSize;
}
)
(
size=$(compute-minimal-size)
set -x
truncate -s $size "$out/partition.img"
)
(
cd files
set -x
mkfs.btrfs \
-r . \
-L "$partName" \
-U "$partitionID" \
--shrink \
"$out/partition.img"
)
cat >> $out/layout.json <<EOF
{
"partitionType": "$partitionType",
"partitionUUID": "$partitionUUID",
"partitionLabel": "$partitionLabel"
}
EOF
'';
platformFsImg = pkgs.runCommandNoCC "kernel" {
filename = "${config.system.build.platformPartition}";
partSize = cfg.platformPartSize;
partImage = config.system.build.platformPartition;
# from: <https://www.chromium.org/chromium-os/chromiumos-design-docs/disk-format>
partitionType = "FE3A2A5D-4F32-41A7-B725-ACCC3285A309"; # "ChromeOS Kernel"
partitionLabel = "kernel"; #< TODO: is it safe to rename this?
} ''
mkdir $out
truncate -s $partSize $out/partition.img
dd if=$partImage of=$out/partition.img bs=512
# TODO: assert that the `dd` command didn't overflow the allocated partition space
cat >> $out/layout.json <<EOF
{
"partitionType": "$partitionType",
"partitionUUID": "$partitionUUID",
"partitionLabel": "$partitionLabel"
}
EOF
'';
img = pkgs.runCommandNoCC "nixos" {
nativeBuildInputs = with pkgs; [
jq
vboot_reference
];
partitions = lib.optionals (cfg.platformPartSize != null) [
platformFsImg
] ++ [
bootFsImg
nixFsImg
];
}) // {
firstPartGap = cfg.firstPartGap;
sectorSize = cfg.sectorSize;
passthru = {
inherit bootFsImg nixFsImg;
};
};
} ''
# hoisted (in simplified form) from pkgs.mobile-nixos.imageBuilder.diskImage.makeGPT
roundUp() {
# adjusts $1 upward until it's a multiple of $2.
local inp=$1
local mult=$2
if (($inp % $mult)); then
echo $(( $mult + $inp / $mult * $mult ))
else
echo $inp
fi
}
getPartSize() {
local partImg="$1/partition.img"
local partSize=$(($(du --apparent-size -B 512 "$partImg" | awk '{ print $1 }') * 512))
echo $(roundUp $partSize $mb)
}
mb=$((1024*1024))
mkdir -p $out
# 34 is the base GPT header size, as added to -p by cgpt.
gptSize=$((34*512))
part0Start=$(( $gptSize + $firstPartGap ))
(
# solve for the size of the disk image
echo "planned disk layout:"
echo "- 0 -> primary GPT header"
totalSize=$part0Start
for part in $partitions; do
echo "- $totalSize -> $part"
partSize=$(getPartSize $part)
totalSize=$(( $totalSize + $partSize ))
done
echo "- $totalSize -> secondary GPT header"
totalSize=$(( $totalSize + $gptSize ))
echo "- $totalSize -> end of disk"
truncate -s $totalSize $out/disk.img
# Zeroes the GPT
cgpt create -z $out/disk.img
# Create the GPT with space if desired
cgpt create -p 0 $out/disk.img
# Add the PMBR
cgpt boot -p $out/disk.img
)
(
partStart=$part0Start
for part in $partitions; do
partSize=$(getPartSize $part)
partitionType=$(jq -r .partitionType $part/layout.json)
partitionUUID=$(jq -r .partitionUUID $part/layout.json)
partitionLabel=$(jq -r .partitionLabel $part/layout.json)
(
set -x
cgpt add \
-b "$(( $partStart / $sectorSize ))" \
-s "$(( $partSize / $sectorSize ))" \
-t "$partitionType" \
-u "$partitionUUID" \
-l "$partitionLabel" \
$out/disk.img
dd conv=notrunc if=$part/partition.img of=$out/disk.img \
seek=$(( $partStart / $sectorSize)) count=$(( $partSize / $sectorSize )) bs=$sectorSize
)
partStart=$(( $partStart + $partSize ))
done
)
echo "disk image created:"
ls -lh $out/disk.img
cgpt show $out/disk.img
'';
in
{
system.build.img = pkgs.runCommand "nixos-with-bootloader" {
system.build.img = pkgs.runCommandNoCC "nixos-with-bootloader" {
preferLocalBuild = true;
passthru = {
inherit bootFsImg nixFsImg;
withoutBootloader = img; #< XXX: this derivation places the image at $out/nixos.img
withoutBootloader = img; #< XXX: this derivation places the image at $out/disk.img
};
} (
if cfg.installBootloader == null then ''

View File

@@ -1,19 +0,0 @@
{ pkgs
, fetchFromGitHub
}:
let
src = fetchFromGitHub {
owner = "nixos";
repo = "mobile-nixos";
# XXX: commit `0f3ac0bef1aea70254a3bae35e3cc2561623f4c1`
# replaces the imageBuilder with a "new implementation from celun" and wildly breaks my use.
# pinning to d25d3b... is equivalent to holding at 2023-09-15
rev = "d25d3b87e7f300d8066e31d792337d9cd7ecd23b";
hash = "sha256-MiVokKlpcJmfoGuWAMeW1En7gZ5hk0rCQArYm6P9XCc=";
};
overlay = import "${src}/overlay/overlay.nix";
final = pkgs.extend overlay;
in src.overrideAttrs (base: {
# passthru only mobile-nixos' own packages -- not the whole nixpkgs-with-mobile-nixos-as-overlay:
passthru = base.passthru // (overlay final pkgs);
})