diff --git a/nixos-modules/genode-core.nix b/nixos-modules/genode-core.nix index ab0fee3..2b28dc8 100644 --- a/nixos-modules/genode-core.nix +++ b/nixos-modules/genode-core.nix @@ -1,38 +1,70 @@ { config, pkgs, lib, modulesPath, ... }: with lib; -let localPackages = pkgs.buildPackages; +let + localPackages = pkgs.buildPackages; + coreROMs = mkOption { + type = with types; listOf str; + default = [ ]; + description = '' + List of label suffixes that when matched against + ROM requests shall be forwared to the core. + ''; + example = [ "platform_info" ]; + }; + inputs = mkOption { + description = "List of packages to build a ROM store with."; + default = [ ]; + type = types.listOf types.package; + }; in { options.genode = { + core = { prefix = mkOption { type = types.str; example = "hw-pc-"; + description = "String prefix signifying the Genode core in use."; }; supportedSystems = mkOption { type = types.listOf types.str; example = [ "i686-genode" "x86_64-genode" ]; + description = "Hardware supported by this core."; }; - basePackages = mkOption { type = types.listOf types.package; }; + basePackages = mkOption { + type = types.listOf types.package; + description = '' + List of packages to make availabe before the Nix store is ready. + These are baked into . + ''; + }; + + children = mkOption { + type = with types; + attrsOf (submodule { + options = { + inherit coreROMs inputs; + configFile = mkOption { + type = types.path; + description = '' + Set of children at the lowest init level, these children must not + have any dependency on a Nix store. + Configuration format is a Dhall configuration of type + Genode.Init.Child.Type. + See https://git.sr.ht/~ehmry/dhall-genode/tree/master/Init/Child/Type + ''; + }; + }; + }); + }; }; boot = { - kernel = mkOption { - type = types.path; - default = "${pkgs.genodePackages.bender}/bender"; - }; - - initrd = mkOption { - type = types.str; - default = "${pkgs.genodePackages.bender}/bender"; - description = "Path to an image or a command-line arguments"; - }; - configFile = mkOption { type = types.path; description = '' @@ -49,9 +81,59 @@ in { romModules = mkOption { type = types.attrsOf types.path; + default = { }; description = "Attr set of initial ROM modules"; }; + storeFsUuid = mkOption { + type = types.str; + default = import ./store-fs-uuid; + description = "Custom partition type of the nix-store file-system."; + }; + + storePartUuid = mkOption { + type = types.str; + default = import ./partition-type; + description = "Custom partition type of the nix-store file-system."; + }; + + storeBackend = mkOption { + type = types.enum [ "tarball" "usb" ]; # "parent"? + default = "tarball"; + description = '' + Backend for the initial /nix/store file-system. + + + + + tarball + + + An in-memory tarball. + + + + + + usb + + + An EXT2 file-system backed by USB storage. + + + + + + ''; + }; + + storePaths = mkOption { + type = with types; listOf package; + description = '' + Derivations to be included in the Nix store in the generated boot image. + ''; + }; + }; }; @@ -75,20 +157,17 @@ in { }; mergeManifests = inputs: - localPackages.writeTextFile { - name = "manifest.dhall"; - text = with builtins; - let - f = head: input: - if hasAttr "manifest" input then - '' - ${head}, { mapKey = "${ - lib.getName input - }", mapValue = ${input.manifest} }'' - else - abort "${input.pname} does not have a manifest"; - in (foldl' f "[" inputs) + "]"; - }; + with builtins; + let + f = head: input: + if hasAttr "manifest" input then + '' + ${head}, { mapKey = "${ + lib.getName input + }", mapValue = ${input.manifest} }'' + else + abort "${input.pname} does not have a manifest"; + in (foldl' f "[" inputs) + "]"; romDirectories = filterAttrs (_: value: value != null) (mapAttrs (name: value: @@ -108,18 +187,114 @@ in { message = "invalid Genode core for this system"; }]; + genode.core.basePackages = + lib.optional (config.genode.boot.storeBackend == "usb") + pkgs.genodePackages.part_block; + + genode.core.children = + # Component to steer the store_fs to a specific partition + (if config.genode.boot.storeBackend == "usb" then { + part_block.configFile = builtins.toFile "part_block.dhall" '' + let Genode = env:DHALL_GENODE + + let Init = Genode.Init + + in Init.Child.flat + Init.Child.Attributes::{ + , binary = "part_block" + , resources = Init.Resources::{ ram = Genode.units.MiB 8 } + , config = Init.Config::{ + , attributes = toMap { ignore_mbr = "yes" } + , policies = + [ Init.Config.Policy::{ + , service = "Block" + , label = Init.LabelSelector.prefix "store_fs" + , attributes = toMap + { partition = "1" + , writeable = "yes" + , TODO = "select by partition UUID" + } + } + ] + } + } + ''; + } else + { }) // { + store_fs.configFile = let + + storeVfsConfig = { + tarball = '' + VFS.vfs [ VFS.leafAttrs "tar" (toMap { name = "${config.system.build.tarball.fileName}.tar" }) ] + ''; + usb = '' + VFS.vfs [ VFS.leafAttrs "rump" (toMap { fs = "ext2fs", ram="12M" }) ] + ''; + }.${config.genode.boot.storeBackend}; + + storeResources = { + tarball = "Init.Resources.default"; + usb = "Init.Resources::{ caps = 256, ram = Genode.units.MiB 16 }"; + }.${config.genode.boot.storeBackend}; + + in builtins.toFile "store_fs.dhall" '' + let Genode = env:DHALL_GENODE + + let Init = Genode.Init + + let VFS = Genode.VFS + + in Init.Child.flat + Init.Child.Attributes::{ + , binary = "vfs" + , resources = ${storeResources} + , provides = [ "File_system" ] + , config = Init.Config::{ + , content = [ ${storeVfsConfig} ] + , policies = + [ Init.Config.Policy::{ + , service = "File_system" + , label = Init.LabelSelector.suffix "nix-store" + , attributes = toMap { root = "/nix/store" } + } + , Init.Config.Policy::{ + , service = "File_system" + , label = Init.LabelSelector.prefix "store_rom" + , attributes = toMap { root = "/" } + } + ] + } + } + ''; + }; + genode.boot.configFile = let tarball = "${config.system.build.tarball}/tarball/${config.system.build.tarball.fileName}.tar"; - manifest = mergeManifests (map addManifest - (config.genode.core.basePackages ++ [ config.system.build.tarball ] - ++ (with pkgs.genodePackages; [ - init - cached_fs_rom - jitter_sponge - report_rom - vfs - ]))); + + storeBackendInputs = { + tarball = [ config.system.build.tarball ]; + usb = [ pkgs.genodePackages.rump ]; + }.${config.genode.boot.storeBackend}; + + coreInputs = with builtins; + concatMap (getAttr "inputs") (attrValues config.genode.core.children); + + manifest = + # Manifests are Dhall metadata to be attached to every + # package to be used for dynamically buildings enviroments + # using Dhall expressions. Probably not worth pursuing. + pkgs.writeText "manifest.dhall" (mergeManifests (map addManifest + (with pkgs.genodePackages; + config.genode.core.basePackages ++ storeBackendInputs + ++ [ init cached_fs_rom jitter_sponge report_rom vfs ] + ++ coreInputs)) + + lib.optionalString (config.genode.boot.romModules != { }) '' + # [ { mapKey = "romModules", mapValue = [ ${ + toString (mapAttrsToList + (k: v: '', { mapKey = "${k}", mapValue = "${v}" }'') + config.genode.boot.romModules) + }] } ]''); storeRomPolicies = mapAttrsToList (name: value: '', { mapKey = "${name}", mapValue = "${value}" }'') @@ -138,19 +313,34 @@ in { } '') value.coreROMs) config.genode.init.children)); + extraCoreChildren = "[ ${ + toString (lib.mapAttrsToList (name: value: + '', { mapKey = "${name}", mapValue = ${value.configFile} }'') + config.genode.core.children) + } ]"; + in localPackages.runCommand "boot.dhall" { } '' cat > $out << EOF let Genode = env:DHALL_GENODE in + let VFS = Genode.VFS + let XML = Genode.Prelude.XML + in ${./store-wrapper.dhall} - (${config.genode.init.configFile}) - "${config.system.build.tarball.fileName}.tar" - $(stat --format '%s' ${tarball}) - ([${toString storeRomPolicies} ] : Genode.Prelude.Map.Type Text Text) - ([${extraRoutes} ] : List Genode.Init.ServiceRoute.Type) - ${manifest} + { extraCoreChildren = ${extraCoreChildren} + , subinit = ${config.genode.init.configFile} + , storeSize = $(stat --format '%s' ${tarball}) + , storeRomPolicies = [${ + toString storeRomPolicies + } ] : Genode.Prelude.Map.Type Text Text + , routes = [${extraRoutes} ] : List Genode.Init.ServiceRoute.Type + , bootManifest = ${manifest} + } EOF ''; + genode.boot.storePaths = with builtins; + [ config.genode.init.configFile ] ++ (attrValues romDirectories); + # Create the tarball of the store to live in core ROM system.build.tarball = pkgs.callPackage "${modulesPath}/../lib/make-system-tarball.nix" { @@ -181,6 +371,25 @@ in { xmllint --noout $out ''; + system.build.bootDriveImage = let + espImage = import ./lib/make-esp-fs.nix { inherit config pkgs; }; + storeFsImage = + pkgs.callPackage ./lib/make-ext2-fs.nix { inherit config pkgs; }; + bootDriveImage = import ./lib/make-bootable-image.nix { + inherit config pkgs espImage storeFsImage; + }; + in bootDriveImage; + + # virtualisation.useEFIBoot = config.genode.boot.storeBackend == "usb"; + + virtualisation.qemu.options = + lib.optionals (config.genode.boot.storeBackend == "usb") [ + "-bios ${pkgs.buildPackages.OVMF.fd}/FV/OVMF.fd" + "-drive id=usbdisk,file=${config.system.build.bootDriveImage},if=none,readonly" + "-usb" + "-device usb-storage,drive=usbdisk" + ]; + }; } diff --git a/nixos-modules/hardware/default.nix b/nixos-modules/hardware/default.nix new file mode 100644 index 0000000..ad29081 --- /dev/null +++ b/nixos-modules/hardware/default.nix @@ -0,0 +1,85 @@ +{ config, pkgs, lib, ... }: + +with lib; + +{ + imports = [ ./nic.nix ./usb.nix ]; + + options.hardware.genode.platform.policies = lib.mkOption { + type = with types; listOf path; + default = [ ]; + description = '' + List of policies to append to the Genode platform driver. + Type is Init.Config.Policy.Type. + ''; + }; + + config = { + + genode.core.basePackages = with pkgs.genodePackages; [ + acpi_drv + platform_drv + ]; + + genode.init.children.acpi_drv = { + coreROMs = [ "acpi_drv" ]; + configFile = pkgs.writeText "acpi_drv.dhall" '' + let Genode = env:DHALL_GENODE + + let Init = Genode.Init + + let label = λ(_ : Text) → { local = _, route = _ } + + in Init.Child.flat + Init.Child.Attributes::{ + , binary = "acpi_drv" + , resources = Init.Resources::{ + , caps = 400 + , ram = Genode.units.MiB 4 + , constrainPhys = True + } + , romReports = [ label "acpi", label "smbios_table" ] + , routes = + [ Init.ServiceRoute.parent "IRQ" + , Init.ServiceRoute.parent "IO_MEM" + , Init.ServiceRoute.parent "IO_PORT" + ] + } + ''; + }; + + genode.init.children.platform_drv = { + coreROMs = [ "platform_drv" ]; + configFile = let + policies = + map (policy: ", ${policy}") config.hardware.genode.platform.policies; + in pkgs.writeText "platform_drv.dhall" '' + let Genode = env:DHALL_GENODE + + let Init = Genode.Init + + in Init.Child.flat + Init.Child.Attributes::{ + , binary = "platform_drv" + , resources = Init.Resources::{ + , caps = 800 + , ram = Genode.units.MiB 4 + , constrainPhys = True + } + , reportRoms = let label = "acpi" in [ { local = label, route = label } ] + , provides = [ "Platform" ] + , routes = + [ Init.ServiceRoute.parent "IRQ" + , Init.ServiceRoute.parent "IO_MEM" + , Init.ServiceRoute.parent "IO_PORT" + ] + , config = Init.Config::{ + , policies = [ ${toString policies} ] + } + } + ''; + }; + + }; + +} diff --git a/nixos-modules/hardware.nix b/nixos-modules/hardware/nic.nix similarity index 72% rename from nixos-modules/hardware.nix rename to nixos-modules/hardware/nic.nix index 4066ac4..22e2355 100644 --- a/nixos-modules/hardware.nix +++ b/nixos-modules/hardware/nic.nix @@ -21,15 +21,6 @@ with lib; })); }; - hardware.genode.platform.policies = lib.mkOption { - type = with types; listOf path; - default = [ ]; - description = '' - List of policies to append to the Genode platform driver. - Type is Init.Config.Policy.Type. - ''; - }; - }; config = { @@ -66,11 +57,6 @@ with lib; } '') (builtins.attrNames config.networking.interfaces); - genode.core.basePackages = with pkgs.genodePackages; [ - acpi_drv - platform_drv - ]; - genode.init.children = let nics = mapAttrs' (name: interface: @@ -199,68 +185,7 @@ with lib; }; }) config.networking.interfaces; - in nics // (lib.filterAttrs (n: v: v != null) sockets) // { - - acpi_drv = { - coreROMs = [ "acpi_drv" ]; - configFile = pkgs.writeText "acpi_drv.dhall" '' - let Genode = env:DHALL_GENODE - - let Init = Genode.Init - - let label = λ(_ : Text) → { local = _, route = _ } - - in Init.Child.flat - Init.Child.Attributes::{ - , binary = "acpi_drv" - , resources = Init.Resources::{ - , caps = 400 - , ram = Genode.units.MiB 4 - , constrainPhys = True - } - , romReports = [ label "acpi", label "smbios_table" ] - , routes = - [ Init.ServiceRoute.parent "IRQ" - , Init.ServiceRoute.parent "IO_MEM" - , Init.ServiceRoute.parent "IO_PORT" - ] - } - ''; - }; - - platform_drv = { - coreROMs = [ "platform_drv" ]; - configFile = let - policies = map (policy: ", ${policy}") - config.hardware.genode.platform.policies; - in pkgs.writeText "platform_drv.dhall" '' - let Genode = env:DHALL_GENODE - - let Init = Genode.Init - - in Init.Child.flat - Init.Child.Attributes::{ - , binary = "platform_drv" - , resources = Init.Resources::{ - , caps = 800 - , ram = Genode.units.MiB 4 - , constrainPhys = True - } - , reportRoms = let label = "acpi" in [ { local = label, route = label } ] - , provides = [ "Platform" ] - , routes = - [ Init.ServiceRoute.parent "IRQ" - , Init.ServiceRoute.parent "IO_MEM" - , Init.ServiceRoute.parent "IO_PORT" - ] - , config = Init.Config::{ - , policies = [ ${toString policies} ] - } - } - ''; - }; - - }; + in nics // (lib.filterAttrs (n: v: v != null) sockets); }; diff --git a/nixos-modules/hardware/usb.nix b/nixos-modules/hardware/usb.nix new file mode 100644 index 0000000..f78d72d --- /dev/null +++ b/nixos-modules/hardware/usb.nix @@ -0,0 +1,82 @@ +{ config, pkgs, lib, ... }: + +with lib; + +{ + options = { + + hardware.usb.genode.enable = lib.mkEnableOption "USB driver"; + + hardware.usb.genode.storage.enable = + lib.mkEnableOption "USB mass storage driver"; + + }; + + config = { + + hardware.usb.genode.storage.enable = config.genode.boot.storeBackend + == "usb"; + + hardware.usb.genode.enable = config.hardware.usb.genode.storage.enable; + + hardware.genode.platform.policies = + lib.optional config.hardware.usb.genode.enable + (builtins.toFile ("usb.platform-policy.dhall") '' + let Genode = env:DHALL_GENODE + + in Genode.Init.Config.Policy::{ + , service = "Platform" + , label = Genode.Init.LabelSelector.prefix "usb_drv" + , content = + [ Genode.Prelude.XML.leaf + { name = "pci", attributes = toMap { class = "USB" } } + ] + } + ''); + + genode.core.basePackages = lib.optional config.hardware.usb.genode.enable + pkgs.genodePackages.usb_drv; + + genode.init.children.usb_drv = lib.mkIf config.hardware.usb.genode.enable { + coreROMs = [ "usb_drv" ]; + configFile = builtins.toFile "usb_drv.dhall" '' + let Genode = env:DHALL_GENODE + + let XML = Genode.Prelude.XML + + let Init = Genode.Init + + let storageEnable = ${ + if config.hardware.usb.genode.storage.enable then "True" else "False" + } + + in Init.Child.flat + Init.Child.Attributes::{ + , binary = "usb_drv" + , provides = [ "Block", "Usb" ] + , resources = Init.Resources::{ caps = 256, ram = Genode.units.MiB 12 } + , routes = [ Init.ServiceRoute.parent "IO_MEM" ] + , config = Init.Config::{ + , attributes = toMap { uhci = "yes", ehci = "yes", xhci = "yes" } + , content = + if storageEnable + then [ XML.leaf + { name = "storage", attributes = XML.emptyAttributes } + ] + else [] : List XML.Type + , policies = + if storageEnable + then [ Init.Config.Policy::{ + , service = "Block" + , label = Init.LabelSelector.prefix "store_fs" + } + ] + else [] : List Init.Config.Policy.Type + } + } + ''; + }; + + }; + +} diff --git a/nixos-modules/lib/make-bootable-image.nix b/nixos-modules/lib/make-bootable-image.nix new file mode 100644 index 0000000..3a12cbf --- /dev/null +++ b/nixos-modules/lib/make-bootable-image.nix @@ -0,0 +1,69 @@ +# Builds a compressed EFI System Partition image +{ config, pkgs, espImage, storeFsImage }: + +pkgs.stdenv.mkDerivation { + name = "boot.qcow2"; + + nativeBuildInputs = with pkgs.buildPackages; [ + config.system.build.qemu + utillinux + zstd + ]; + + buildCommand = '' + img=./temp.raw + blockSize=512 + sectorSize=$(( $blockSize * 1 )) + imgBytes=0 + + espSectorOffset=2048 + esbByteOffset=$(( $espSectorOffset * $sectorSize )) + + # Pad the front of the image + echo "Pad front of image with " $esbByteOffset " bytes" + truncate --size=$esbByteOffset $img + + # Concatentenate the ESP + echo "Concatenate ESP ${espImage}" + zstdcat ${espImage} >> $img + + imgBytes=$(stat --format=%s $img) + echo "Image is $(( $imgBytes >> 20 )) MiB with ESP partition" + + nixSectorOffset=$(( ($imgBytes + $sectorSize - 1) / $sectorSize )) + nixByteOffset=$(( $nixSectorOffset * $sectorSize )) + + # Pad the ESP + echo "Pad end of ESP with " $(( $nixByteOffset - $imgBytes )) " bytes" + truncate --size=$nixByteOffset $img + + # Concatenate the nix partition + echo "Concatenate store ${storeFsImage}" + zstdcat ${storeFsImage} >> $img + + imgBytes=$(stat --format=%s $img) + echo "Image is $(( $imgBytes >> 20 )) MiB with store partition" + + endSectorOffset=$(( ($(stat --format=%s $img) + $sectorSize + 1) / $sectorSize )) + endByteOffset=$(( $endSectorOffset * $sectorSize )) + + # Pad the end of the image + echo "Pad end of store with $(( $endByteOffset - $imgBytes )) bytes" + truncate --size=$endByteOffset $img + + imgBytes=$(stat --format=%s $img) + echo "Image is $(( $imgBytes >> 20 )) MiB with final padding" + + efiUuid=C12A7328-F81F-11D2-BA4B-00A0C93EC93B + + # Create the partition table + sfdisk $img < embedded.cfg + insmod configfile + insmod efi_gop + insmod efi_uga + insmod ext2 + insmod normal + insmod part_gpt + insmod search_fs_uuid + search.fs_uuid ${config.genode.boot.storeFsUuid} root + set prefix=($root)/boot/grub + configfile /boot/grub/grub.cfg + EOF + + grub-script-check embedded.cfg + + ${grub'}/bin/grub-mkimage \ + --config=embedded.cfg \ + --output=$bootdir/boot${targetArch}.efi \ + --prefix=/boot/grub \ + --format=${grub'.grubTarget} \ + $MODULES + + # Make the ESP image twice as large as necessary + imageBytes=$(du --summarize --block-size=4096 --total $bootdir | tail -1 | awk '{ print int($1 * 8192) }') + + truncate --size=$imageBytes $img + mkfs.vfat -n EFIBOOT --invariant $img + mcopy -sv -i $img EFI :: + fsck.vfat -nv $img + + zstd --verbose --no-progress ./$img -o $out + ''; +} diff --git a/nixos-modules/lib/make-ext2-fs.nix b/nixos-modules/lib/make-ext2-fs.nix new file mode 100644 index 0000000..b2dc092 --- /dev/null +++ b/nixos-modules/lib/make-ext2-fs.nix @@ -0,0 +1,77 @@ +{ config, pkgs }: + +let + grub' = pkgs.buildPackages.grub2_efi; + sdClosureInfo = pkgs.buildPackages.closureInfo { + rootPaths = config.genode.boot.storePaths; + }; +in pkgs.stdenv.mkDerivation { + name = "ext2-fs.img.zstd"; + + nativeBuildInputs = with pkgs.buildPackages; [ + e2fsprogs.bin + grub' + libfaketime + perl + fakeroot + zstd + ]; + + buildCommand = '' + img=temp.raw + + # Create nix/store before copying path + mkdir -p ./rootImage/boot/grub ./rootImage/nix/store + + cat < ./rootImage/boot/grub/grub.cfg + set timeout=3 + set default=0 + set gfxpayload=auto + + ${config.boot.loader.grub.extraEntries} + EOF + + grub-script-check ./rootImage/boot/grub/grub.cfg + + xargs -I % cp -a --reflink=auto % -t ./rootImage/nix/store/ < ${sdClosureInfo}/store-paths + ( + GLOBIGNORE=".:.." + shopt -u dotglob + + for f in ./files/*; do + cp -a --reflink=auto -t ./rootImage/ "$f" + done + ) + + # Also include a manifest of the closures in a format suitable for nix-store --load-db + cp ${sdClosureInfo}/registration ./rootImage/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 ./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)" + + truncate --size=$bytes $img + + faketime -f "1970-01-01 00:00:01" fakeroot mkfs.ext2 -L NIXOS_GENODE -U ${config.genode.boot.storeFsUuid} -d ./rootImage $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 + + 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..937f4c5 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}/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/partition-type b/nixos-modules/partition-type new file mode 100644 index 0000000..2cca25d --- /dev/null +++ b/nixos-modules/partition-type @@ -0,0 +1 @@ +"24b69406-18a1-428d-908e-d21a1437122c" 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" diff --git a/nixos-modules/store-fs-uuid b/nixos-modules/store-fs-uuid new file mode 100644 index 0000000..7325548 --- /dev/null +++ b/nixos-modules/store-fs-uuid @@ -0,0 +1 @@ +"9668f8dd-d9a0-4398-a55a-0d499d5e5cbb" diff --git a/nixos-modules/store-wrapper.dhall b/nixos-modules/store-wrapper.dhall index 15f089a..dbc0db0 100644 --- a/nixos-modules/store-wrapper.dhall +++ b/nixos-modules/store-wrapper.dhall @@ -2,195 +2,184 @@ let Genode = env:DHALL_GENODE let Prelude = Genode.Prelude +let XML = Prelude.XML + let Init = Genode.Init let Child = Init.Child let TextMapType = Prelude.Map.Type Text +let ChildMapType = TextMapType Child.Type + let Manifest/Type = TextMapType (TextMapType Text) -in λ(subinit : Init.Type) → - λ(storeName : Text) → - λ(storeSize : Natural) → - λ(storeRomPolicies : Prelude.Map.Type Text Text) → - λ(routes : List Init.ServiceRoute.Type) → - λ(bootManifest : Manifest/Type) → +in λ ( params + : { extraCoreChildren : ChildMapType + , subinit : Init.Type + , storeSize : Natural + , storeRomPolicies : Prelude.Map.Type Text Text + , routes : List Init.ServiceRoute.Type + , bootManifest : Manifest/Type + } + ) → Genode.Boot::{ , config = Init::{ - , routes + , routes = params.routes , children = let child = Prelude.Map.keyValue Child.Type - in [ child - "timer" - ( Child.flat - Child.Attributes::{ - , binary = "timer_drv" - , provides = [ "Timer" ] - } - ) - , child - "rtc" - ( Child.flat - Child.Attributes::{ - , binary = "rtc_drv" - , provides = [ "Rtc" ] - , routes = [ Init.ServiceRoute.parent "IO_PORT" ] - } - ) - , child - "jitter_sponge" - ( Child.flat - Child.Attributes::{ - , binary = "jitter_sponge" - , provides = [ "Terminal" ] - , config = Init.Config::{ - , policies = - [ Init.Config.Policy::{ - , service = "Terminal" - , label = Init.LabelSelector.suffix "entropy" - } - ] + in [ child + "timer" + ( Child.flat + Child.Attributes::{ + , binary = "timer_drv" + , provides = [ "Timer" ] + , config = Init.Config::{ + , policies = + [ Init.Config.Policy::{ + , service = "Timer" + , label = Init.LabelSelector.none + } + ] + } } - } - ) - , child - "store_fs" - ( Child.flat - Child.Attributes::{ - , binary = "vfs" - , config = Init.Config::{ - , content = - let VFS = Genode.VFS - - in [ VFS.vfs - [ VFS.leafAttrs - "tar" - (toMap { name = storeName }) - ] + ) + , child + "rtc" + ( Child.flat + Child.Attributes::{ + , binary = "rtc_drv" + , provides = [ "Rtc" ] + , routes = [ Init.ServiceRoute.parent "IO_PORT" ] + } + ) + , child + "jitter_sponge" + ( Child.flat + Child.Attributes::{ + , binary = "jitter_sponge" + , provides = [ "Terminal" ] + , config = Init.Config::{ + , policies = + [ Init.Config.Policy::{ + , service = "Terminal" + , label = Init.LabelSelector.suffix "entropy" + } + ] + } + } + ) + , child + "store_rom" + ( Child.flat + Child.Attributes::{ + , binary = "cached_fs_rom" + , provides = [ "ROM" ] + , resources = Init.Resources::{ + , ram = params.storeSize + Genode.units.MiB 1 + } + , config = Init.Config::{ + , policies = + [ Init.Config.Policy::{ + , service = "ROM" + , label = + Init.LabelSelector.prefix + "nixos -> /nix/store" + , diag = Some True + } ] - , policies = - [ Init.Config.Policy::{ - , service = "File_system" - , label = Init.LabelSelector.suffix "nix-store" - , attributes = toMap { root = "/nix/store" } - } - , Init.Config.Policy::{ - , service = "File_system" - , label = Init.LabelSelector.prefix "store_rom" - , attributes = toMap { root = "/" } - } - ] - } - , provides = [ "File_system" ] - } - ) - , child - "store_rom" - ( Child.flat - Child.Attributes::{ - , binary = "cached_fs_rom" - , provides = [ "ROM" ] - , resources = Init.Resources::{ - , ram = storeSize + Genode.units.MiB 1 - } - , config = Init.Config::{ - , policies = - [ Init.Config.Policy::{ - , service = "ROM" - , label = - Init.LabelSelector.prefix - "nixos -> /nix/store" - } - ] - # ( let Entry = Prelude.Map.Entry Text Text + # ( let Entry = Prelude.Map.Entry Text Text - in Prelude.List.concatMap - Entry - Init.Config.Policy.Type - ( λ(e : Entry) → - [ Init.Config.Policy::{ - , service = "ROM" - , label = - Init.LabelSelector.prefix - "nixos -> ${e.mapKey}" - , attributes = toMap - { directory = - "${e.mapValue}/bin" - } - } - , Init.Config.Policy::{ - , service = "ROM" - , label = - Init.LabelSelector.Type.Partial - { prefix = Some - "nixos -> ${e.mapKey}" - , suffix = Some ".lib.so" + in Prelude.List.concatMap + Entry + Init.Config.Policy.Type + ( λ(e : Entry) → + [ Init.Config.Policy::{ + , service = "ROM" + , diag = Some True + , label = + Init.LabelSelector.prefix + "nixos -> ${e.mapKey}" + , attributes = toMap + { directory = + "${e.mapValue}/bin" } - , attributes = toMap - { directory = - "${e.mapValue}/lib" - } - } - ] - ) - storeRomPolicies - ) - } - } - ) - , child - "nixos" - ( Init.toChild - subinit - Init.Attributes::{ - , exitPropagate = True - , resources = Init.Resources::{ - , ram = Genode.units.MiB 4 - } - , routes = - let parentROMs = - Prelude.List.concatMap - Text - Init.ServiceRoute.Type - ( λ(suffix : Text) → - Prelude.List.map - Text - Init.ServiceRoute.Type - ( λ(prefix : Text) → - { service = - { name = "ROM" + } + , Init.Config.Policy::{ + , service = "ROM" + , diag = Some True , label = Init.LabelSelector.Type.Partial - { prefix = Some prefix - , suffix = Some suffix + { prefix = Some + "nixos -> ${e.mapKey}" + , suffix = Some ".so" } + , attributes = toMap + { directory = + "${e.mapValue}/lib" + } } - , route = - Init.Route.parent - (Some suffix) - } + ] ) - ( Prelude.Map.keys - Text - Init.Child.Type - subinit.children - ) - ) + params.storeRomPolicies + ) + } + } + ) + ] + # params.extraCoreChildren + # [ child + "nixos" + ( Init.toChild + params.subinit + Init.Attributes::{ + , exitPropagate = True + , resources = Init.Resources::{ + , ram = Genode.units.MiB 4 + } + , routes = + let parentROMs = + Prelude.List.concatMap + Text + Init.ServiceRoute.Type + ( λ(suffix : Text) → + Prelude.List.map + Text + Init.ServiceRoute.Type + ( λ(prefix : Text) → + { service = + { name = "ROM" + , label = + Init.LabelSelector.Type.Partial + { prefix = Some prefix + , suffix = Some suffix + } + } + , route = + Init.Route.parent + (Some suffix) + } + ) + ( Prelude.Map.keys + Text + Init.Child.Type + params.subinit.children + ) + ) - in parentROMs - [ "ld.lib.so", "vfs.lib.so", "init" ] - # [ Init.ServiceRoute.parent "IO_MEM" - , Init.ServiceRoute.parent "IO_PORT" - , Init.ServiceRoute.parent "IRQ" - , Init.ServiceRoute.parent "VM" - , Init.ServiceRoute.child "Timer" "timer" - , Init.ServiceRoute.child "Rtc" "rtc" - ] - } - ) - ] + in parentROMs + [ "ld.lib.so", "vfs.lib.so", "init" ] + # [ Init.ServiceRoute.parent "IO_MEM" + , Init.ServiceRoute.parent "IO_PORT" + , Init.ServiceRoute.parent "IRQ" + , Init.ServiceRoute.parent "VM" + , Init.ServiceRoute.child "Timer" "timer" + , Init.ServiceRoute.child "Rtc" "rtc" + ] + } + ) + ] } , rom = Genode.BootModules.toRomPaths @@ -199,7 +188,7 @@ in λ(subinit : Init.Type) → ( Prelude.Map.values Text (Prelude.Map.Type Text Text) - bootManifest + params.bootManifest ) ) } diff --git a/tests/lib/build-vms.nix b/tests/lib/build-vms.nix index 1e3db3f..eea9aeb 100644 --- a/tests/lib/build-vms.nix +++ b/tests/lib/build-vms.nix @@ -29,6 +29,7 @@ rec { baseModules = (import "${modulesPath}/module-list.nix") ++ [ ../../nixos-modules/genode-core.nix ../../nixos-modules/genode-init.nix + ../../nixos-modules/hardware ../../nixos-modules/qemu-vm.nix { key = "no-manual"; diff --git a/tests/networking.nix b/tests/networking.nix index 67d0d39..b61626a 100644 --- a/tests/networking.nix +++ b/tests/networking.nix @@ -2,10 +2,9 @@ name = "networking"; nodes = { - a = { pkgs, ... }: { imports = [ ../nixos-modules/hardware.nix ]; }; + a = { pkgs, ... }: { }; b = { config, pkgs, lib, ... }: { - imports = [ ../nixos-modules/hardware.nix ]; networking.interfaces.eth1.genode.stack = null; genode.init.children.ping = { inputs = with pkgs.genodePackages; [ ping ];