Emery Hemingway
8379dccf12
Retrieve ROMs in the common case by full store path. This reduces the need for route policies for driving relative requests into absolute package paths. Making library requests by absolute path required libraries to be stored in the core image as such, and it follows that program binaries should be handled in the same way. This makes requests to core and to a file-system store more consistent, and makes dependency detection more robust.
447 lines
15 KiB
Nix
447 lines
15 KiB
Nix
{ config, pkgs, lib, modulesPath, ... }:
|
|
|
|
with lib;
|
|
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;
|
|
description = ''
|
|
List of packages to make availabe before the Nix store is ready.
|
|
These are baked into <option>config.genode.core.image</option>.
|
|
'';
|
|
};
|
|
|
|
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
|
|
<literal>Genode.Init.Child.Type</literal>.
|
|
See https://git.sr.ht/~ehmry/dhall-genode/tree/master/Init/Child/Type
|
|
'';
|
|
};
|
|
};
|
|
});
|
|
};
|
|
|
|
};
|
|
|
|
boot = {
|
|
|
|
configFile = mkOption {
|
|
type = types.path;
|
|
description = ''
|
|
Dhall boot configuration. See
|
|
https://git.sr.ht/~ehmry/dhall-genode/tree/master/Boot/package.dhall
|
|
'';
|
|
};
|
|
|
|
image = mkOption {
|
|
type = types.path;
|
|
description =
|
|
"Boot image containing the base component binaries and configuration.";
|
|
};
|
|
|
|
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 [ "fs" "memory" ]; # "parent"?
|
|
default = "memory";
|
|
description = ''
|
|
Backend for the initial /nix/store file-system.
|
|
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term>
|
|
<literal>fs</literal>
|
|
</term>
|
|
<listitem>
|
|
<para>Store backed by a File_system session.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>
|
|
<literal>tarball</literal>
|
|
</term>
|
|
<listitem>
|
|
<para>An in-memory tarball.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
'';
|
|
};
|
|
|
|
storePaths = mkOption {
|
|
type = with types; listOf package;
|
|
description = ''
|
|
Derivations to be included in the Nix store in the generated boot image.
|
|
'';
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
config = let
|
|
|
|
addManifest = drv:
|
|
drv // {
|
|
manifest =
|
|
localPackages.runCommand "${drv.name}.dhall" { inherit drv; } ''
|
|
set -eu
|
|
echo -n '[' >> $out
|
|
find $drv/ -type f -printf ',{mapKey= "%p",mapValue="%p"}' >> $out
|
|
${if builtins.elem "lib" drv.outputs then
|
|
''
|
|
find ${drv.lib}/ -type f -printf ',{mapKey= "%p",mapValue="%p"}' >> $out''
|
|
else
|
|
""}
|
|
echo -n ']' >> $out
|
|
'';
|
|
};
|
|
|
|
mergeManifests = 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:
|
|
if value.inputs == [ ] then
|
|
null
|
|
else
|
|
pkgs.symlinkJoin {
|
|
name = "${name}-rom";
|
|
paths = value.inputs;
|
|
}) config.genode.init.children);
|
|
|
|
tarball =
|
|
"${config.system.build.tarball}/tarball/${config.system.build.tarball.fileName}.tar";
|
|
in {
|
|
|
|
assertions = [{
|
|
assertion = builtins.any (s:
|
|
s == config.nixpkgs.system || s == config.nixpkgs.crossSystem.system)
|
|
config.genode.core.supportedSystems;
|
|
message = "invalid Genode core for this system";
|
|
}];
|
|
|
|
genode.core.basePackages =
|
|
lib.optional (config.genode.boot.storeBackend != "memory")
|
|
pkgs.genodePackages.part_block;
|
|
|
|
genode.boot.romModules = let
|
|
getBin = name: "${builtins.getAttr name pkgs.genodePackages}/bin/${name}";
|
|
in {
|
|
cached_fs_rom = getBin "cached_fs_rom";
|
|
init = "${pkgs.genodePackages.init}/bin/init";
|
|
jitter_sponge = "${pkgs.genodePackages.jitter_sponge}/bin/jitter_sponge";
|
|
report_rom = "${pkgs.genodePackages.report_rom}/bin/report_rom";
|
|
rtc_drv = "${pkgs.genodePackages.rtc_drv}/bin/rtc_drv";
|
|
vfs = "${pkgs.genodePackages.vfs}/bin/vfs";
|
|
"vfs.lib.so" = "${pkgs.genodePackages.vfs.lib}/lib/vfs.lib.so";
|
|
};
|
|
|
|
genode.core.children =
|
|
# Component to steer the main fs to a specific partition
|
|
(if config.genode.boot.storeBackend != "memory" then {
|
|
part_block.configFile = pkgs.writeText "part_block.dhall" ''
|
|
let Genode = env:DHALL_GENODE
|
|
|
|
let Init = Genode.Init
|
|
|
|
in Init.Child.flat
|
|
Init.Child.Attributes::{
|
|
, binary = "${pkgs.genodePackages.part_block}/bin/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 "fs"
|
|
, attributes = toMap
|
|
{ partition = "${
|
|
toString config.fileSystems."/".block.partition
|
|
}"
|
|
, writeable = "yes"
|
|
, TODO = "select by partition UUID"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
'';
|
|
} else
|
|
{ }) // {
|
|
fs.configFile = let
|
|
vfsConfig = if config.genode.boot.storeBackend == "memory" then ''
|
|
VFS.vfs
|
|
[ VFS.leafAttrs
|
|
"tar"
|
|
(toMap { name = "${tarball}" })
|
|
]
|
|
'' else
|
|
let
|
|
rumpExt2 = ''
|
|
VFS.vfs
|
|
[ VFS.leafAttrs
|
|
"plugin"
|
|
( toMap
|
|
{ load = "${pkgs.genodePackages.rump}/lib/vfs_rump.lib.so"
|
|
, fs = "ext2fs"
|
|
, ram = "12M"
|
|
}
|
|
)
|
|
]
|
|
'';
|
|
in {
|
|
ahci = rumpExt2;
|
|
usb = rumpExt2;
|
|
}.${config.fileSystems."/".block.driver};
|
|
|
|
storeResources = let
|
|
rumpExt2 =
|
|
"Init.Resources::{ caps = 256, ram = Genode.units.MiB 16 }";
|
|
in {
|
|
fs = rumpExt2;
|
|
memory = "Init.Resources.default";
|
|
}.${config.genode.boot.storeBackend};
|
|
|
|
persistencePolicies = lib.mapAttrsToList (name: _: ''
|
|
, Init.Config.Policy::{
|
|
, service = "File_system"
|
|
, label = Genode.Init.LabelSelector.prefix
|
|
"nixos -> ${name}"
|
|
, attributes = toMap { root = "/services", writeable = "yes" }
|
|
}
|
|
'') (filterAttrs (_: child: child.fsPersistence)
|
|
config.genode.init.children);
|
|
|
|
fsPolicies = map (name: ''
|
|
, Init.Config.Policy::{
|
|
, service = "File_system"
|
|
, label =
|
|
Init.LabelSelector.Type.Partial
|
|
{ prefix = Some "nixos -> ${name}", suffix = Some "nix-store" }
|
|
, attributes = toMap { root = "/nix/store", writeable = "no" }
|
|
}
|
|
'') (builtins.attrNames config.genode.init.children);
|
|
|
|
in pkgs.writeText "fs.dhall" ''
|
|
let Genode = env:DHALL_GENODE
|
|
|
|
let Init = Genode.Init
|
|
|
|
let VFS = Genode.VFS
|
|
|
|
let persistencePolicies = [ ${
|
|
toString persistencePolicies
|
|
} ] : List Init.Config.Policy.Type
|
|
|
|
let fsPolicies = [ ${
|
|
toString fsPolicies
|
|
} ] : List Init.Config.Policy.Type
|
|
|
|
in Init.Child.flat
|
|
Init.Child.Attributes::{
|
|
, binary = "vfs"
|
|
, resources = ${storeResources}
|
|
, provides = [ "File_system" ]
|
|
, config = Init.Config::{
|
|
, content = [ ${vfsConfig} ]
|
|
, policies =
|
|
[ Init.Config.Policy::{
|
|
, service = "File_system"
|
|
, label = Init.LabelSelector.prefix "store_rom"
|
|
, attributes = toMap { root = "/" }
|
|
}
|
|
] # persistencePolicies # fsPolicies
|
|
}
|
|
}
|
|
'';
|
|
};
|
|
|
|
genode.boot.configFile = let
|
|
|
|
storeBackendInputs = {
|
|
fs = [ pkgs.genodePackages.rump ];
|
|
memory = [ config.system.build.tarball ];
|
|
}.${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
|
|
++ [ 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}" }'')
|
|
romDirectories;
|
|
|
|
extraRoutes = lib.concatStringsSep ", " (lib.lists.flatten
|
|
(lib.mapAttrsToList (name: value:
|
|
map (suffix: ''
|
|
{ service =
|
|
{ name = "ROM"
|
|
, label =
|
|
Genode.Init.LabelSelector.Type.Partial
|
|
{ prefix = Some "nixos -> ${name}", suffix = Some "${suffix}" }
|
|
}
|
|
, route = Genode.Init.Route.parent (Some "${suffix}")
|
|
}
|
|
'') 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}
|
|
{ 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" {
|
|
contents = [ ];
|
|
storeContents = let
|
|
romDirs = mapAttrsToList (name: object: {
|
|
symlink = "rom/${name}";
|
|
inherit object;
|
|
}) romDirectories;
|
|
configFiles = mapAttrsToList (name: child: {
|
|
symlink = "config/${name}.dhall";
|
|
object = child.configFile;
|
|
}) config.genode.init.children;
|
|
in romDirs ++ configFiles;
|
|
compressCommand = "cat";
|
|
compressionExtension = "";
|
|
};
|
|
|
|
system.build.initXml = pkgs.buildPackages.runCommand "init.xml" {
|
|
nativeBuildInputs = with pkgs.buildPackages; [ dhall xorg.lndir libxml2 ];
|
|
DHALL_GENODE = "${pkgs.genodePackages.dhallGenode}/binary.dhall";
|
|
} ''
|
|
export XDG_CACHE_HOME=$NIX_BUILD_TOP
|
|
lndir -silent \
|
|
${pkgs.genodePackages.dhallGenode}/.cache \
|
|
$XDG_CACHE_HOME
|
|
dhall text <<< "(env:DHALL_GENODE).Init.render (${config.genode.boot.configFile}).config" > $out
|
|
xmllint --noout $out
|
|
'';
|
|
|
|
virtualisation.diskImage = 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 lib.mkIf (config.genode.boot.storeBackend != "memory") bootDriveImage;
|
|
|
|
virtualisation.useBootLoader = config.genode.boot.storeBackend != "memory";
|
|
|
|
virtualisation.qemu.options =
|
|
let blockCommon = [ "-bios ${pkgs.buildPackages.buildPackages.OVMF.fd}/FV/OVMF.fd" ];
|
|
in {
|
|
fs = blockCommon;
|
|
memory = [ ];
|
|
}.${config.genode.boot.storeBackend};
|
|
|
|
};
|
|
|
|
}
|