WiP! Systemd emulation
This commit is contained in:
parent
3e4644c337
commit
c37a12f081
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
|||
.reuse
|
||||
result
|
||||
result-*
|
||||
/tmp
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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)
|
||||
} }
|
||||
'';
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
159
nixos-modules/systemd-runner.dhall
Normal file
159
nixos-modules/systemd-runner.dhall
Normal 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
37
nixos-modules/systemd.nix
Normal 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);
|
||||
}
|
|
@ -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 = { };
|
||||
|
|
|
@ -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")
|
||||
'';
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user