From b4f0b8f3a09ca2b7f0725da23bb86752eee445a7 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Mon, 21 Dec 2020 12:28:33 +0100 Subject: [PATCH] WiP! nixos: Vbox guests --- nixos-modules/default.nix | 12 +- nixos-modules/guest-vbox-linux.nix | 110 +++++++++++++++ nixos-modules/vbox-guest.dhall | 217 +++++++++++++++++++++++++++++ 3 files changed, 336 insertions(+), 3 deletions(-) create mode 100644 nixos-modules/guest-vbox-linux.nix create mode 100644 nixos-modules/vbox-guest.dhall diff --git a/nixos-modules/default.nix b/nixos-modules/default.nix index 8187db1..65adfe7 100644 --- a/nixos-modules/default.nix +++ b/nixos-modules/default.nix @@ -1,12 +1,18 @@ { flake }: let - baseModules = - [ ./genode-core.nix ./genode-init.nix ./gui ./hardware.nix ./systemd.nix ]; + baseModules = [ + ./genode-core.nix + ./genode-init.nix + ./guest-vbox-linux.nix + ./gui + ./hardware.nix + ./systemd.nix + ]; in { x86_64 = { - imports = [ baseModules ]; + imports = baseModules; nixpkgs = rec { localSystem = "x86_64-linux"; crossSystem = "x86_64-genode"; diff --git a/nixos-modules/guest-vbox-linux.nix b/nixos-modules/guest-vbox-linux.nix new file mode 100644 index 0000000..2e0de4d --- /dev/null +++ b/nixos-modules/guest-vbox-linux.nix @@ -0,0 +1,110 @@ +{ config, lib, pkgs, modulesPath, ... }: + +with lib; +let cfg = config.genode.vbox; +in { + + options.genode.vbox.guests = mkOption { + type = types.attrsOf (types.submodule ({ config, options, name, ... }: { + options = { + + bootFormat = mkOption { + default = "vdi"; + type = types.enum [ "iso" "vdi" ]; + description = "Set boot media format."; + }; + + memorySize = mkOption { + type = types.int; + default = 1536; + description = '' + The amount of RAM in MiB allocated to the VirtualBox guest. + ''; + }; + + config = mkOption { + description = '' + A specification of the desired configuration of this + guest VM, as a NixOS module. + ''; + default = { }; + type = mkOptionType { + name = "Toplevel NixOS config"; + merge = loc: defs: + (import "${modulesPath}/../lib/eval-config.nix" { + inherit (config.nixpkgs) system; + modules = { + iso = [ "${modulesPath}/installer/cd-dvd/iso-image.nix" ]; + vdi = [ + "${modulesPath}/virtualisation/virtualbox-image.nix" + { virtualbox.memorySize = cfg.guests.${name}.memorySize; } + ]; + }.${genodeConfig.guests.${name}.bootFormat} + ++ [{ system.nixos.tags = [ name ]; }] + ++ (map (x: x.value) defs); + prefix = [ "guests" name ]; + }).config; + }; + }; + + }; + })); + }; + + config = { + + genode.init.children = mapAttrs' (name: cfg: + + let + boot = { + iso = rec { + filename = "nixos.iso"; + drv = pkgs.callPackage + "${modulesPath'}/../lib/make-iso9660-image.nix" + # call the ISO utility from our nixpkgs with the package set of the guest + { + isoName = filename; + inherit (config.isoImage) volumeID contents; + }; + format = "< ISO | VDI >.ISO"; + storeRoot = "${baseNameOf drv}/iso"; + uuid = "81763434-9a51-49e8-9444-528a5a28c4bc"; + }; + vdi = rec { + filename = "nixos.vdi"; + drv = import "${modulesPath'}/../lib/make-disk-image.nix" { + inherit config lib pkgs; + diskSize = config.virtualbox.baseImageSize; + partitionTableType = "legacy"; + name = "nixos-${pkgs.stdenv.hostPlatform.system}.vdi"; + format = "vdi"; + }; + format = "< ISO | VDI >.VDI"; + storeRoot = baseNameOf drv; + uuid = '' + $(${pkgs.virtualbox}/bin/VBoxManage showmediuminfo "${boot.drv}/${boot.filename}" | awk '/^UUID:/ {print $2}')''; + }; + }.${cfg.bootFormat}; + + in { + + inputs = with pkgs.genodePackages; [ libiconv vbox5 vfs_pipe ]; + + coreROMs = [ "platform_info" ]; + + configFile = pkgs.writeText "${name}.vbox.dhall" '' + ${./vbox-guest.dhall} + { bootFilename = "${boot.filename}" + , bootFormat = "${boot.format}" + , bootPkg = "${boot.storeRoot}" + , bootUuid = ${boot.uuid} + , memorySize = ${toString cfg.memorySize} + , vmName = "${vmName}" + } + ''; + }) config.genode.vbox.guests; + + }; + +} + diff --git a/nixos-modules/vbox-guest.dhall b/nixos-modules/vbox-guest.dhall new file mode 100644 index 0000000..5bfb3d9 --- /dev/null +++ b/nixos-modules/vbox-guest.dhall @@ -0,0 +1,217 @@ +let Genode = env:DHALL_GENODE + +let Prelude = Genode.Prelude + +let XML = Prelude.XML + +let Init = Genode.Init + +let Child = Init.Child + +let Resources = Init.Resources + +let ServiceRoute = Init.ServiceRoute + +let Libc = Genode.Libc + +let VFS = Genode.VFS + +let BootFormat = < ISO | VDI > + +let Params + : Type + = { bootFilename : Text + , bootPkg : Text + , bootUuid : Text + , bootFormat : BootFormat + , memorySize : Natural + , vmName : Text + } + +let toVbox + : Params → Genode.Init.Child.Type + = λ(params : Params) → + let vboxConfig = + let hardDisks = + merge + { ISO = XML.text "" + , VDI = + XML.leaf + { name = "HardDisk" + , attributes = toMap + { uuid = "{${params.bootUuid}}" + , location = "${params.bootFilename}" + , format = "VDI" + , type = "Normal" + } + } + } + params.bootFormat + + let dvdImages = + merge + { ISO = + XML.leaf + { name = "Image" + , attributes = toMap + { uuid = "{${params.bootUuid}}" + , location = "${params.bootFilename}" + } + } + , VDI = XML.text "" + } + params.bootFormat + + let attachedDevices = + XML.element + { name = "AttachedDevice" + , attributes = + merge + { ISO = toMap + { passthrough = "false" + , type = "DVD" + , port = "3" + , device = "0" + } + , VDI = toMap + { type = "HardDisk", port = "0", device = "0" } + } + params.bootFormat + , content = + [ XML.leaf + { name = "Image" + , attributes = toMap + { uuid = "{${params.bootUuid}}" } + } + ] + } + + in '' + + + + ${XML.render hardDisks} + ${XML.render dvdImages} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${XML.render attachedDevices} + + + + + '' + + in Child.flat + Child.Attributes::{ + , binary = "virtualbox5" + , config = + ( Libc.toConfig + Libc::{ + , vfs = + let mutableVfs = + let fsNode = + [ XML.leaf + { name = "fs" + , attributes = toMap + { label = "nix/store" + , root = "${params.bootPkg}" + } + } + ] + + in merge + { ISO = + [ XML.leaf + { name = "fs" + , attributes = toMap + { writeable = "yes" } + } + , XML.element + { name = "import" + , attributes = toMap + { overwrite = "no" } + , content = fsNode + } + ] + , VDI = + [ XML.leaf + { name = "fs" + , attributes = toMap + { writeable = "yes" } + } + , XML.element + { name = "import" + , attributes = toMap + { overwrite = "no" } + , content = fsNode + } + ] + } + params.bootFormat + + in [ VFS.inline "machine.vbox" vboxConfig + , VFS.dir + "dev" + [ VFS.leaf "log" + , VFS.leaf "null" + , VFS.leaf "rtc" + ] + ] + # mutableVfs + } + ) + with attributes = toMap + { vbox_file = "machine.vbox", vm_name = params.vmName } + , resources = Resources::{ + , caps = 1024 + , ram = + Genode.units.MiB 128 + Genode.units.MiB params.memorySize + } + , romReports = [ "clipboard", "shape" ] + , routes = + [ ServiceRoute.parent "File_system" + , ServiceRoute.parent "Nic" + , ServiceRoute.parent "Gui" + , ServiceRoute.parent "Rtc" + , ServiceRoute.parent "Timer" + , ServiceRoute.parent "VM" + , ServiceRoute.parent "Report" + ] + } + +in toVbox