xeus-cling: fix improper linking with LLVM (#351130)
[NixPkgs.git] / nixos / modules / virtualisation / xen-dom0.nix
blob2911c0c1d97c4b77fa13651f825c6fd4a05dab9b
1 # Xen Project Hypervisor (Dom0) support.
4   config,
5   lib,
6   pkgs,
7   ...
8 }:
10 let
11   inherit (builtins) readFile;
12   inherit (lib.modules) mkRemovedOptionModule mkRenamedOptionModule mkIf;
13   inherit (lib.options)
14     mkOption
15     mkEnableOption
16     literalExpression
17     mkPackageOption
18     ;
19   inherit (lib.types)
20     listOf
21     str
22     ints
23     lines
24     enum
25     path
26     submodule
27     addCheck
28     float
29     bool
30     int
31     nullOr
32     ;
33   inherit (lib.lists) optional optionals;
34   inherit (lib.strings) hasSuffix optionalString;
35   inherit (lib.meta) getExe;
36   inherit (lib.attrsets) optionalAttrs;
37   inherit (lib.trivial) boolToString;
38   inherit (lib.teams.xen) members;
40   cfg = config.virtualisation.xen;
42   xenBootBuilder = pkgs.writeShellApplication {
43     name = "xenBootBuilder";
44     runtimeInputs =
45       (with pkgs; [
46         binutils
47         coreutils
48         findutils
49         gawk
50         gnugrep
51         gnused
52         jq
53       ])
54       ++ optionals (cfg.efi.bootBuilderVerbosity == "info") (
55         with pkgs;
56         [
57           bat
58           diffutils
59         ]
60       );
61     runtimeEnv = {
62       efiMountPoint = config.boot.loader.efi.efiSysMountPoint;
63     };
65     # We disable SC2016 because we don't want to expand the regexes in the sed commands.
66     excludeShellChecks = [ "SC2016" ];
68     text = readFile ./xen-boot-builder.sh;
69   };
73   imports = [
74     (mkRemovedOptionModule
75       [
76         "virtualisation"
77         "xen"
78         "bridge"
79         "name"
80       ]
81       "The Xen Network Bridge options are currently unavailable. Please set up your own bridge manually."
82     )
83     (mkRemovedOptionModule
84       [
85         "virtualisation"
86         "xen"
87         "bridge"
88         "address"
89       ]
90       "The Xen Network Bridge options are currently unavailable. Please set up your own bridge manually."
91     )
92     (mkRemovedOptionModule
93       [
94         "virtualisation"
95         "xen"
96         "bridge"
97         "prefixLength"
98       ]
99       "The Xen Network Bridge options are currently unavailable. Please set up your own bridge manually."
100     )
101     (mkRemovedOptionModule
102       [
103         "virtualisation"
104         "xen"
105         "bridge"
106         "forwardDns"
107       ]
108       "The Xen Network Bridge options are currently unavailable. Please set up your own bridge manually."
109     )
110     (mkRenamedOptionModule
111       [
112         "virtualisation"
113         "xen"
114         "qemu-package"
115       ]
116       [
117         "virtualisation"
118         "xen"
119         "qemu"
120         "package"
121       ]
122     )
123     (mkRenamedOptionModule
124       [
125         "virtualisation"
126         "xen"
127         "package-qemu"
128       ]
129       [
130         "virtualisation"
131         "xen"
132         "qemu"
133         "package"
134       ]
135     )
136     (mkRenamedOptionModule
137       [
138         "virtualisation"
139         "xen"
140         "stored"
141       ]
142       [
143         "virtualisation"
144         "xen"
145         "store"
146         "path"
147       ]
148     )
149   ];
151   ## Interface ##
153   options.virtualisation.xen = {
155     enable = mkEnableOption "the Xen Project Hypervisor, a virtualisation technology defined as a *type-1 hypervisor*, which allows multiple virtual machines, known as *domains*, to run concurrently on the physical machine. NixOS runs as the privileged *Domain 0*. This option requires a reboot into a Xen kernel to take effect";
157     debug = mkEnableOption "Xen debug features for Domain 0. This option enables some hidden debugging tests and features, and should not be used in production";
159     trace = mkOption {
160       type = bool;
161       default = cfg.debug;
162       defaultText = literalExpression "false";
163       example = true;
164       description = "Whether to enable Xen debug tracing and logging for Domain 0.";
165     };
167     package = mkPackageOption pkgs "Xen Hypervisor" { default = [ "xen" ]; };
169     qemu = {
170       package = mkPackageOption pkgs "QEMU (with Xen Hypervisor support)" {
171         default = [ "qemu_xen" ];
172       };
173       pidFile = mkOption {
174         type = path;
175         default = "/run/xen/qemu-dom0.pid";
176         example = "/var/run/xen/qemu-dom0.pid";
177         description = "Path to the QEMU PID file.";
178       };
179     };
181     bootParams = mkOption {
182       default = [ ];
183       example = ''
184         [
185           "iommu=force:true,qinval:true,debug:true"
186           "noreboot=true"
187           "vga=ask"
188         ]
189       '';
190       type = listOf str;
191       description = ''
192         Xen Command Line parameters passed to Domain 0 at boot time.
193         Note: these are different from `boot.kernelParams`. See
194         the [Xen documentation](https://xenbits.xenproject.org/docs/unstable/misc/xen-command-line.html) for more information.
195       '';
196     };
198     efi = {
199       bootBuilderVerbosity = mkOption {
200         type = enum [
201           "default"
202           "info"
203           "debug"
204           "quiet"
205         ];
206         default = "default";
207         example = "info";
208         description = ''
209           The EFI boot entry builder script should be called with exactly one of the following arguments in order to specify its verbosity:
211           - `quiet` supresses all messages.
213           - `default` adds a simple "Installing Xen Project Hypervisor boot entries...done." message to the script.
215           - `info` is the same as `default`, but it also prints a diff with information on which generations were altered.
216             - This option adds two extra dependencies to the script: `diffutils` and `bat`.
218           - `debug` prints information messages for every single step of the script.
220           This option does not alter the actual functionality of the script, just the number of messages printed when rebuilding the system.
221         '';
222       };
224       path = mkOption {
225         type = path;
226         default = "${cfg.package.boot}/${cfg.package.efi}";
227         defaultText = literalExpression "\${config.virtualisation.xen.package.boot}/\${config.virtualisation.xen.package.efi}";
228         example = literalExpression "\${config.virtualisation.xen.package}/boot/efi/efi/nixos/xen-\${config.virtualisation.xen.package.version}.efi";
229         description = ''
230           Path to xen.efi. `pkgs.xen` is patched to install the xen.efi file
231           on `$boot/boot/xen.efi`, but an unpatched Xen build may install it
232           somewhere else, such as `$out/boot/efi/efi/nixos/xen.efi`. Unless
233           you're building your own Xen derivation, you should leave this
234           option as the default value.
235         '';
236       };
237     };
239     dom0Resources = {
240       maxVCPUs = mkOption {
241         default = 0;
242         example = 4;
243         type = ints.unsigned;
244         description = ''
245           Amount of virtual CPU cores allocated to Domain 0 on boot.
246           If set to 0, all cores are assigned to Domain 0, and
247           unprivileged domains will compete with Domain 0 for CPU time.
248         '';
249       };
251       memory = mkOption {
252         default = 0;
253         example = 512;
254         type = ints.unsigned;
255         description = ''
256           Amount of memory (in MiB) allocated to Domain 0 on boot.
257           If set to 0, all memory is assigned to Domain 0, and
258           unprivileged domains will compete with Domain 0 for free RAM.
259         '';
260       };
262       maxMemory = mkOption {
263         default = cfg.dom0Resources.memory;
264         defaultText = literalExpression "config.virtualisation.xen.dom0Resources.memory";
265         example = 1024;
266         type = ints.unsigned;
267         description = ''
268           Maximum amount of memory (in MiB) that Domain 0 can
269           dynamically allocate to itself. Does nothing if set
270           to the same amount as virtualisation.xen.memory, or
271           if that option is set to 0.
272         '';
273       };
274     };
276     domains = {
277       extraConfig = mkOption {
278         type = lines;
279         default = "";
280         example = ''
281           XENDOMAINS_SAVE=/persist/xen/save
282           XENDOMAINS_RESTORE=false
283           XENDOMAINS_CREATE_USLEEP=10000000
284         '';
285         description = ''
286           Options defined here will override the defaults for xendomains.
287           The default options can be seen in the file included from
288           /etc/default/xendomains.
289         '';
290       };
291     };
293     store = {
294       path = mkOption {
295         type = path;
296         default = "${cfg.package}/bin/oxenstored";
297         defaultText = literalExpression "\${config.virtualisation.xen.package}/bin/oxenstored";
298         example = literalExpression "\${config.virtualisation.xen.package}/bin/xenstored";
299         description = ''
300           Path to the Xen Store Daemon. This option is useful to
301           switch between the legacy C-based Xen Store Daemon, and
302           the newer OCaml-based Xen Store Daemon, `oxenstored`.
303         '';
304       };
305       type = mkOption {
306         type = enum [
307           "c"
308           "ocaml"
309         ];
310         default = if (hasSuffix "oxenstored" cfg.store.path) then "ocaml" else "c";
311         internal = true;
312         readOnly = true;
313         description = "Helper internal option that determines the type of the Xen Store Daemon based on cfg.store.path.";
314       };
315       settings = mkOption {
316         default = { };
317         example = {
318           enableMerge = false;
319           quota.maxWatchEvents = 2048;
320           quota.enable = true;
321           conflict.maxHistorySeconds = 0.12;
322           conflict.burstLimit = 15.0;
323           xenstored.log.file = "/dev/null";
324           xenstored.log.level = "info";
325         };
326         description = ''
327           The OCaml-based Xen Store Daemon configuration. This
328           option does nothing with the C-based `xenstored`.
329         '';
330         type = submodule {
331           options = {
332             pidFile = mkOption {
333               default = "/run/xen/xenstored.pid";
334               example = "/var/run/xen/xenstored.pid";
335               type = path;
336               description = "Path to the Xen Store Daemon PID file.";
337             };
338             testEAGAIN = mkOption {
339               default = cfg.debug;
340               defaultText = literalExpression "config.virtualisation.xen.debug";
341               example = true;
342               type = bool;
343               visible = false;
344               description = "Randomly fail a transaction with EAGAIN. This option is used for debugging purposes only.";
345             };
346             enableMerge = mkOption {
347               default = true;
348               example = false;
349               type = bool;
350               description = "Whether to enable transaction merge support.";
351             };
352             conflict = {
353               burstLimit = mkOption {
354                 default = 5.0;
355                 example = 15.0;
356                 type = addCheck (
357                   float
358                   // {
359                     name = "nonnegativeFloat";
360                     description = "nonnegative floating point number, meaning >=0";
361                     descriptionClass = "nonRestrictiveClause";
362                   }
363                 ) (n: n >= 0);
364                 description = ''
365                   Limits applied to domains whose writes cause other domains' transaction
366                   commits to fail. Must include decimal point.
368                   The burst limit is the number of conflicts a domain can cause to
369                   fail in a short period; this value is used for both the initial and
370                   the maximum value of each domain's conflict-credit, which falls by
371                   one point for each conflict caused, and when it reaches zero the
372                   domain's requests are ignored.
373                 '';
374               };
375               maxHistorySeconds = mkOption {
376                 default = 5.0e-2;
377                 example = 1.0;
378                 type = addCheck (float // { description = "nonnegative floating point number, meaning >=0"; }) (
379                   n: n >= 0
380                 );
381                 description = ''
382                   Limits applied to domains whose writes cause other domains' transaction
383                   commits to fail. Must include decimal point.
385                   The conflict-credit is replenished over time:
386                   one point is issued after each conflict.maxHistorySeconds, so this
387                   is the minimum pause-time during which a domain will be ignored.
388                 '';
389               };
390               rateLimitIsAggregate = mkOption {
391                 default = true;
392                 example = false;
393                 type = bool;
394                 description = ''
395                   If the conflict.rateLimitIsAggregate option is `true`, then after each
396                   tick one point of conflict-credit is given to just one domain: the
397                   one at the front of the queue. If `false`, then after each tick each
398                   domain gets a point of conflict-credit.
400                   In environments where it is known that every transaction will
401                   involve a set of nodes that is writable by at most one other domain,
402                   then it is safe to set this aggregate limit flag to `false` for better
403                   performance. (This can be determined by considering the layout of
404                   the xenstore tree and permissions, together with the content of the
405                   transactions that require protection.)
407                   A transaction which involves a set of nodes which can be modified by
408                   multiple other domains can suffer conflicts caused by any of those
409                   domains, so the flag must be set to `true`.
410                 '';
411               };
412             };
413             perms = {
414               enable = mkOption {
415                 default = true;
416                 example = false;
417                 type = bool;
418                 description = "Whether to enable the node permission system.";
419               };
420               enableWatch = mkOption {
421                 default = true;
422                 example = false;
423                 type = bool;
424                 description = ''
425                   Whether to enable the watch permission system.
427                   When this is set to `true`, unprivileged guests can only get watch events
428                   for xenstore entries that they would've been able to read.
430                   When this is set to `false`, unprivileged guests may get watch events
431                   for xenstore entries that they cannot read. The watch event contains
432                   only the entry name, not the value.
433                   This restores behaviour prior to [XSA-115](https://xenbits.xenproject.org/xsa/advisory-115.html).
434                 '';
435               };
436             };
437             quota = {
438               enable = mkOption {
439                 default = true;
440                 example = false;
441                 type = bool;
442                 description = "Whether to enable the quota system.";
443               };
444               maxEntity = mkOption {
445                 default = 1000;
446                 example = 1024;
447                 type = ints.positive;
448                 description = "Entity limit for transactions.";
449               };
450               maxSize = mkOption {
451                 default = 2048;
452                 example = 4096;
453                 type = ints.positive;
454                 description = "Size limit for transactions.";
455               };
456               maxWatch = mkOption {
457                 default = 100;
458                 example = 256;
459                 type = ints.positive;
460                 description = "Maximum number of watches by the Xenstore Watchdog.";
461               };
462               transaction = mkOption {
463                 default = 10;
464                 example = 50;
465                 type = ints.positive;
466                 description = "Maximum number of transactions.";
467               };
468               maxRequests = mkOption {
469                 default = 1024;
470                 example = 1024;
471                 type = ints.positive;
472                 description = "Maximum number of requests per transaction.";
473               };
474               maxPath = mkOption {
475                 default = 1024;
476                 example = 1024;
477                 type = ints.positive;
478                 description = "Path limit for the quota system.";
479               };
480               maxOutstanding = mkOption {
481                 default = 1024;
482                 example = 1024;
483                 type = ints.positive;
484                 description = "Maximum outstanding requests, i.e. in-flight requests / domain.";
485               };
486               maxWatchEvents = mkOption {
487                 default = 1024;
488                 example = 2048;
489                 type = ints.positive;
490                 description = "Maximum number of outstanding watch events per watch.";
491               };
492             };
493             persistent = mkOption {
494               default = false;
495               example = true;
496               type = bool;
497               description = "Whether to activate the filed base backend.";
498             };
499             xenstored = {
500               log = {
501                 file = mkOption {
502                   default = "/var/log/xen/xenstored.log";
503                   example = "/dev/null";
504                   type = path;
505                   description = "Path to the Xen Store log file.";
506                 };
507                 level = mkOption {
508                   default = if cfg.trace then "debug" else null;
509                   defaultText = literalExpression "if (config.virtualisation.xen.trace == true) then \"debug\" else null";
510                   example = "error";
511                   type = nullOr (enum [
512                     "debug"
513                     "info"
514                     "warn"
515                     "error"
516                   ]);
517                   description = "Logging level for the Xen Store.";
518                 };
519                 # The hidden options below have no upstream documentation whatsoever.
520                 # The nb* options appear to alter the log rotation behaviour, and
521                 # the specialOps option appears to affect the Xenbus logging logic.
522                 nbFiles = mkOption {
523                   default = 10;
524                   example = 16;
525                   type = int;
526                   visible = false;
527                   description = "Set `xenstored-log-nb-files`.";
528                 };
529               };
530               accessLog = {
531                 file = mkOption {
532                   default = "/var/log/xen/xenstored-access.log";
533                   example = "/var/log/security/xenstored-access.log";
534                   type = path;
535                   description = "Path to the Xen Store access log file.";
536                 };
537                 nbLines = mkOption {
538                   default = 13215;
539                   example = 16384;
540                   type = int;
541                   visible = false;
542                   description = "Set `access-log-nb-lines`.";
543                 };
544                 nbChars = mkOption {
545                   default = 180;
546                   example = 256;
547                   type = int;
548                   visible = false;
549                   description = "Set `acesss-log-nb-chars`.";
550                 };
551                 specialOps = mkOption {
552                   default = false;
553                   example = true;
554                   type = bool;
555                   visible = false;
556                   description = "Set `access-log-special-ops`.";
557                 };
558               };
559               xenfs = {
560                 kva = mkOption {
561                   default = "/proc/xen/xsd_kva";
562                   example = cfg.store.settings.xenstored.xenfs.kva;
563                   type = path;
564                   visible = false;
565                   description = ''
566                     Path to the Xen Store Daemon KVA location inside the XenFS pseudo-filesystem.
567                     While it is possible to alter this value, some drivers may be hardcoded to follow the default paths.
568                   '';
569                 };
570                 port = mkOption {
571                   default = "/proc/xen/xsd_port";
572                   example = cfg.store.settings.xenstored.xenfs.port;
573                   type = path;
574                   visible = false;
575                   description = ''
576                     Path to the Xen Store Daemon userspace port inside the XenFS pseudo-filesystem.
577                     While it is possible to alter this value, some drivers may be hardcoded to follow the default paths.
578                   '';
579                 };
580               };
581             };
582             ringScanInterval = mkOption {
583               default = 20;
584               example = 30;
585               type = addCheck (
586                 int
587                 // {
588                   name = "nonzeroInt";
589                   description = "nonzero signed integer, meaning !=0";
590                   descriptionClass = "nonRestrictiveClause";
591                 }
592               ) (n: n != 0);
593               description = ''
594                 Perodic scanning for all the rings as a safenet for lazy clients.
595                 Define the interval in seconds; set to a negative integer to disable.
596               '';
597             };
598           };
599         };
600       };
601     };
602   };
604   ## Implementation ##
606   config = mkIf cfg.enable {
607     assertions = [
608       {
609         assertion = pkgs.stdenv.hostPlatform.isx86_64;
610         message = "Xen is currently not supported on ${pkgs.stdenv.hostPlatform.system}.";
611       }
612       {
613         assertion =
614           config.boot.loader.systemd-boot.enable
615           || (config.boot ? lanzaboote) && config.boot.lanzaboote.enable;
616         message = "Xen only supports booting on systemd-boot or Lanzaboote.";
617       }
618       {
619         assertion = config.boot.initrd.systemd.enable;
620         message = "Xen does not support the legacy script-based Stage 1 initrd.";
621       }
622       {
623         assertion = cfg.dom0Resources.maxMemory >= cfg.dom0Resources.memory;
624         message = ''
625           You have allocated more memory to dom0 than virtualisation.xen.dom0Resources.maxMemory
626           allows for. Please increase the maximum memory limit, or decrease the default memory allocation.
627         '';
628       }
629       {
630         assertion = cfg.debug -> cfg.trace;
631         message = "Xen's debugging features are enabled, but logging is disabled. This is most likely not what you want.";
632       }
633       {
634         assertion = cfg.store.settings.quota.maxWatchEvents >= cfg.store.settings.quota.maxOutstanding;
635         message = ''
636           Upstream Xen recommends that maxWatchEvents be equal to or greater than maxOutstanding,
637           in order to mitigate denial of service attacks from malicious frontends.
638         '';
639       }
640     ];
642     virtualisation.xen.bootParams =
643       optionals cfg.trace [
644         "loglvl=all"
645         "guest_loglvl=all"
646       ]
647       ++
648         optional (cfg.dom0Resources.memory != 0)
649           "dom0_mem=${toString cfg.dom0Resources.memory}M${
650             optionalString (
651               cfg.dom0Resources.memory != cfg.dom0Resources.maxMemory
652             ) ",max:${toString cfg.dom0Resources.maxMemory}M"
653           }"
654       ++ optional (
655         cfg.dom0Resources.maxVCPUs != 0
656       ) "dom0_max_vcpus=${toString cfg.dom0Resources.maxVCPUs}";
658     boot = {
659       kernelModules = [
660         "xen-evtchn"
661         "xen-gntdev"
662         "xen-gntalloc"
663         "xen-blkback"
664         "xen-netback"
665         "xen-pciback"
666         "evtchn"
667         "gntdev"
668         "netbk"
669         "blkbk"
670         "xen-scsibk"
671         "usbbk"
672         "pciback"
673         "xen-acpi-processor"
674         "blktap2"
675         "tun"
676         "netxen_nic"
677         "xen_wdt"
678         "xen-acpi-processor"
679         "xen-privcmd"
680         "xen-scsiback"
681         "xenfs"
682       ];
684       # The xenfs module is needed to mount /proc/xen.
685       initrd.kernelModules = [ "xenfs" ];
687       # Increase the number of loopback devices from the default (8),
688       # which is way too small because every VM virtual disk requires a
689       # loopback device.
690       extraModprobeConfig = ''
691         options loop max_loop=64
692       '';
694       # Xen Bootspec extension. This extension allows NixOS bootloaders to
695       # fetch the `xen.efi` path and access the `cfg.bootParams` option.
696       bootspec.extensions = {
697         "org.xenproject.bootspec.v1" = {
698           xen = cfg.efi.path;
699           xenParams = cfg.bootParams;
700         };
701       };
703       # See the `xenBootBuilder` script in the main `let...in` statement of this file.
704       loader.systemd-boot.extraInstallCommands = ''
705         ${getExe xenBootBuilder} ${cfg.efi.bootBuilderVerbosity}
706       '';
707     };
709     # Domain 0 requires a pvops-enabled kernel.
710     # All NixOS kernels come with this enabled by default; this is merely a sanity check.
711     system.requiredKernelConfig = with config.lib.kernelConfig; [
712       (isYes "XEN")
713       (isYes "X86_IO_APIC")
714       (isYes "ACPI")
715       (isYes "XEN_DOM0")
716       (isYes "PCI_XEN")
717       (isYes "XEN_DEV_EVTCHN")
718       (isYes "XENFS")
719       (isYes "XEN_COMPAT_XENFS")
720       (isYes "XEN_SYS_HYPERVISOR")
721       (isYes "XEN_GNTDEV")
722       (isYes "XEN_BACKEND")
723       (isModule "XEN_NETDEV_BACKEND")
724       (isModule "XEN_BLKDEV_BACKEND")
725       (isModule "XEN_PCIDEV_BACKEND")
726       (isYes "XEN_BALLOON")
727       (isYes "XEN_SCRUB_PAGES")
728     ];
730     environment = {
731       systemPackages = [
732         cfg.package
733         cfg.qemu.package
734       ];
735       etc =
736         # Set up Xen Domain 0 configuration files.
737         {
738           "xen/xl.conf".source = "${cfg.package}/etc/xen/xl.conf"; # TODO: Add options to configure xl.conf declaratively. It's worth considering making a new "xl value" type, as it could be reused to produce xl.cfg (domain definition) files.
739           "xen/scripts-xen" = {
740             source = "${cfg.package}/etc/xen/scripts/*";
741             target = "xen/scripts";
742           };
743           "default/xencommons".text = ''
744             source ${cfg.package}/etc/default/xencommons
746             XENSTORED="${cfg.store.path}"
747             QEMU_XEN="${cfg.qemu.package}/${cfg.qemu.package.qemu-system-i386}"
748             ${optionalString cfg.trace ''
749               XENSTORED_TRACE=yes
750               XENCONSOLED_TRACE=all
751             ''}
752           '';
753           "default/xendomains".text = ''
754             source ${cfg.package}/etc/default/xendomains
756             ${cfg.domains.extraConfig}
757           '';
758         }
759         # The OCaml-based Xen Store Daemon requires /etc/xen/oxenstored.conf to start.
760         // optionalAttrs (cfg.store.type == "ocaml") {
761           "xen/oxenstored.conf".text = ''
762             pid-file = ${cfg.store.settings.pidFile}
763             test-eagain = ${boolToString cfg.store.settings.testEAGAIN}
764             merge-activate = ${toString cfg.store.settings.enableMerge}
765             conflict-burst-limit = ${toString cfg.store.settings.conflict.burstLimit}
766             conflict-max-history-seconds = ${toString cfg.store.settings.conflict.maxHistorySeconds}
767             conflict-rate-limit-is-aggregate = ${toString cfg.store.settings.conflict.rateLimitIsAggregate}
768             perms-activate = ${toString cfg.store.settings.perms.enable}
769             perms-watch-activate = ${toString cfg.store.settings.perms.enableWatch}
770             quota-activate = ${toString cfg.store.settings.quota.enable}
771             quota-maxentity = ${toString cfg.store.settings.quota.maxEntity}
772             quota-maxsize = ${toString cfg.store.settings.quota.maxSize}
773             quota-maxwatch = ${toString cfg.store.settings.quota.maxWatch}
774             quota-transaction = ${toString cfg.store.settings.quota.transaction}
775             quota-maxrequests = ${toString cfg.store.settings.quota.maxRequests}
776             quota-path-max = ${toString cfg.store.settings.quota.maxPath}
777             quota-maxoutstanding = ${toString cfg.store.settings.quota.maxOutstanding}
778             quota-maxwatchevents = ${toString cfg.store.settings.quota.maxWatchEvents}
779             persistent = ${boolToString cfg.store.settings.persistent}
780             xenstored-log-file = ${cfg.store.settings.xenstored.log.file}
781             xenstored-log-level = ${
782               if isNull cfg.store.settings.xenstored.log.level then
783                 "null"
784               else
785                 cfg.store.settings.xenstored.log.level
786             }
787             xenstored-log-nb-files = ${toString cfg.store.settings.xenstored.log.nbFiles}
788             access-log-file = ${cfg.store.settings.xenstored.accessLog.file}
789             access-log-nb-lines = ${toString cfg.store.settings.xenstored.accessLog.nbLines}
790             acesss-log-nb-chars = ${toString cfg.store.settings.xenstored.accessLog.nbChars}
791             access-log-special-ops = ${boolToString cfg.store.settings.xenstored.accessLog.specialOps}
792             ring-scan-interval = ${toString cfg.store.settings.ringScanInterval}
793             xenstored-kva = ${cfg.store.settings.xenstored.xenfs.kva}
794             xenstored-port = ${cfg.store.settings.xenstored.xenfs.port}
795           '';
796         };
797     };
799     # Xen provides udev rules.
800     services.udev.packages = [ cfg.package ];
802     systemd = {
803       # Xen provides systemd units.
804       packages = [ cfg.package ];
806       mounts = [
807         {
808           description = "Mount /proc/xen files";
809           what = "xenfs";
810           where = "/proc/xen";
811           type = "xenfs";
812           unitConfig = {
813             ConditionPathExists = "/proc/xen";
814             RefuseManualStop = "true";
815           };
816         }
817       ];
819       services = {
821         # While this service is installed by the `xen` package, it shouldn't be used in dom0.
822         xendriverdomain.enable = false;
824         xenstored = {
825           wantedBy = [ "multi-user.target" ];
826           preStart = ''
827             export XENSTORED_ROOTDIR="/var/lib/xenstored"
828             rm -f "$XENSTORED_ROOTDIR"/tdb* &>/dev/null
829             mkdir -p /var/{run,log,lib}/xen
830           '';
831         };
833         xen-init-dom0 = {
834           restartIfChanged = false;
835           wantedBy = [ "multi-user.target" ];
836         };
838         xen-qemu-dom0-disk-backend = {
839           wantedBy = [ "multi-user.target" ];
840           serviceConfig = {
841             PIDFile = cfg.qemu.pidFile;
842             ExecStart = ''
843               ${cfg.qemu.package}/${cfg.qemu.package.qemu-system-i386} \
844               -xen-domid 0 -xen-attach -name dom0 -nographic -M xenpv \
845               -daemonize -monitor /dev/null -serial /dev/null -parallel \
846               /dev/null -nodefaults -no-user-config -pidfile \
847               ${cfg.qemu.pidFile}
848             '';
849           };
850         };
852         xenconsoled.wantedBy = [ "multi-user.target" ];
854         xen-watchdog = {
855           wantedBy = [ "multi-user.target" ];
856           serviceConfig = {
857             RestartSec = "1";
858             Restart = "on-failure";
859           };
860         };
862         xendomains = {
863           restartIfChanged = false;
864           path = [
865             cfg.package
866             cfg.qemu.package
867           ];
868           preStart = "mkdir -p /var/lock/subsys -m 755";
869           wantedBy = [ "multi-user.target" ];
870         };
871       };
872     };
873   };
874   meta.maintainers = members;