diff --git a/.gitignore b/.gitignore index 903a8f2..259a0a7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .reuse result result-* +/tmp diff --git a/nixos-modules/genode-core.nix b/nixos-modules/genode-core.nix index b1d22e1..2bcf944 100644 --- a/nixos-modules/genode-core.nix +++ b/nixos-modules/genode-core.nix @@ -56,7 +56,41 @@ in { }; - config = let initInputs = unique config.genode.init.inputs; + config = let + initInputs = unique config.genode.init.inputs; + + addManifest = drv: + drv // { + manifest = + localPackages.runCommand "${drv.name}.dhall" { inherit drv; } '' + set -eu + echo -n '[' >> $out + find $drv/ -type f -printf ',{mapKey= "%f",mapValue="%p"}' >> $out + ${if builtins.elem "lib" drv.outputs then + '' + find ${drv.lib}/ -type f -printf ',{mapKey= "%f",mapValue="%p"}' >> $out'' + else + ""} + echo -n ']' >> $out + ''; + }; + + 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) + "]"; + }; + in { assertions = [{ @@ -66,58 +100,25 @@ in { }]; genode.boot.config = let - - addManifest = drv: - drv // { - manifest = - localPackages.runCommand "${drv.name}.dhall" { inherit drv; } '' - set -eu - echo -n '[' >> $out - find $drv/ -type f -printf ',{mapKey= "%f",mapValue="%p"}' >> $out - ${if builtins.elem "lib" drv.outputs then - '' - find ${drv.lib}/ -type f -printf ',{mapKey= "%f",mapValue="%p"}' >> $out'' - else - ""} - echo -n ']' >> $out - ''; - }; - - 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) + "]"; - }; - - storeManifest = mergeManifests (map addManifest initInputs); - - storeTarball = localPackages.runCommand "store" { } '' - mkdir -p $out - tar cf "$out/store.tar" --absolute-names ${toString initInputs} - ''; - manifest = mergeManifests (map addManifest - (config.genode.core.basePackages ++ [ storeTarball ] + (config.genode.core.basePackages ++ [ config.system.build.storeTarball ] ++ (with pkgs.genodePackages; [ init vfs cached_fs_rom ]))); in localPackages.runCommand "boot.dhall" { } '' cat > $out << EOF ${./store-wrapper.dhall} (${config.genode.init.config}) - $(stat --format '%s' ${storeTarball}/store.tar) - ${storeManifest} ${manifest} + $(stat --format '%s' ${config.system.build.storeTarball}/store.tar) + ${config.system.build.storeManifest} ${manifest} EOF ''; + system.build.storeManifest = mergeManifests (map addManifest initInputs); + + system.build.storeTarball = localPackages.runCommand "store" { } '' + mkdir -p $out + tar cf "$out/store.tar" --absolute-names ${toString initInputs} + ''; + system.build.initXml = pkgs.buildPackages.runCommand "init.xml" { nativeBuildInputs = with pkgs.buildPackages; [ dhall xorg.lndir ]; DHALL_GENODE = "${pkgs.genodePackages.dhallGenode}/binary.dhall"; diff --git a/nixos-modules/genode-init.nix b/nixos-modules/genode-init.nix index a695333..9c16f43 100644 --- a/nixos-modules/genode-init.nix +++ b/nixos-modules/genode-init.nix @@ -20,14 +20,19 @@ in { }; baseConfig = mkOption { - description = '' - Dhall configuration of this init instance before merging children. - ''; + description = + "Dhall configuration of this init instance before merging children."; type = types.str; default = '' let Genode = env:DHALL_GENODE - in Genode.Init::{ routes = [ Genode.Init.ServiceRoute.parent "Timer" ] } + in Genode.Init::{ + , routes = + [ Genode.Init.ServiceRoute.parent "File_system" + , Genode.Init.ServiceRoute.parent "Rtc" + , Genode.Init.ServiceRoute.parent "Timer" + ] + } ''; }; @@ -48,56 +53,19 @@ in { }; subinits = mkOption { - type = types.attrsOf (types.submodule ({ config, options, ... }: { - options = { - - config = mkOption { - description = '' - A specification of the desired configuration of this sub-init, as a NixOS module. - ''; - type = - let confPkgs = if config.pkgs == null then pkgs else config.pkgs; - in lib.mkOptionType { - name = "Toplevel NixOS config"; - merge = loc: defs: - (import (confPkgs.path + "/nixos/lib/eval-config.nix") { - inherit system; - pkgs = confPkgs; - baseModules = - import (confPkgs.path + "/nixos/modules/module-list.nix"); - inherit (confPkgs) lib; - modules = let - extraConfig = { - _file = "module at ${__curPos.file}:${ - toString __curPos.line - }"; - config = { }; - }; - in [ extraConfig ] ++ (map (x: x.value) defs); - prefix = [ "containers" name ]; - }).config; - }; + type = with types; + attrsOf (submodule { + options = { + inherit inputs; + config = mkOption { + type = types.path; + description = '' + Dhall configuration of child init. + See https://git.sr.ht/~ehmry/dhall-genode/tree/master/Init/Type + ''; + }; }; - - pkgs = mkOption { - type = types.nullOr types.attrs; - default = null; - example = literalExample "pkgs"; - description = '' - Customise which nixpkgs to use for this container. - ''; - }; - - }; - - config = mkMerge [ - (mkIf options.config.isDefined { - path = config.config.system.build.toplevel; - }) - ]; - })); - - default = { }; + }); }; }; @@ -105,16 +73,27 @@ in { config = { genode.init.inputs = with builtins; - [ pkgs.genodePackages.report_rom ] ++ concatLists - (catAttrs "inputs" (attrValues config.genode.init.children)); + [ pkgs.genodePackages.report_rom ] ++ concatLists (catAttrs "inputs" + ((attrValues config.genode.init.children) + ++ (attrValues config.genode.init.subinits))); - genode.init.config = builtins.toFile "init.dhall" '' + genode.init.config = pkgs.writeText "init.dhall" '' + let Genode = env:DHALL_GENODE let baseConfig = ${config.genode.init.baseConfig} in baseConfig with children = baseConfig.children # toMap {${ concatMapStrings (name: ", `${name}` = ${config.genode.init.children.${name}.settings}") (builtins.attrNames config.genode.init.children) + } ${ + concatMapStrings (name: '' + , `${name}` = + Genode.Init.toChild + ${config.genode.init.subinits.${name}.config} + Genode.Init.Attributes.default + '') + + (builtins.attrNames config.genode.init.subinits) } } ''; diff --git a/nixos-modules/hardware.nix b/nixos-modules/hardware.nix index 62fbf30..ce97fe2 100644 --- a/nixos-modules/hardware.nix +++ b/nixos-modules/hardware.nix @@ -85,10 +85,14 @@ with lib; , provides = [ "File_system" ] , resources = Init.Resources::{ caps = 128, ram = Genode.units.MiB 16 } , config = Init.Config::{ - , defaultPolicy = Some Init.Config.DefaultPolicy::{ - , attributes = toMap { root = "/", writeable = "yes" } - } - , content = + , policies = + [ Init.Config.Policy::{ + , service = "File_system" + , label = Init.LabelSelector.suffix "sockets" + , attributes = toMap { root = "/" } + } + ] + , content = let XML = Genode.Prelude.XML in [ XML.element diff --git a/nixos-modules/store-wrapper.dhall b/nixos-modules/store-wrapper.dhall index 8ee4661..9c551cf 100644 --- a/nixos-modules/store-wrapper.dhall +++ b/nixos-modules/store-wrapper.dhall @@ -43,8 +43,7 @@ let parentROMs = Text Init.ServiceRoute.Type ( λ(label : Text) → - { service = - { name = "ROM", label = Init.LabelSelector.Type.Last label } + { service = { name = "ROM", label = Init.LabelSelector.last label } , route = Init.Route.Type.Parent { label = Some label, diag = None Bool } } @@ -66,7 +65,6 @@ let wrapStore , Init.ServiceRoute.parent "VM" , Init.ServiceRoute.child "Timer" "timer" , Init.ServiceRoute.child "Rtc" "rtc" - , Init.ServiceRoute.child "File_system" "store_fs" ] # parentROMs [ "ld.lib.so" @@ -88,63 +86,73 @@ in λ(subinit : Init.Type) → Genode.Boot::{ , config = Init::{ , children = - [ { mapKey = "timer" - , mapValue = - Child.flat - Child.Attributes::{ - , binary = "timer_drv" - , provides = [ "Timer" ] - } - } - , { mapKey = "rtc" - , mapValue = - Child.flat - Child.Attributes::{ - , binary = "rtc_drv" - , provides = [ "Rtc" ] - , routes = [ Init.ServiceRoute.parent "IO_PORT" ] - } - } - , { mapKey = "store_fs" - , mapValue = - Child.flat - Child.Attributes::{ - , binary = "vfs" - , config = Init.Config::{ - , content = - [ XML.element - { name = "vfs" - , attributes = XML.emptyAttributes + 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 + "store_fs" + ( Child.flat + Child.Attributes::{ + , binary = "vfs" + , config = Init.Config::{ , content = - [ XML.leaf - { name = "tar" - , attributes = toMap { name = "store.tar" } + [ XML.element + { name = "vfs" + , attributes = XML.emptyAttributes + , content = + [ XML.leaf + { name = "tar" + , attributes = toMap + { name = "store.tar" } + } + ] } ] + , 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 = "/" } + } + ] } - ] - , defaultPolicy = Some Init.Config.DefaultPolicy::{ - , attributes = toMap { root = "/", writeable = "no" } - } - } - , provides = [ "File_system" ] - } - } - , { mapKey = "store_rom" - , mapValue = - Child.flat - Child.Attributes::{ - , binary = "cached_fs_rom" - , provides = [ "ROM" ] - , resources = Init.Resources::{ - , ram = storeSize + Genode.units.MiB 1 - } - , routes = - [ Init.ServiceRoute.child "File_system" "store_fs" ] - } - } - , { mapKey = "init", mapValue = wrapStore subinit storeManifest } - ] + , 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 + } + } + ) + , child "init" (wrapStore subinit storeManifest) + ] } , rom = Genode.BootModules.toRomPaths diff --git a/nixos-modules/systemd-runner.dhall b/nixos-modules/systemd-runner.dhall new file mode 100644 index 0000000..719adad --- /dev/null +++ b/nixos-modules/systemd-runner.dhall @@ -0,0 +1,159 @@ +let Genode = env:DHALL_GENODE + +let Prelude = Genode.Prelude + +let XML = Prelude.XML + +let Init = Genode.Init + +let Child = Init.Child + +let parentRoutes = + Prelude.List.map Text Init.ServiceRoute.Type Init.ServiceRoute.parent + +in λ(params : { coreutils : Text, execStart : Text }) → + Init::{ + , verbose = True + , routes = parentRoutes [ "Timer", "Rtc", "File_system" ] + , children = toMap + { vfs = + Child.flat + Child.Attributes::{ + , binary = "vfs" + , exitPropagate = True + , provides = [ "File_system" ] + , resources = Genode.Init.Resources::{ + , caps = 256 + , ram = Genode.units.MiB 8 + } + , config = Init.Config::{ + , content = + [ XML.element + { name = "vfs" + , attributes = XML.emptyAttributes + , content = + let dir = + λ(name : Text) → + λ(content : List XML.Type) → + XML.element + { name = "dir" + , content + , attributes = toMap { name } + } + + let leaf = + λ(name : Text) → + XML.leaf + { name, attributes = XML.emptyAttributes } + + in [ dir + "dev" + [ dir "pipes" [ leaf "pipe" ] + , dir + "sockets" + [ XML.leaf + { name = "fs" + , attributes = toMap + { label = "sockets" } + } + ] + , leaf "log" + , leaf "null" + , leaf "rtc" + , leaf "zero" + ] + , dir + "etc" + [ XML.element + { name = "inline" + , attributes = toMap + { name = "ExecStart" } + , content = + [ XML.text params.execStart ] + } + ] + , dir + "usr" + [ dir + "bin" + [ XML.leaf + { name = "symlink" + , attributes = toMap + { name = "env" + , target = + "${params.coreutils}/bin/env" + } + } + ] + ] + , dir "tmp" [ leaf "ram" ] + , dir + "nix" + [ dir + "store" + [ XML.leaf + { name = "fs" + , attributes = toMap + { label = "nix-store" } + } + ] + ] + ] + } + ] + , policies = + [ Init.Config.Policy::{ + , service = "File_system" + , label = Init.LabelSelector.prefix "shell" + , attributes = toMap { root = "/", writeable = "yes" } + } + ] + } + } + , shell = + Child.flat + Child.Attributes::{ + , binary = "execlineb" + , exitPropagate = True + , resources = Genode.Init.Resources::{ + , caps = 256 + , ram = Genode.units.MiB 8 + } + , config = Genode.Init.Config::{ + , content = + [ XML.leaf + { name = "libc" + , attributes = toMap + { stdin = "/dev/null" + , stdout = "/dev/log" + , stderr = "/dev/log" + , pipe = "/dev/pipes" + , rtc = "/dev/rtc" + , socket = "/dev/sockets" + } + } + , XML.element + { name = "vfs" + , attributes = XML.emptyAttributes + , content = + [ XML.leaf + { name = "fs" + , attributes = XML.emptyAttributes + } + ] + } + ] + # Prelude.List.map + Text + XML.Type + ( λ(x : Text) → + XML.leaf + { name = "arg" + , attributes = toMap { value = x } + } + ) + [ "execlineb", "/etc/ExecStart" ] + } + } + } + } diff --git a/nixos-modules/systemd.nix b/nixos-modules/systemd.nix new file mode 100644 index 0000000..2181864 --- /dev/null +++ b/nixos-modules/systemd.nix @@ -0,0 +1,37 @@ +{ config, pkgs, lib, ... }: +with lib; { + + options.systemd.services = lib.mkOption { + type = types.attrsOf (types.submodule ({ name, config, ... }: { + options.genode.enable = lib.mkOption { + type = types.bool; + default = false; + description = "Translate this systemd unit to a Genode subsystem."; + }; + })); + }; + + config.services.klogd.enable = false; + # The default is determined by checking the Linux version + # which cannot be evaluated here. + + config.genode.init.subinits = mapAttrs' (name: service: + let name' = "services." + name; + in { + name = name'; + value = { + + inputs = with pkgs; + ([ execline skalibs ] ++ (with genodePackages; [ vfs_pipe posix libc ])); + + config = pkgs.writeText "${name'}.dhall" '' + ${./systemd-runner.dhall} { + , coreutils = "${pkgs.coreutils}" + , execStart = "${toString service.serviceConfig.ExecStart}" + } + ''; + + }; + }) (filterAttrs (name: service: service.genode.enable) + config.systemd.services); +} diff --git a/packages/genodelabs/targets.nix b/packages/genodelabs/targets.nix index 3d4e713..bc4344d 100644 --- a/packages/genodelabs/targets.nix +++ b/packages/genodelabs/targets.nix @@ -91,6 +91,7 @@ in { vfs_import.patches = [ ./vfs_import.patch ]; vfs_jitterentropy.portInputs = [ jitterentropy libc ]; vfs_lwip.portInputs = [ lwip ]; + vfs_pipe = { }; vfs_ttf.portInputs = [ libc stb ]; virtdev_rom = { }; diff --git a/tests/lighttpd.nix b/tests/lighttpd.nix index 24a3565..fbd6f7c 100644 --- a/tests/lighttpd.nix +++ b/tests/lighttpd.nix @@ -1,20 +1,17 @@ { name = "lighttpd"; nodes = { - webserver = { - imports = [ ../nixos-modules/hardware.nix ]; + webserver = { config, pkgs, ... }: { + imports = [ ../nixos-modules/hardware.nix ../nixos-modules/systemd.nix ]; services.lighttpd.enable = true; networking.interfaces.eth1.genode.driver = "virtio"; networking.interfaces.eth1.genode.stack = "lwip"; - }; - client = { - imports = [ ../nixos-modules/hardware.nix ]; - networking.interfaces.eth1.genode.driver = "virtio"; - networking.interfaces.eth1.genode.stack = "lwip"; + systemd.services.lighttpd.genode.enable = true; + genode.init.subinits."services.lighttpd".inputs = [ pkgs.lighttpd ]; }; }; testScript = '' start_all() - client.wait_until_serial_output("forever") + webserver.wait_until_serial_output("forever") ''; }