From 14a9448b79fa650f4d2f80a9668b69ffd4058209 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Thu, 10 Dec 2020 19:26:22 +0100 Subject: [PATCH] fixup! Boot from USB --- nixos-modules/lib/make-ext2-fs.nix | 126 ++++++++++++++--------------- nixos-modules/nova.nix | 35 ++++++-- nixos-modules/qemu-vm.nix | 8 +- 3 files changed, 92 insertions(+), 77 deletions(-) diff --git a/nixos-modules/lib/make-ext2-fs.nix b/nixos-modules/lib/make-ext2-fs.nix index 78b273c..b2dc092 100644 --- a/nixos-modules/lib/make-ext2-fs.nix +++ b/nixos-modules/lib/make-ext2-fs.nix @@ -1,83 +1,77 @@ -# Builds an ext2 image containing a populated /nix/store with the closure -# 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 -, lib -# 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 -, libfaketime -, perl -, fakeroot -, qemu -}: +{ config, pkgs }: let - sdClosureInfo = pkgs.buildPackages.closureInfo { rootPaths = storePaths; }; -in -pkgs.stdenv.mkDerivation { - name = "ext2-fs.qcow2"; + grub' = pkgs.buildPackages.grub2_efi; + sdClosureInfo = pkgs.buildPackages.closureInfo { + rootPaths = config.genode.boot.storePaths; + }; +in pkgs.stdenv.mkDerivation { + name = "ext2-fs.img.zstd"; - nativeBuildInputs = [ e2fsprogs.bin libfaketime perl fakeroot qemu ]; + nativeBuildInputs = with pkgs.buildPackages; [ + e2fsprogs.bin + grub' + libfaketime + perl + fakeroot + zstd + ]; - buildCommand = - '' - img=temp.raw - ( - mkdir -p ./files - ${populateImageCommands} - ) + buildCommand = '' + img=temp.raw - echo "Preparing store paths for image..." + # Create nix/store before copying path + mkdir -p ./rootImage/boot/grub ./rootImage/nix/store - # Create nix/store before copying path - mkdir -p ./rootImage/nix/store + cat < ./rootImage/boot/grub/grub.cfg + set timeout=3 + set default=0 + set gfxpayload=auto - xargs -I % cp -a --reflink=auto % -t ./rootImage/nix/store/ < ${sdClosureInfo}/store-paths - ( - GLOBIGNORE=".:.." - shopt -u dotglob + ${config.boot.loader.grub.extraEntries} + EOF - for f in ./files/*; do - cp -a --reflink=auto -t ./rootImage/ "$f" - done - ) + grub-script-check ./rootImage/boot/grub/grub.cfg - # Also include a manifest of the closures in a format suitable for nix-store --load-db - cp ${sdClosureInfo}/registration ./rootImage/nix-path-registration + xargs -I % cp -a --reflink=auto % -t ./rootImage/nix/store/ < ${sdClosureInfo}/store-paths + ( + GLOBIGNORE=".:.." + shopt -u dotglob - # Make a crude approximation of the size of the target image. - # If the script starts failing, increase the fudge factors here. - numInodes=$(find ./rootImage | wc -l) - numDataBlocks=$(du -s -c -B 4096 --apparent-size ./rootImage | tail -1 | awk '{ print int($1 * 1.10) }') - bytes=$((2 * 4096 * $numInodes + 4096 * $numDataBlocks)) - echo "Creating an EXT2 image of $bytes bytes (numInodes=$numInodes, numDataBlocks=$numDataBlocks)" + for f in ./files/*; do + cp -a --reflink=auto -t ./rootImage/ "$f" + done + ) - truncate -s $bytes $img + # Also include a manifest of the closures in a format suitable for nix-store --load-db + cp ${sdClosureInfo}/registration ./rootImage/nix-path-registration - faketime -f "1970-01-01 00:00:01" fakeroot mkfs.ext2 -L ${volumeLabel} -U ${uuid} -d ./rootImage $img + # Make a crude approximation of the size of the target image. + # If the script starts failing, increase the fudge factors here. + numInodes=$(find ./rootImage | wc -l) + numDataBlocks=$(du -s -c -B 4096 --apparent-size ./rootImage | tail -1 | awk '{ print int($1 * 1.10) }') + bytes=$((2 * 4096 * $numInodes + 4096 * $numDataBlocks)) + echo "Creating an EXT2 image of $bytes bytes (numInodes=$numInodes, numDataBlocks=$numDataBlocks)" - export EXT2FS_NO_MTAB_OK=yes - # 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.ext2 -n -f $img; then - echo "--- Fsck failed for EXT2 image of $bytes bytes (numInodes=$numInodes, numDataBlocks=$numDataBlocks) ---" - cat errorlog - return 1 - fi + truncate --size=$bytes $img - echo "Resizing to minimum allowed size" - resize2fs -M $img + faketime -f "1970-01-01 00:00:01" fakeroot mkfs.ext2 -L NIXOS_GENODE -U ${config.genode.boot.storeFsUuid} -d ./rootImage $img - # And a final fsck, because of the previous truncating. - fsck.ext2 -n -f $img + export EXT2FS_NO_MTAB_OK=yes + # 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.ext2 -n -f $img; then + echo "--- Fsck failed for EXT2 image of $bytes bytes (numInodes=$numInodes, numDataBlocks=$numDataBlocks) ---" + cat errorlog + return 1 + fi - qemu-img convert $img $out - ''; + echo "Resizing to minimum allowed size" + resize2fs -M $img + + # And a final fsck, because of the previous truncating. + fsck.ext2 -n -f $img + + # Compress to store + zstd --verbose --no-progress ./$img -o $out + ''; } diff --git a/nixos-modules/nova.nix b/nixos-modules/nova.nix index da52d0e..0ba09c4 100644 --- a/nixos-modules/nova.nix +++ b/nixos-modules/nova.nix @@ -7,6 +7,17 @@ let inherit (config.nixpkgs) system localSystem crossSystem; inherit pkgs; }; + + bootDir = pkgs.runCommand "${config.system.name}-bootdir" { } '' + mkdir $out + gz() { + gzip --keep --to-stdout "$1" > "$2" + } + gz ${pkgs.genodePackages.genodeSources}/tool/boot/bender $out/bender.gz + gz ${pkgs.genodePackages.NOVA}/hypervisor-x86_64 $out/hypervisor.gz + gz ${config.genode.boot.image}/image.elf $out/image.elf.gz + ''; + in { genode.core = { prefix = "nova-"; @@ -15,13 +26,27 @@ in { }; genode.boot = { - - initrd = - "'${pkgs.genodePackages.NOVA}/hypervisor-x86_64 arg=iommu novpid serial,${config.genode.boot.image}/image.elf'"; - image = utils.novaImage config.system.name { } config.genode.boot.configFile; - }; + genode.boot.storePaths = + lib.optional (config.genode.boot.storeBackend == "usb") bootDir; + + virtualisation.qemu.options = + lib.optionals (!config.virtualisation.useBootLoader) [ + "-kernel '${pkgs.genodePackages.bender}/share/bender/bender'" + "-initrd '${pkgs.genodePackages.NOVA}/hypervisor-x86_64 arg=iommu logmem novpid serial,${config.genode.boot.image}/image.elf'" + ]; + + boot.loader.grub.extraEntries = '' + menuentry 'Genode on NOVA' { + insmod multiboot2 + insmod gzio + multiboot2 ${bootDir}/bender.gz serial_fallback + module2 ${bootDir}/hypervisor.gz hypervisor iommu logmem novga novpid serial + module2 ${bootDir}/image.elf.gz image.elf + } + ''; + } diff --git a/nixos-modules/qemu-vm.nix b/nixos-modules/qemu-vm.nix index 9f91cb0..d0b0feb 100644 --- a/nixos-modules/qemu-vm.nix +++ b/nixos-modules/qemu-vm.nix @@ -83,9 +83,9 @@ let imap1 (idx: drive: drive // { device = driveDeviceName idx; }); efiPrefix = if (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) then - "${pkgs.OVMF.fd}/FV/OVMF" + "${pkgs.buildPackages.OVMF.fd}/FV/OVMF" else if pkgs.stdenv.isAarch64 then - "${pkgs.OVMF.fd}/FV/AAVMF" + "${pkgs.buildPackages.OVMF.fd}/FV/AAVMF" else throw "No EFI firmware available for platform"; efiFirmware = "${efiPrefix}_CODE.fd"; @@ -516,10 +516,6 @@ in { "-device usb-kbd" "-device usb-tablet" ]) - (mkIf (!cfg.useBootLoader) [ - "-kernel ${config.genode.boot.kernel}" - "-initrd ${config.genode.boot.initrd}" - ]) (mkIf cfg.useEFIBoot [ "-drive if=pflash,format=raw,unit=0,readonly,file=${efiFirmware}" "-drive if=pflash,format=raw,unit=1,file=$NIX_EFI_VARS"