2
0
Fork 0

WiP! Systemd emulation

This commit is contained in:
Ehmry - 2020-10-26 15:02:23 +01:00
parent 3e4644c337
commit c37a12f081
9 changed files with 355 additions and 168 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
.reuse
result
result-*
/tmp

View File

@ -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";

View File

@ -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)
} }
'';

View File

@ -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

View File

@ -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

View File

@ -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" ]
}
}
}
}

37
nixos-modules/systemd.nix Normal file
View File

@ -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);
}

View File

@ -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 = { };

View File

@ -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")
'';
}