Genode Packages collection https://git.sr.ht/~ehmry/genodepkgs/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

genode-core.nix 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. { config, pkgs, lib, modulesPath, ... }:
  2. with lib;
  3. let
  4. localPackages = pkgs.buildPackages;
  5. coreROMs = mkOption {
  6. type = with types; listOf str;
  7. default = [ ];
  8. description = ''
  9. List of label suffixes that when matched against
  10. ROM requests shall be forwared to the core.
  11. '';
  12. example = [ "platform_info" ];
  13. };
  14. inputs = mkOption {
  15. description = "List of packages to build a ROM store with.";
  16. default = [ ];
  17. type = types.listOf types.package;
  18. };
  19. in {
  20. options.genode = {
  21. core = {
  22. prefix = mkOption {
  23. type = types.str;
  24. example = "hw-pc-";
  25. description = "String prefix signifying the Genode core in use.";
  26. };
  27. supportedSystems = mkOption {
  28. type = types.listOf types.str;
  29. example = [ "i686-genode" "x86_64-genode" ];
  30. description = "Hardware supported by this core.";
  31. };
  32. basePackages = mkOption {
  33. type = types.listOf types.package;
  34. description = ''
  35. List of packages to make availabe before the Nix store is ready.
  36. These are baked into <option>config.genode.core.image</option>.
  37. '';
  38. };
  39. children = mkOption {
  40. type = with types;
  41. attrsOf (submodule {
  42. options = {
  43. inherit coreROMs inputs;
  44. configFile = mkOption {
  45. type = types.path;
  46. description = ''
  47. Set of children at the lowest init level, these children must not
  48. have any dependency on a Nix store.
  49. Configuration format is a Dhall configuration of type
  50. <literal>Genode.Init.Child.Type</literal>.
  51. See https://git.sr.ht/~ehmry/dhall-genode/tree/master/Init/Child/Type
  52. '';
  53. };
  54. };
  55. });
  56. };
  57. };
  58. boot = {
  59. configFile = mkOption {
  60. type = types.path;
  61. description = ''
  62. Dhall boot configuration. See
  63. https://git.sr.ht/~ehmry/dhall-genode/tree/master/Boot/package.dhall
  64. '';
  65. };
  66. image = mkOption {
  67. type = types.path;
  68. description =
  69. "Boot image containing the base component binaries and configuration.";
  70. };
  71. romModules = mkOption {
  72. type = types.attrsOf types.path;
  73. default = { };
  74. description = "Attr set of initial ROM modules";
  75. };
  76. storeFsUuid = mkOption {
  77. type = types.str;
  78. default = import ./store-fs-uuid;
  79. description = "Custom partition type of the nix-store file-system.";
  80. };
  81. storePartUuid = mkOption {
  82. type = types.str;
  83. default = import ./partition-type;
  84. description = "Custom partition type of the nix-store file-system.";
  85. };
  86. storeBackend = mkOption {
  87. type = types.enum [ "tarball" "usb" ]; # "parent"?
  88. default = "tarball";
  89. description = ''
  90. Backend for the initial /nix/store file-system.
  91. <variablelist>
  92. <varlistentry>
  93. <term><literal>tarball</literal></term>
  94. <listitem>
  95. <para>
  96. An in-memory tarball.
  97. </para>
  98. </listitem>
  99. </varlistentry>
  100. <varlistentry>
  101. <term><literal>usb</literal></term>
  102. <listitem>
  103. <para>
  104. An EXT2 file-system backed by USB storage.
  105. </para>
  106. </listitem>
  107. </varlistentry>
  108. </variablelist>
  109. '';
  110. };
  111. storePaths = mkOption {
  112. type = with types; listOf package;
  113. description = ''
  114. Derivations to be included in the Nix store in the generated boot image.
  115. '';
  116. };
  117. };
  118. };
  119. config = let
  120. addManifest = drv:
  121. drv // {
  122. manifest =
  123. localPackages.runCommand "${drv.name}.dhall" { inherit drv; } ''
  124. set -eu
  125. echo -n '[' >> $out
  126. find $drv/ -type f -printf ',{mapKey= "%f",mapValue="%p"}' >> $out
  127. ${if builtins.elem "lib" drv.outputs then
  128. ''
  129. find ${drv.lib}/ -type f -printf ',{mapKey= "%f",mapValue="%p"}' >> $out''
  130. else
  131. ""}
  132. echo -n ']' >> $out
  133. '';
  134. };
  135. mergeManifests = inputs:
  136. with builtins;
  137. let
  138. f = head: input:
  139. if hasAttr "manifest" input then
  140. ''
  141. ${head}, { mapKey = "${
  142. lib.getName input
  143. }", mapValue = ${input.manifest} }''
  144. else
  145. abort "${input.pname} does not have a manifest";
  146. in (foldl' f "[" inputs) + "]";
  147. romDirectories = filterAttrs (_: value: value != null) (mapAttrs
  148. (name: value:
  149. if value.inputs == [ ] then
  150. null
  151. else
  152. pkgs.symlinkJoin {
  153. name = "${name}-rom";
  154. paths = value.inputs;
  155. }) config.genode.init.children);
  156. in {
  157. assertions = [{
  158. assertion = builtins.any (s: s == config.nixpkgs.system)
  159. config.genode.core.supportedSystems;
  160. message = "invalid Genode core for this system";
  161. }];
  162. genode.core.basePackages =
  163. lib.optional (config.genode.boot.storeBackend == "usb")
  164. pkgs.genodePackages.part_block;
  165. genode.core.children =
  166. # Component to steer the store_fs to a specific partition
  167. (if config.genode.boot.storeBackend == "usb" then {
  168. part_block.configFile = builtins.toFile "part_block.dhall" ''
  169. let Genode = env:DHALL_GENODE
  170. let Init = Genode.Init
  171. in Init.Child.flat
  172. Init.Child.Attributes::{
  173. , binary = "part_block"
  174. , resources = Init.Resources::{ ram = Genode.units.MiB 8 }
  175. , config = Init.Config::{
  176. , attributes = toMap { ignore_mbr = "yes" }
  177. , policies =
  178. [ Init.Config.Policy::{
  179. , service = "Block"
  180. , label = Init.LabelSelector.prefix "store_fs"
  181. , attributes = toMap
  182. { partition = "1"
  183. , writeable = "yes"
  184. , TODO = "select by partition UUID"
  185. }
  186. }
  187. ]
  188. }
  189. }
  190. '';
  191. } else
  192. { }) // {
  193. store_fs.configFile = let
  194. storeVfsConfig = {
  195. tarball = ''
  196. VFS.vfs [ VFS.leafAttrs "tar" (toMap { name = "${config.system.build.tarball.fileName}.tar" }) ]
  197. '';
  198. usb = ''
  199. VFS.vfs [ VFS.leafAttrs "rump" (toMap { fs = "ext2fs", ram="12M" }) ]
  200. '';
  201. }.${config.genode.boot.storeBackend};
  202. storeResources = {
  203. tarball = "Init.Resources.default";
  204. usb = "Init.Resources::{ caps = 256, ram = Genode.units.MiB 16 }";
  205. }.${config.genode.boot.storeBackend};
  206. in builtins.toFile "store_fs.dhall" ''
  207. let Genode = env:DHALL_GENODE
  208. let Init = Genode.Init
  209. let VFS = Genode.VFS
  210. in Init.Child.flat
  211. Init.Child.Attributes::{
  212. , binary = "vfs"
  213. , resources = ${storeResources}
  214. , config = Init.Config::{
  215. , content = [ ${storeVfsConfig} ]
  216. , policies =
  217. [ Init.Config.Policy::{
  218. , service = "File_system"
  219. , label = Init.LabelSelector.suffix "nix-store"
  220. , attributes = toMap { root = "/nix/store" }
  221. }
  222. , Init.Config.Policy::{
  223. , service = "File_system"
  224. , label = Init.LabelSelector.prefix "store_rom"
  225. , attributes = toMap { root = "/" }
  226. }
  227. ]
  228. }
  229. }
  230. '';
  231. };
  232. genode.boot.configFile = let
  233. tarball =
  234. "${config.system.build.tarball}/tarball/${config.system.build.tarball.fileName}.tar";
  235. storeBackendInputs = {
  236. tarball = [ config.system.build.tarball ];
  237. usb = [ pkgs.genodePackages.rump ];
  238. }.${config.genode.boot.storeBackend};
  239. coreInputs = with builtins;
  240. concatMap (getAttr "inputs") (attrValues config.genode.core.children);
  241. manifest =
  242. # Manifests are Dhall metadata to be attached to every
  243. # package to be used for dynamically buildings enviroments
  244. # using Dhall expressions. Probably not worth pursuing.
  245. pkgs.writeText "manifest.dhall" (mergeManifests (map addManifest
  246. (with pkgs.genodePackages;
  247. config.genode.core.basePackages ++ storeBackendInputs
  248. ++ [ init cached_fs_rom jitter_sponge report_rom vfs ]
  249. ++ coreInputs))
  250. + lib.optionalString (config.genode.boot.romModules != { }) ''
  251. # [ { mapKey = "romModules", mapValue = [ ${
  252. toString (mapAttrsToList
  253. (k: v: '', { mapKey = "${k}", mapValue = "${v}" }'')
  254. config.genode.boot.romModules)
  255. }] } ]'');
  256. storeRomPolicies = mapAttrsToList
  257. (name: value: '', { mapKey = "${name}", mapValue = "${value}" }'')
  258. romDirectories;
  259. extraRoutes = lib.concatStringsSep ", " (lib.lists.flatten
  260. (lib.mapAttrsToList (name: value:
  261. map (suffix: ''
  262. { service =
  263. { name = "ROM"
  264. , label =
  265. Genode.Init.LabelSelector.Type.Partial
  266. { prefix = Some "nixos -> ${name}", suffix = Some "${suffix}" }
  267. }
  268. , route = Genode.Init.Route.parentLabel "${suffix}"
  269. }
  270. '') value.coreROMs) config.genode.init.children));
  271. extraCoreChildren = "[ ${
  272. toString (lib.mapAttrsToList (name: value:
  273. '', { mapKey = "${name}", mapValue = ${value.configFile} }'')
  274. config.genode.core.children)
  275. } ]";
  276. in localPackages.runCommand "boot.dhall" { } ''
  277. cat > $out << EOF
  278. let Genode = env:DHALL_GENODE in
  279. let VFS = Genode.VFS
  280. let XML = Genode.Prelude.XML
  281. in
  282. ${./store-wrapper.dhall}
  283. { extraCoreChildren = ${extraCoreChildren}
  284. , subinit = ${config.genode.init.configFile}
  285. , storeSize = $(stat --format '%s' ${tarball})
  286. , storeRomPolicies = [${
  287. toString storeRomPolicies
  288. } ] : Genode.Prelude.Map.Type Text Text
  289. , routes = [${extraRoutes} ] : List Genode.Init.ServiceRoute.Type
  290. , bootManifest = ${manifest}
  291. }
  292. EOF
  293. '';
  294. genode.boot.storePaths = with builtins;
  295. [ config.genode.init.configFile ] ++ (attrValues romDirectories);
  296. # Create the tarball of the store to live in core ROM
  297. system.build.tarball =
  298. pkgs.callPackage "${modulesPath}/../lib/make-system-tarball.nix" {
  299. contents = [ ];
  300. storeContents = let
  301. romDirs = mapAttrsToList (name: object: {
  302. symlink = "rom/${name}";
  303. inherit object;
  304. }) romDirectories;
  305. configFiles = mapAttrsToList (name: child: {
  306. symlink = "config/${name}.dhall";
  307. object = child.configFile;
  308. }) config.genode.init.children;
  309. in romDirs ++ configFiles;
  310. compressCommand = "cat";
  311. compressionExtension = "";
  312. };
  313. system.build.initXml = pkgs.buildPackages.runCommand "init.xml" {
  314. nativeBuildInputs = with pkgs.buildPackages; [ dhall xorg.lndir libxml2 ];
  315. DHALL_GENODE = "${pkgs.genodePackages.dhallGenode}/binary.dhall";
  316. } ''
  317. export XDG_CACHE_HOME=$NIX_BUILD_TOP
  318. lndir -silent \
  319. ${pkgs.genodePackages.dhallGenode}/.cache \
  320. $XDG_CACHE_HOME
  321. dhall text <<< "(env:DHALL_GENODE).Init.render (${config.genode.boot.configFile}).config" > $out
  322. xmllint --noout $out
  323. '';
  324. system.build.bootDriveImage = let
  325. espImage = import ./lib/make-esp-fs.nix { inherit config pkgs; };
  326. storeFsImage =
  327. pkgs.callPackage ./lib/make-ext2-fs.nix { inherit config pkgs; };
  328. bootDriveImage = import ./lib/make-bootable-image.nix {
  329. inherit config pkgs espImage storeFsImage;
  330. };
  331. in bootDriveImage;
  332. # virtualisation.useEFIBoot = config.genode.boot.storeBackend == "usb";
  333. virtualisation.qemu.options =
  334. lib.optionals (config.genode.boot.storeBackend == "usb") [
  335. "-bios ${pkgs.buildPackages.OVMF.fd}/FV/OVMF.fd"
  336. "-drive id=usbdisk,file=${config.system.build.bootDriveImage},if=none,readonly"
  337. "-usb"
  338. "-device usb-storage,drive=usbdisk"
  339. ];
  340. };
  341. }