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