1{ config, lib, pkgs, ... }:
2
3let
4
5 cfg = config.boot.uki;
6
7 inherit (pkgs.stdenv.hostPlatform) efiArch;
8
9 format = pkgs.formats.ini { };
10in
11
12{
13 options = {
14
15 boot.uki = {
16 name = lib.mkOption {
17 type = lib.types.str;
18 description = "Name of the UKI";
19 };
20
21 version = lib.mkOption {
22 type = lib.types.nullOr lib.types.str;
23 default = config.system.image.version;
24 defaultText = lib.literalExpression "config.system.image.version";
25 description = "Version of the image or generation the UKI belongs to";
26 };
27
28 tries = lib.mkOption {
29 type = lib.types.nullOr lib.types.ints.unsigned;
30 default = null;
31 description = ''
32 Number of boot attempts before this UKI is considered bad.
33
34 If no tries are specified (the default) automatic boot assessment remains inactive.
35
36 See documentation on [Automatic Boot Assessment](https://systemd.io/AUTOMATIC_BOOT_ASSESSMENT/) and
37 [boot counting](https://uapi-group.org/specifications/specs/boot_loader_specification/#boot-counting)
38 for more information.
39 '';
40 };
41
42 settings = lib.mkOption {
43 type = format.type;
44 description = ''
45 The configuration settings for ukify. These control what the UKI
46 contains and how it is built.
47 '';
48 };
49
50 configFile = lib.mkOption {
51 type = lib.types.path;
52 description = ''
53 The configuration file passed to {manpage}`ukify(1)` to create the UKI.
54
55 By default this configuration file is created from {option}`boot.uki.settings`.
56 '';
57 };
58 };
59
60 system.boot.loader.ukiFile = lib.mkOption {
61 type = lib.types.str;
62 internal = true;
63 description = "Name of the UKI file";
64 };
65
66 };
67
68 config = {
69
70 boot.uki.name = lib.mkOptionDefault (if config.system.image.id != null then
71 config.system.image.id
72 else
73 "nixos");
74
75 boot.uki.settings = {
76 UKI = {
77 Linux = lib.mkOptionDefault "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}";
78 Initrd = lib.mkOptionDefault "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
79 Cmdline = lib.mkOptionDefault "init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}";
80 Stub = lib.mkOptionDefault "${pkgs.systemd}/lib/systemd/boot/efi/linux${efiArch}.efi.stub";
81 Uname = lib.mkOptionDefault "${config.boot.kernelPackages.kernel.modDirVersion}";
82 OSRelease = lib.mkOptionDefault "@${config.system.build.etc}/etc/os-release";
83 # This is needed for cross compiling.
84 EFIArch = lib.mkOptionDefault efiArch;
85 } // lib.optionalAttrs (config.hardware.deviceTree.enable && config.hardware.deviceTree.name != null) {
86 DeviceTree = lib.mkOptionDefault "${config.hardware.deviceTree.package}/${config.hardware.deviceTree.name}";
87 };
88 };
89
90 boot.uki.configFile = lib.mkOptionDefault (format.generate "ukify.conf" cfg.settings);
91
92 system.boot.loader.ukiFile =
93 let
94 name = config.boot.uki.name;
95 version = config.boot.uki.version;
96 versionInfix = if version != null then "_${version}" else "";
97 triesInfix = if cfg.tries != null then "+${builtins.toString cfg.tries}" else "";
98 in
99 name + versionInfix + triesInfix + ".efi";
100
101 system.build.uki = pkgs.runCommand config.system.boot.loader.ukiFile { } ''
102 mkdir -p $out
103 ${pkgs.buildPackages.systemdUkify}/lib/systemd/ukify build \
104 --config=${cfg.configFile} \
105 --output="$out/${config.system.boot.loader.ukiFile}"
106 '';
107
108 meta.maintainers = with lib.maintainers; [ nikstur ];
109
110 };
111}