···1112## Submitting changes
13000014* Format the commit messages in the following way:
1516 ```
···40 * If there is no upstream license, `meta.license` should default to `lib.licenses.unfree`.
41* `meta.maintainers` must be set.
4243-See the nixpkgs manual for more details on [standard meta-attributes](https://nixos.org/nixpkgs/manual/#sec-standard-meta-attributes) and on how to [submit changes to nixpkgs](https://nixos.org/nixpkgs/manual/#chap-submitting-changes).
4445## Writing good commit messages
46
···1112## Submitting changes
1314+Read the ["Submitting changes"](https://nixos.org/nixpkgs/manual/#chap-submitting-changes) section of the nixpkgs manual. It explains how to write, test, and iterate on your change, and which branch to base your pull request against.
15+16+Below is a short excerpt of some points in there:
17+18* Format the commit messages in the following way:
1920 ```
···44 * If there is no upstream license, `meta.license` should default to `lib.licenses.unfree`.
45* `meta.maintainers` must be set.
4647+See the nixpkgs manual for more details on [standard meta-attributes](https://nixos.org/nixpkgs/manual/#sec-standard-meta-attributes).
4849## Writing good commit messages
50
···45options {kernel_params}
46"""
4748-# The boot loader entry for memtest86.
49-#
50-# TODO: This is hard-coded to use the 64-bit EFI app, but it could probably
51-# be updated to use the 32-bit EFI app on 32-bit systems. The 32-bit EFI
52-# app filename is BOOTIA32.efi.
53-MEMTEST_BOOT_ENTRY = """title MemTest86
54-efi /efi/memtest86/BOOTX64.efi
55-"""
56-57-58def generation_conf_filename(profile: Optional[str], generation: int, specialisation: Optional[str]) -> str:
59 pieces = [
60 "nixos",
···283 except OSError as e:
284 print("ignoring profile '{}' in the list of boot entries because of the following error:\n{}".format(profile, e), file=sys.stderr)
285286- memtest_entry_file = "@efiSysMountPoint@/loader/entries/memtest86.conf"
287- if os.path.exists(memtest_entry_file):
288- os.unlink(memtest_entry_file)
289- shutil.rmtree("@efiSysMountPoint@/efi/memtest86", ignore_errors=True)
290- if "@memtest86@" != "":
291- mkdir_p("@efiSysMountPoint@/efi/memtest86")
292- for path in glob.iglob("@memtest86@/*"):
293- if os.path.isdir(path):
294- shutil.copytree(path, os.path.join("@efiSysMountPoint@/efi/memtest86", os.path.basename(path)))
295- else:
296- shutil.copy(path, "@efiSysMountPoint@/efi/memtest86/")
00000297298- memtest_entry_file = "@efiSysMountPoint@/loader/entries/memtest86.conf"
299- memtest_entry_file_tmp_path = "%s.tmp" % memtest_entry_file
300- with open(memtest_entry_file_tmp_path, 'w') as f:
301- f.write(MEMTEST_BOOT_ENTRY)
302- os.rename(memtest_entry_file_tmp_path, memtest_entry_file)
303304 # Since fat32 provides little recovery facilities after a crash,
305 # it can leave the system in an unbootable state, when a crash/outage
···45options {kernel_params}
46"""
47000000000048def generation_conf_filename(profile: Optional[str], generation: int, specialisation: Optional[str]) -> str:
49 pieces = [
50 "nixos",
···273 except OSError as e:
274 print("ignoring profile '{}' in the list of boot entries because of the following error:\n{}".format(profile, e), file=sys.stderr)
275276+ for root, _, files in os.walk('@efiSysMountPoint@/efi/nixos/.extra-files', topdown=False):
277+ relative_root = root.removeprefix("@efiSysMountPoint@/efi/nixos/.extra-files").removeprefix("/")
278+ actual_root = os.path.join("@efiSysMountPoint@", relative_root)
279+280+ for file in files:
281+ actual_file = os.path.join(actual_root, file)
282+283+ if os.path.exists(actual_file):
284+ os.unlink(actual_file)
285+ os.unlink(os.path.join(root, file))
286+287+ if not len(os.listdir(actual_root)):
288+ os.rmdir(actual_root)
289+ os.rmdir(root)
290+291+ mkdir_p("@efiSysMountPoint@/efi/nixos/.extra-files")
292293+ subprocess.check_call("@copyExtraFiles@")
0000294295 # Since fat32 provides little recovery facilities after a crash,
296 # it can leave the system in an unbootable state, when a crash/outage
···29 inherit (efi) efiSysMountPoint canTouchEfiVariables;
3031 memtest86 = if cfg.memtest86.enable then pkgs.memtest86-efi else "";
32+33+ netbootxyz = if cfg.netbootxyz.enable then pkgs.netbootxyz-efi else "";
34+35+ copyExtraFiles = pkgs.writeShellScript "copy-extra-files" ''
36+ empty_file=$(mktemp)
37+38+ ${concatStrings (mapAttrsToList (n: v: ''
39+ ${pkgs.coreutils}/bin/install -Dp "${v}" "${efi.efiSysMountPoint}/"${escapeShellArg n}
40+ ${pkgs.coreutils}/bin/install -D $empty_file "${efi.efiSysMountPoint}/efi/nixos/.extra-files/"${escapeShellArg n}
41+ '') cfg.extraFiles)}
42+43+ ${concatStrings (mapAttrsToList (n: v: ''
44+ ${pkgs.coreutils}/bin/install -Dp "${pkgs.writeText n v}" "${efi.efiSysMountPoint}/loader/entries/"${escapeShellArg n}
45+ ${pkgs.coreutils}/bin/install -D $empty_file "${efi.efiSysMountPoint}/efi/nixos/.extra-files/loader/entries/"${escapeShellArg n}
46+ '') cfg.extraEntries)}
47+ '';
48 };
4950 checkedSystemdBootBuilder = pkgs.runCommand "systemd-boot" {
···141 <literal>true</literal>.
142 '';
143 };
144+145+ entryFilename = mkOption {
146+ default = "memtest86.conf";
147+ type = types.str;
148+ description = ''
149+ <literal>systemd-boot</literal> orders the menu entries by the config file names,
150+ so if you want something to appear after all the NixOS entries,
151+ it should start with <filename>o</filename> or onwards.
152+ '';
153+ };
154+ };
155+156+ netbootxyz = {
157+ enable = mkOption {
158+ default = false;
159+ type = types.bool;
160+ description = ''
161+ Make <literal>netboot.xyz</literal> available from the
162+ <literal>systemd-boot</literal> menu. <literal>netboot.xyz</literal>
163+ is a menu system that allows you to boot OS installers and
164+ utilities over the network.
165+ '';
166+ };
167+168+ entryFilename = mkOption {
169+ default = "o_netbootxyz.conf";
170+ type = types.str;
171+ description = ''
172+ <literal>systemd-boot</literal> orders the menu entries by the config file names,
173+ so if you want something to appear after all the NixOS entries,
174+ it should start with <filename>o</filename> or onwards.
175+ '';
176+ };
177+ };
178+179+ extraEntries = mkOption {
180+ type = types.attrsOf types.lines;
181+ default = {};
182+ example = literalExpression ''
183+ { "memtest86.conf" = '''
184+ title MemTest86
185+ efi /efi/memtest86/memtest86.efi
186+ '''; }
187+ '';
188+ description = ''
189+ Any additional entries you want added to the <literal>systemd-boot</literal> menu.
190+ These entries will be copied to <filename>/boot/loader/entries</filename>.
191+ Each attribute name denotes the destination file name,
192+ and the corresponding attribute value is the contents of the entry.
193+194+ <literal>systemd-boot</literal> orders the menu entries by the config file names,
195+ so if you want something to appear after all the NixOS entries,
196+ it should start with <filename>o</filename> or onwards.
197+ '';
198+ };
199+200+ extraFiles = mkOption {
201+ type = types.attrsOf types.path;
202+ default = {};
203+ example = literalExpression ''
204+ { "efi/memtest86/memtest86.efi" = "''${pkgs.memtest86-efi}/BOOTX64.efi"; }
205+ '';
206+ description = ''
207+ A set of files to be copied to <filename>/boot</filename>.
208+ Each attribute name denotes the destination file name in
209+ <filename>/boot</filename>, while the corresponding
210+ attribute value specifies the source file.
211+ '';
212 };
213214 graceful = mkOption {
···232 assertions = [
233 {
234 assertion = (config.boot.kernelPackages.kernel.features or { efiBootStub = true; }) ? efiBootStub;
0235 message = "This kernel does not support the EFI boot stub";
236 }
237+ ] ++ concatMap (filename: [
238+ {
239+ assertion = !(hasInfix "/" filename);
240+ message = "boot.loader.systemd-boot.extraEntries.${lib.strings.escapeNixIdentifier filename} is invalid: entries within folders are not supported";
241+ }
242+ {
243+ assertion = hasSuffix ".conf" filename;
244+ message = "boot.loader.systemd-boot.extraEntries.${lib.strings.escapeNixIdentifier filename} is invalid: entries must have a .conf file extension";
245+ }
246+ ]) (builtins.attrNames cfg.extraEntries)
247+ ++ concatMap (filename: [
248+ {
249+ assertion = !(hasPrefix "/" filename);
250+ message = "boot.loader.systemd-boot.extraFiles.${lib.strings.escapeNixIdentifier filename} is invalid: paths must not begin with a slash";
251+ }
252+ {
253+ assertion = !(hasInfix ".." filename);
254+ message = "boot.loader.systemd-boot.extraFiles.${lib.strings.escapeNixIdentifier filename} is invalid: paths must not reference the parent directory";
255+ }
256+ {
257+ assertion = !(hasInfix "nixos/.extra-files" (toLower filename));
258+ message = "boot.loader.systemd-boot.extraFiles.${lib.strings.escapeNixIdentifier filename} is invalid: files cannot be placed in the nixos/.extra-files directory";
259+ }
260+ ]) (builtins.attrNames cfg.extraFiles);
261262 boot.loader.grub.enable = mkDefault false;
263264 boot.loader.supportsInitrdSecrets = true;
265+266+ boot.loader.systemd-boot.extraFiles = mkMerge [
267+ # TODO: This is hard-coded to use the 64-bit EFI app, but it could probably
268+ # be updated to use the 32-bit EFI app on 32-bit systems. The 32-bit EFI
269+ # app filename is BOOTIA32.efi.
270+ (mkIf cfg.memtest86.enable {
271+ "efi/memtest86/BOOTX64.efi" = "${pkgs.memtest86-efi}/BOOTX64.efi";
272+ })
273+ (mkIf cfg.netbootxyz.enable {
274+ "efi/netbootxyz/netboot.xyz.efi" = "${pkgs.netbootxyz-efi}";
275+ })
276+ ];
277+278+ boot.loader.systemd-boot.extraEntries = mkMerge [
279+ (mkIf cfg.memtest86.enable {
280+ "${cfg.memtest86.entryFilename}" = ''
281+ title MemTest86
282+ efi /efi/memtest86/BOOTX64.efi
283+ '';
284+ })
285+ (mkIf cfg.netbootxyz.enable {
286+ "${cfg.netbootxyz.entryFilename}" = ''
287+ title netboot.xyz
288+ efi /efi/netbootxyz/netboot.xyz.efi
289+ '';
290+ })
291+ ];
292293 system = {
294 build.installBootLoader = checkedSystemdBootBuilder;
···110 assert "updating systemd-boot from (000.0-1-notnixos) to " in output
111 '';
112 };
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000113}
···1+{ lib
2+, fetchurl
3+}:
4+5+let
6+ pname = "netboot.xyz-efi";
7+ version = "2.0.53";
8+in fetchurl {
9+ name = "${pname}-${version}";
10+11+ url = "https://github.com/netbootxyz/netboot.xyz/releases/download/${version}/netboot.xyz.efi";
12+ sha256 = "sha256-v7XqrhG94BLTpDHDazTiowQUXu/ITEcgVMmhlqgmSQE=";
13+14+ meta = with lib; {
15+ homepage = "https://netboot.xyz/";
16+ description = "A tool to boot OS installers and utilities over the network, to be run from a bootloader";
17+ license = licenses.asl20;
18+ maintainers = with maintainers; [ Enzime ];
19+ platforms = platforms.linux;
20+ };
21+}