summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorStefan <stefan-guix@vodafonemail.de>2022-11-30 19:59:09 -0500
committerMaxim Cournoyer <maxim.cournoyer@gmail.com>2022-12-01 14:31:28 -0500
commita9acbf919a7668e26863d2d26d48c5fd41b57fcd (patch)
treee29c25d793f35b03a711ed865d20eecb55033034 /gnu
parent1a63aea94340f6a24ac09e1c348401e9dfd05395 (diff)
gnu: bootloader: Rework chaining, add grub-efi-netboot-removable-bootloader.
This rework allows to use an (efi-bootloader-chain) like this, which is able to boot over network or local storage, depending on whether the bootloader target has support for symbolic links: (operating-system (bootloader (bootloader-configuration (bootloader (efi-bootloader-chain grub-efi-netboot-removable-bootloader #:packages (list my-firmware-package my-u-boot-package) #:files (list (plain-file "config.txt" "kernel=u-boot.bin")) #:hooks my-special-bootloader-profile-manipulator)) (targets '("/booti/efi")) …)) …) * doc/guix.texi (Bootloader Configuration): Describe the new ‘grub-efi-netboot-removable-bootloader’. Mention the file names used and that the UEFI Boot Manager is not modified. Advise to disable write-access over TFTP. * gnu/bootloader.scm (efi-bootloader-profile): Allow a list of packages and collect everything directly in the profile, avoiding a separate collection directory. Renamed the profile from "bootloader-profile" to "efi-bootloader-profile". [bootloader-collection]: Rename to... [efi-bootloader-profile-hook]: ... this and remove unused modules. Do not create the now extraneous collection directory. (efi-bootloader-chain): Add PACKAGES and DISK-IMAGE-INSTALLER arguments. Remove handling of the collection directory, now only calling the given installer procedure. * gnu/bootloader/grub.scm (make-grub-efi-netboot-installer): New helper. (make-grub-configuration): New helper based on (grub-configuration-file). Add a GRUB argument, fix indentation, remove previous code retrieving GRUB from CONFIG. (grub-configuration-file): Make use of make-grub-configuration. (grub-efi-configuration-file): New procedure. (grub-cfg): New variable to replace "/boot/grub/grub.cfg". (install-grub-efi-netboot): Remove, splitting logic to... (make-grub-efi-netboot-installer): ... this new helper procedure, as well as to make-grub-efi-netboot, added below. (grub-bootloader): Adjust to use the GRUB-CFG. (grub-efi-bootloader): Likewise. Removed inheritance and declare all fields explicitly. (make-grub-efi-netboot-bootloader): New procedure. (grub-efi-netboot-bootloader): Use it. (grub-efi-netboot-removable-bootloader): New variable. * gnu/packages/bootloaders.scm (make-grub-efi-netboot): New procedure. Signed-off-by: Maxim Cournoyer <maxim.cournoyer@gmail.com> Modified-by: Maxim Cournoyer <maxim.cournoyer@gmail.com>
Diffstat (limited to 'gnu')
-rw-r--r--gnu/bootloader.scm105
-rw-r--r--gnu/bootloader/grub.scm220
-rw-r--r--gnu/packages/bootloaders.scm90
3 files changed, 281 insertions, 134 deletions
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index da65b9d5d5d..2c36d8c6cf7 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -322,26 +322,22 @@ instead~%")))
322 (force %bootloaders)) 322 (force %bootloaders))
323 (leave (G_ "~a: no such bootloader~%") name))) 323 (leave (G_ "~a: no such bootloader~%") name)))
324 324
325(define (efi-bootloader-profile files bootloader-package hooks) 325(define (efi-bootloader-profile packages files hooks)
326 "Creates a profile with BOOTLOADER-PACKAGE and a directory collection/ with 326 "Creates a profile from the lists of PACKAGES and FILES from the store.
327links to additional FILES from the store. This collection is meant to be used 327This profile is meant to be used by the bootloader-installer.
328by the bootloader installer.
329 328
330FILES is a list of file or directory names from the store, which will be 329FILES is a list of file or directory names from the store, which will be
331symlinked into the collection/ directory. If a directory name ends with '/', 330symlinked into the profile. If a directory name ends with '/', then the
332then the directory content instead of the directory itself will be symlinked 331directory content instead of the directory itself will be symlinked into the
333into the collection/ directory. 332profile.
334 333
335FILES may contain file like objects produced by functions like plain-file, 334FILES may contain file like objects produced by procedures like plain-file,
336local-file, etc., or package contents produced with file-append. 335local-file, etc., or package contents produced with file-append.
337 336
338HOOKS lists additional hook functions to modify the profile." 337HOOKS lists additional hook functions to modify the profile."
339 (define (bootloader-collection manifest) 338 (define (efi-bootloader-profile-hook manifest)
340 (define build 339 (define build
341 (with-imported-modules '((guix build utils) 340 (with-imported-modules '((guix build utils))
342 (ice-9 ftw)
343 (srfi srfi-1)
344 (srfi srfi-26))
345 #~(begin 341 #~(begin
346 (use-modules ((guix build utils) 342 (use-modules ((guix build utils)
347 #:select (mkdir-p strip-store-file-name)) 343 #:select (mkdir-p strip-store-file-name))
@@ -365,8 +361,7 @@ HOOKS lists additional hook functions to modify the profile."
365 (define (name-is-store-entry? name) 361 (define (name-is-store-entry? name)
366 "Return #t if NAME is a direct store entry and nothing inside." 362 "Return #t if NAME is a direct store entry and nothing inside."
367 (not (string-index (strip-store-file-name name) #\/))) 363 (not (string-index (strip-store-file-name name) #\/)))
368 (let* ((collection (string-append #$output "/collection")) 364 (let* ((files '#$files)
369 (files '#$files)
370 (directories (filter name-ends-with-/? files)) 365 (directories (filter name-ends-with-/? files))
371 (names-from-directories 366 (names-from-directories
372 (append-map (lambda (directory) 367 (append-map (lambda (directory)
@@ -374,11 +369,11 @@ HOOKS lists additional hook functions to modify the profile."
374 directories)) 369 directories))
375 (names (append names-from-directories 370 (names (append names-from-directories
376 (remove name-ends-with-/? files)))) 371 (remove name-ends-with-/? files))))
377 (mkdir-p collection) 372 (mkdir-p #$output)
378 (if (every file-exists? names) 373 (if (every file-exists? names)
379 (begin 374 (begin
380 (for-each (lambda (name) 375 (for-each (lambda (name)
381 (symlink-to name collection 376 (symlink-to name #$output
382 (if (name-is-store-entry? name) 377 (if (name-is-store-entry? name)
383 strip-store-file-name 378 strip-store-file-name
384 basename))) 379 basename)))
@@ -386,57 +381,63 @@ HOOKS lists additional hook functions to modify the profile."
386 #t) 381 #t)
387 #f))))) 382 #f)))))
388 383
389 (gexp->derivation "bootloader-collection" 384 (gexp->derivation "efi-bootloader-profile"
390 build 385 build
391 #:local-build? #t 386 #:local-build? #t
392 #:substitutable? #f 387 #:substitutable? #f
393 #:properties 388 #:properties
394 `((type . profile-hook) 389 `((type . profile-hook)
395 (hook . bootloader-collection)))) 390 (hook . efi-bootloader-profile-hook))))
396 391
397 (profile (content (packages->manifest (list bootloader-package))) 392 (profile (content (packages->manifest packages))
398 (name "bootloader-profile") 393 (name "efi-bootloader-profile")
399 (hooks (append (list bootloader-collection) hooks)) 394 (hooks (cons efi-bootloader-profile-hook hooks))
400 (locales? #f) 395 (locales? #f)
401 (allow-collisions? #f) 396 (allow-collisions? #f)
402 (relative-symlinks? #f))) 397 (relative-symlinks? #f)))
403 398
404(define* (efi-bootloader-chain files 399(define* (efi-bootloader-chain final-bootloader
405 final-bootloader
406 #:key 400 #:key
401 (packages '())
402 (files '())
407 (hooks '()) 403 (hooks '())
408 installer) 404 installer
409 "Define a bootloader chain with FINAL-BOOTLOADER as the final bootloader and 405 disk-image-installer)
410certain directories and files from the store given in the list of FILES. 406 "Define a chain of bootloaders with the FINAL-BOOTLOADER, optional PACKAGES,
407and optional directories and files from the store given in the list of FILES.
411 408
412FILES may contain file like objects produced by functions like plain-file, 409The package of the FINAL-BOOTLOADER and all PACKAGES and FILES will be placed
413local-file, etc., or package contents produced with file-append. They will be 410in an efi-bootloader-profile, which will be passed to the INSTALLER.
414collected inside a directory collection/ inside a generated bootloader profile, 411
415which will be passed to the INSTALLER. 412FILES may contain file-like objects produced by procedures like plain-file,
413local-file, etc., or package contents produced with file-append.
416 414
417If a directory name in FILES ends with '/', then the directory content instead 415If a directory name in FILES ends with '/', then the directory content instead
418of the directory itself will be symlinked into the collection/ directory. 416of the directory itself will be symlinked into the efi-bootloader-profile.
419 417
420The procedures in the HOOKS list can be used to further modify the bootloader 418The procedures in the HOOKS list can be used to further modify the bootloader
421profile. It is possible to pass a single function instead of a list. 419profile. It is possible to pass a single function instead of a list.
422 420
423If the INSTALLER argument is used, then this function will be called to install 421If the INSTALLER argument is used, then this gexp procedure will be called to
424the bootloader. Otherwise the installer of the FINAL-BOOTLOADER will be called." 422install the efi-bootloader-profile. Otherwise the installer of the
425 (let* ((final-installer (or installer 423FINAL-BOOTLOADER will be called.
426 (bootloader-installer final-bootloader))) 424
427 (profile (efi-bootloader-profile files 425If the DISK-IMAGE-INSTALLER is used, then this gexp procedure will be called
428 (bootloader-package final-bootloader) 426to install the efi-bootloader-profile into a disk image. Otherwise the
429 (if (list? hooks) 427disk-image-installer of the FINAL-BOOTLOADER will be called."
430 hooks 428 (bootloader
431 (list hooks))))) 429 (inherit final-bootloader)
432 (bootloader 430 (name "efi-bootloader-chain")
433 (inherit final-bootloader) 431 (package
434 (package profile) 432 (efi-bootloader-profile (cons (bootloader-package final-bootloader)
435 (installer 433 packages)
436 #~(lambda (bootloader target mount-point) 434 files
437 (#$final-installer bootloader target mount-point) 435 (if (list? hooks)
438 (copy-recursively 436 hooks
439 (string-append bootloader "/collection") 437 (list hooks))))
440 (string-append mount-point target) 438 (installer
441 #:follow-symlinks? #t 439 (or installer
442 #:log (%make-void-port "w"))))))) 440 (bootloader-installer final-bootloader)))
441 (disk-image-installer
442 (or disk-image-installer
443 (bootloader-disk-image-installer final-bootloader)))))
diff --git a/gnu/bootloader/grub.scm b/gnu/bootloader/grub.scm
index 72832573547..aab766fd6ca 100644
--- a/gnu/bootloader/grub.scm
+++ b/gnu/bootloader/grub.scm
@@ -53,13 +53,14 @@
53 grub-theme-gfxmode 53 grub-theme-gfxmode
54 54
55 install-grub-efi-removable 55 install-grub-efi-removable
56 install-grub-efi-netboot 56 make-grub-efi-netboot-installer
57 57
58 grub-bootloader 58 grub-bootloader
59 grub-efi-bootloader 59 grub-efi-bootloader
60 grub-efi-removable-bootloader 60 grub-efi-removable-bootloader
61 grub-efi32-bootloader 61 grub-efi32-bootloader
62 grub-efi-netboot-bootloader 62 grub-efi-netboot-bootloader
63 grub-efi-netboot-removable-bootloader
63 grub-mkrescue-bootloader 64 grub-mkrescue-bootloader
64 grub-minimal-bootloader 65 grub-minimal-bootloader
65 66
@@ -353,7 +354,7 @@ code."
353 ((or #f (? string?)) 354 ((or #f (? string?))
354 #~(format #f "search --file --set ~a" #$file))))) 355 #~(format #f "search --file --set ~a" #$file)))))
355 356
356(define* (grub-configuration-file config entries 357(define* (make-grub-configuration grub config entries
357 #:key 358 #:key
358 (locale #f) 359 (locale #f)
359 (system (%current-system)) 360 (system (%current-system))
@@ -453,9 +454,7 @@ menuentry ~s {
453 (define locale-config 454 (define locale-config
454 (let* ((entry (first all-entries)) 455 (let* ((entry (first all-entries))
455 (device (menu-entry-device entry)) 456 (device (menu-entry-device entry))
456 (mount-point (menu-entry-device-mount-point entry)) 457 (mount-point (menu-entry-device-mount-point entry)))
457 (bootloader (bootloader-configuration-bootloader config))
458 (grub (bootloader-package bootloader)))
459 #~(let ((locale #$(and locale 458 #~(let ((locale #$(and locale
460 (locale-definition-source 459 (locale-definition-source
461 (locale-name->definition locale)))) 460 (locale-name->definition locale))))
@@ -481,8 +480,6 @@ set lang=~a~%"
481 480
482 (define keyboard-layout-config 481 (define keyboard-layout-config
483 (let* ((layout (bootloader-configuration-keyboard-layout config)) 482 (let* ((layout (bootloader-configuration-keyboard-layout config))
484 (grub (bootloader-package
485 (bootloader-configuration-bootloader config)))
486 (keymap* (and layout 483 (keymap* (and layout
487 (keyboard-layout-file layout #:grub grub))) 484 (keyboard-layout-file layout #:grub grub)))
488 (entry (first all-entries)) 485 (entry (first all-entries))
@@ -533,6 +530,16 @@ fi~%"))))
533 #:options '(#:local-build? #t 530 #:options '(#:local-build? #t
534 #:substitutable? #f))) 531 #:substitutable? #f)))
535 532
533(define (grub-configuration-file config . args)
534 (let* ((bootloader (bootloader-configuration-bootloader config))
535 (grub (bootloader-package bootloader)))
536 (apply make-grub-configuration grub config args)))
537
538(define (grub-efi-configuration-file . args)
539 (apply make-grub-configuration grub-efi args))
540
541(define grub-cfg "/boot/grub/grub.cfg")
542
536 543
537 544
538;;; 545;;;
@@ -674,42 +681,31 @@ fi~%"))))
674 ((target-arm?) "--target=arm-efi")) 681 ((target-arm?) "--target=arm-efi"))
675 "--efi-directory" target-esp))))) 682 "--efi-directory" target-esp)))))
676 683
677(define (install-grub-efi-netboot subdir) 684(define* (make-grub-efi-netboot-installer grub-efi grub-cfg subdir)
678 "Define a grub-efi-netboot bootloader installer for installation in SUBDIR, 685 "Make a bootloader-installer for a grub-efi-netboot bootloader, which expects
679which is usually efi/Guix or efi/boot." 686its files in SUBDIR and its configuration file in GRUB-CFG.
680 (let* ((system (string-split (nix-system->gnu-triplet 687
681 (or (%current-target-system) 688As a grub-efi-netboot package is already pre-installed by 'grub-mknetdir', the
682 (%current-system))) 689installer basically copies all files from the bootloader-package (or profile)
683 #\-)) 690into the bootloader-target directory.
684 (arch (first system)) 691
685 (boot-efi-link (match system 692Additionally for network booting over TFTP, two relative symlinks to the store
686 ;; These are the supportend systems and the names 693and to the GRUB-CFG file are necessary. Due to this a TFTP root directory must
687 ;; defined by the UEFI standard for removable media. 694not be located on a FAT file-system.
688 (("i686" _ ...) "/bootia32.efi") 695
689 (("x86_64" _ ...) "/bootx64.efi") 696If the bootloader-target does not support symlinks, then it is assumed to be a
690 (("arm" _ ...) "/bootarm.efi") 697kind of EFI System Partition (ESP). In this case an intermediate configuration
691 (("aarch64" _ ...) "/bootaa64.efi") 698file is created with the help of GRUB-EFI to load the GRUB-CFG.
692 (("riscv" _ ...) "/bootriscv32.efi") 699
693 (("riscv64" _ ...) "/bootriscv64.efi") 700The installer is usable for any efi-bootloader-chain, which prepares the
694 ;; Other systems are not supported, although defined. 701bootloader-profile in a way ready for copying.
695 ;; (("riscv128" _ ...) "/bootriscv128.efi") 702
696 ;; (("ia64" _ ...) "/bootia64.efi") 703The installer does not manipulate the system's 'UEFI Boot Manager'.
697 ((_ ...) #f))) 704
698 (core-efi (string-append 705The returned installer accepts the BOOTLOADER, TARGET and MOUNT-POINT
699 ;; This is the arch dependent file name of GRUB, e.g. 706arguments. Its job is to copy the BOOTLOADER, which must be a pre-installed
700 ;; i368-efi/core.efi or arm64-efi/core.efi. 707grub-efi-netboot package with a SUBDIR like efi/boot or efi/Guix, below the
701 (match arch 708directory TARGET for the system whose root is mounted at MOUNT-POINT.
702 ("i686" "i386")
703 ("aarch64" "arm64")
704 ("riscv" "riscv32")
705 (_ arch))
706 "-efi/core.efi")))
707 (with-imported-modules
708 '((guix build union))
709 #~(lambda (bootloader target mount-point)
710 "Install the BOOTLOADER, which must be the package grub, as e.g.
711bootx64.efi or bootaa64.efi into SUBDIR, which is usually efi/Guix or efi/boot,
712below the directory TARGET for the system whose root is mounted at MOUNT-POINT.
713 709
714MOUNT-POINT is the last argument in 'guix system init /etc/config.scm mnt/point' 710MOUNT-POINT is the last argument in 'guix system init /etc/config.scm mnt/point'
715or '/' for other 'guix system' commands. 711or '/' for other 'guix system' commands.
@@ -719,17 +715,19 @@ bootloader-configuration in:
719 715
720(operating-system 716(operating-system
721 (bootloader (bootloader-configuration 717 (bootloader (bootloader-configuration
722 (targets '(\"/boot\")) 718 (targets '(\"/boot/efi\"))
723 …)) 719 …))
724 …) 720 …)
725 721
726TARGET is required to be an absolute directory name, usually mounted via NFS, 722TARGET is required to be an absolute directory name, usually mounted via NFS,
727and finally needs to be provided by a TFTP server as the TFTP root directory. 723and finally needs to be provided by a TFTP server as
724the TFTP root directory.
728 725
726Usually the installer will be used to prepare network booting over TFTP. Then
729GRUB will load tftp://server/SUBDIR/grub.cfg and this file will instruct it to 727GRUB will load tftp://server/SUBDIR/grub.cfg and this file will instruct it to
730load more files from the store like tftp://server/gnu/store/…-linux…/Image. 728load more files from the store like tftp://server/gnu/store/…-linux…/Image.
731 729
732To make this possible two symlinks will be created. The first symlink points 730To make this possible two symlinks are created. The first symlink points
733relatively form MOUNT-POINT/TARGET/SUBDIR/grub.cfg to 731relatively form MOUNT-POINT/TARGET/SUBDIR/grub.cfg to
734MOUNT-POINT/boot/grub/grub.cfg, and the second symlink points relatively from 732MOUNT-POINT/boot/grub/grub.cfg, and the second symlink points relatively from
735MOUNT-POINT/TARGET/%store-prefix to MOUNT-POINT/%store-prefix. 733MOUNT-POINT/TARGET/%store-prefix to MOUNT-POINT/%store-prefix.
@@ -739,34 +737,80 @@ paths on the TFTP server side are unknown.
739 737
740It is also important to note that both symlinks will point outside the TFTP root 738It is also important to note that both symlinks will point outside the TFTP root
741directory and that the TARGET/%store-prefix symlink makes the whole store 739directory and that the TARGET/%store-prefix symlink makes the whole store
742accessible via TFTP. Possibly the TFTP server must be configured 740accessible via TFTP. Possibly the TFTP server must be configured to allow
743to allow accesses outside its TFTP root directory. This may need to be 741accesses outside its TFTP root directory. This all may need to be considered
744considered for security aspects." 742for security aspects. It is advised to disable any TFTP write access!
745 (use-modules ((guix build union) #:select (symlink-relative))) 743
746 (let* ((net-dir (string-append mount-point target "/")) 744The installer can also be used to prepare booting from local storage, if the
747 (sub-dir (string-append net-dir #$subdir "/")) 745underlying file-system, like FAT on an EFI System Partition (ESP), does not
748 (store (string-append mount-point (%store-prefix))) 746support symlinks. In this case the MOUNT-POINT/TARGET/SUBDIR/grub.cfg will be
749 (store-link (string-append net-dir (%store-prefix))) 747created with the help of GRUB-EFI to load the /boot/grub/grub.cfg file. A
750 (grub-cfg (string-append mount-point "/boot/grub/grub.cfg")) 748symlink to the store is not needed in this case."
751 (grub-cfg-link (string-append sub-dir (basename grub-cfg))) 749 (with-imported-modules '((guix build union))
752 (boot-efi-link (string-append sub-dir #$boot-efi-link))) 750 #~(lambda (bootloader target mount-point)
753 ;; Prepare the symlink to the store. 751 ;; In context of a disk image creation TARGET will be #f and an
754 (mkdir-p (dirname store-link)) 752 ;; installer is expected to do necessary installations on MOUNT-POINT,
755 (false-if-exception (delete-file store-link)) 753 ;; which will become the root file system. If TARGET is #f, this
756 (symlink-relative store store-link) 754 ;; installer has nothing to do, as it only cares about the EFI System
757 ;; Prepare the symlink to the grub.cfg, which points into the store. 755 ;; Partition (ESP).
758 (mkdir-p (dirname grub-cfg-link)) 756 (when target
759 (false-if-exception (delete-file grub-cfg-link)) 757 (use-modules ((guix build union) #:select (symlink-relative))
760 (symlink-relative grub-cfg grub-cfg-link) 758 (ice-9 popen)
761 ;; Install GRUB, which refers to the grub.cfg, with support for 759 (ice-9 rdelim))
762 ;; encrypted partitions, 760 (let* ((mount-point/target (string-append mount-point target "/"))
763 (setenv "GRUB_ENABLE_CRYPTODISK" "y") 761 ;; When installing Guix, it is common to mount TARGET below
764 (invoke/quiet (string-append bootloader "/bin/grub-mknetdir") 762 ;; MOUNT-POINT rather than the root directory.
765 (string-append "--net-directory=" net-dir) 763 (bootloader-target (if (file-exists? mount-point/target)
766 (string-append "--subdir=" #$subdir)) 764 mount-point/target
767 ;; Prepare the bootloader symlink, which points to core.efi of GRUB. 765 target))
768 (false-if-exception (delete-file boot-efi-link)) 766 (store (string-append mount-point (%store-prefix)))
769 (symlink #$core-efi boot-efi-link)))))) 767 (store-link (string-append bootloader-target (%store-prefix)))
768 (grub-cfg (string-append mount-point #$grub-cfg))
769 (grub-cfg-link (string-append bootloader-target
770 #$subdir "/"
771 (basename grub-cfg))))
772 ;; Copy the bootloader into the bootloader-target directory.
773 ;; Should we beforehand recursively delete any existing file?
774 (copy-recursively bootloader bootloader-target
775 #:follow-symlinks? #t
776 #:log (%make-void-port "w"))
777 ;; For TFTP we need to install additional relative symlinks.
778 ;; If we install on an EFI System Partition (ESP) or some other FAT
779 ;; file-system, then symlinks cannot be created and are not needed.
780 ;; Therefore we ignore exceptions when trying.
781 ;; Prepare the symlink to the grub.cfg.
782 (mkdir-p (dirname grub-cfg-link))
783 (false-if-exception (delete-file grub-cfg-link))
784 (if (unspecified?
785 (false-if-exception (symlink-relative grub-cfg grub-cfg-link)))
786 ;; Symlinks are supported.
787 (begin
788 ;; Prepare the symlink to the store.
789 (mkdir-p (dirname store-link))
790 (false-if-exception (delete-file store-link))
791 (symlink-relative store store-link))
792 ;; Creating symlinks does not seem to be supported. Probably
793 ;; an ESP is used. Add a script to search and load the actual
794 ;; grub.cfg.
795 (let* ((probe #$(file-append grub-efi "/sbin/grub-probe"))
796 (port (open-pipe* OPEN_READ probe "--target=fs_uuid"
797 grub-cfg))
798 (search-root
799 (match (read-line port)
800 ((? eof-object?)
801 ;; There is no UUID available. As a fallback search
802 ;; everywhere for the grub.cfg.
803 (string-append "search --file --set " #$grub-cfg))
804 (fs-uuid
805 ;; The UUID to load the grub.cfg from is known.
806 (string-append "search --fs-uuid --set " fs-uuid))))
807 (load-grub-cfg (string-append "configfile " #$grub-cfg)))
808 (close-pipe port)
809 (with-output-to-file grub-cfg-link
810 (lambda ()
811 (display (string-join (list search-root
812 load-grub-cfg)
813 "\n")))))))))))
770 814
771 815
772 816
@@ -784,7 +828,7 @@ considered for security aspects."
784 (package grub) 828 (package grub)
785 (installer install-grub) 829 (installer install-grub)
786 (disk-image-installer install-grub-disk-image) 830 (disk-image-installer install-grub-disk-image)
787 (configuration-file "/boot/grub/grub.cfg") 831 (configuration-file grub-cfg)
788 (configuration-file-generator grub-configuration-file))) 832 (configuration-file-generator grub-configuration-file)))
789 833
790(define grub-minimal-bootloader 834(define grub-minimal-bootloader
@@ -794,11 +838,12 @@ considered for security aspects."
794 838
795(define grub-efi-bootloader 839(define grub-efi-bootloader
796 (bootloader 840 (bootloader
797 (inherit grub-bootloader) 841 (name 'grub-efi)
842 (package grub-efi)
798 (installer install-grub-efi) 843 (installer install-grub-efi)
799 (disk-image-installer #f) 844 (disk-image-installer #f)
800 (name 'grub-efi) 845 (configuration-file grub-cfg)
801 (package grub-efi))) 846 (configuration-file-generator grub-configuration-file)))
802 847
803(define grub-efi-removable-bootloader 848(define grub-efi-removable-bootloader
804 (bootloader 849 (bootloader
@@ -813,11 +858,22 @@ considered for security aspects."
813 (name 'grub-efi32) 858 (name 'grub-efi32)
814 (package grub-efi32))) 859 (package grub-efi32)))
815 860
816(define grub-efi-netboot-bootloader 861(define (make-grub-efi-netboot-bootloader name subdir)
817 (bootloader 862 (bootloader
818 (inherit grub-efi-bootloader) 863 (name name)
819 (name 'grub-efi-netboot-bootloader) 864 (package (make-grub-efi-netboot (symbol->string name) subdir))
820 (installer (install-grub-efi-netboot "efi/Guix")))) 865 (installer (make-grub-efi-netboot-installer grub-efi grub-cfg subdir))
866 (disk-image-installer #f)
867 (configuration-file grub-cfg)
868 (configuration-file-generator grub-efi-configuration-file)))
869
870(define grub-efi-netboot-bootloader
871 (make-grub-efi-netboot-bootloader 'grub-efi-netboot-bootloader
872 "efi/Guix"))
873
874(define grub-efi-netboot-removable-bootloader
875 (make-grub-efi-netboot-bootloader 'grub-efi-netboot-removable-bootloader
876 "efi/boot"))
821 877
822(define grub-mkrescue-bootloader 878(define grub-mkrescue-bootloader
823 (bootloader 879 (bootloader
diff --git a/gnu/packages/bootloaders.scm b/gnu/packages/bootloaders.scm
index d21e2a1a8b5..7a9cff17120 100644
--- a/gnu/packages/bootloaders.scm
+++ b/gnu/packages/bootloaders.scm
@@ -16,6 +16,7 @@
16;;; Copyright © 2021 Vincent Legoll <vincent.legoll@gmail.com> 16;;; Copyright © 2021 Vincent Legoll <vincent.legoll@gmail.com>
17;;; Copyright © 2021 Brice Waegeneire <brice@waegenei.re> 17;;; Copyright © 2021 Brice Waegeneire <brice@waegenei.re>
18;;; Copyright © 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org> 18;;; Copyright © 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
19;;; Copyright © 2021 Stefan <stefan-guix@vodafonemail.de>
19;;; 20;;;
20;;; This file is part of GNU Guix. 21;;; This file is part of GNU Guix.
21;;; 22;;;
@@ -67,7 +68,9 @@
67 #:use-module (gnu packages virtualization) 68 #:use-module (gnu packages virtualization)
68 #:use-module (gnu packages xorg) 69 #:use-module (gnu packages xorg)
69 #:use-module (guix build-system gnu) 70 #:use-module (guix build-system gnu)
71 #:use-module (guix build-system trivial)
70 #:use-module (guix download) 72 #:use-module (guix download)
73 #:use-module (guix gexp)
71 #:use-module (guix git-download) 74 #:use-module (guix git-download)
72 #:use-module ((guix licenses) #:prefix license:) 75 #:use-module ((guix licenses) #:prefix license:)
73 #:use-module (guix packages) 76 #:use-module (guix packages)
@@ -75,6 +78,7 @@
75 #:use-module (srfi srfi-1) 78 #:use-module (srfi srfi-1)
76 #:use-module (srfi srfi-26) 79 #:use-module (srfi srfi-26)
77 #:use-module (ice-9 optargs) 80 #:use-module (ice-9 optargs)
81 #:use-module (ice-9 match)
78 #:use-module (ice-9 regex)) 82 #:use-module (ice-9 regex))
79 83
80(define unifont 84(define unifont
@@ -390,6 +394,92 @@ menu to select one of the installed operating systems.")
390 (scandir input-dir)) 394 (scandir input-dir))
391 #t))))))))) 395 #t)))))))))
392 396
397(define-public (make-grub-efi-netboot name subdir)
398 "Make a grub-efi-netboot package named NAME, which will be able to boot over
399network via TFTP by accessing its files in the SUBDIR of a TFTP root directory.
400This package is also able to boot from local storage devices.
401
402A bootloader-installer basically needs to copy the package content into the
403bootloader-target directory, which will usually be the TFTP root, as
404'grub-mknetdir' will be invoked already during the package creation.
405
406Alternatively the bootloader-target directory can be a mounted EFI System
407Partition (ESP), or a similar partition with a FAT file system, for booting
408from local storage devices.
409
410The name of the GRUB EFI binary will conform to the UEFI specification for
411removable media. Depending on the system it will be e.g. bootx64.efi or
412bootaa64.efi below SUBDIR.
413
414The SUBDIR argument needs to be set to \"efi/boot\" to create a package which
415conforms to the UEFI specification for removable media.
416
417The SUBDIR argument defaults to \"efi/Guix\", as it is also the case for
418'grub-efi-bootloader'."
419 (package
420 (name name)
421 (version (package-version grub-efi))
422 ;; Source is not needed, but it cannot be omitted.
423 (source #f)
424 (build-system trivial-build-system)
425 (arguments
426 (let* ((system (string-split (nix-system->gnu-triplet
427 (or (%current-target-system)
428 (%current-system)))
429 #\-))
430 (arch (first system))
431 (boot-efi
432 (match system
433 ;; These are the supportend systems and the names defined by
434 ;; the UEFI standard for removable media.
435 (("i686" _ ...) "/bootia32.efi")
436 (("x86_64" _ ...) "/bootx64.efi")
437 (("arm" _ ...) "/bootarm.efi")
438 (("aarch64" _ ...) "/bootaa64.efi")
439 (("riscv" _ ...) "/bootriscv32.efi")
440 (("riscv64" _ ...) "/bootriscv64.efi")
441 ;; Other systems are not supported, although defined.
442 ;; (("riscv128" _ ...) "/bootriscv128.efi")
443 ;; (("ia64" _ ...) "/bootia64.efi")
444 ((_ ...) #f)))
445 (core-efi (string-append
446 ;; This is the arch dependent file name of GRUB, e.g.
447 ;; i368-efi/core.efi or arm64-efi/core.efi.
448 (match arch
449 ("i686" "i386")
450 ("aarch64" "arm64")
451 ("riscv" "riscv32")
452 (_ arch))
453 "-efi/core.efi")))
454 (list
455 #:modules '((guix build utils))
456 #:builder
457 #~(begin
458 (use-modules (guix build utils))
459 (let* ((bootloader #$(this-package-input "grub-efi"))
460 (net-dir #$output)
461 (sub-dir (string-append net-dir "/" #$subdir "/"))
462 (boot-efi (string-append sub-dir #$boot-efi))
463 (core-efi (string-append sub-dir #$core-efi)))
464 ;; Install GRUB, which refers to the grub.cfg, with support for
465 ;; encrypted partitions,
466 (setenv "GRUB_ENABLE_CRYPTODISK" "y")
467 (invoke/quiet (string-append bootloader "/bin/grub-mknetdir")
468 (string-append "--net-directory=" net-dir)
469 (string-append "--subdir=" #$subdir)
470 ;; These modules must be pre-loaded to allow booting
471 ;; from an ESP or a similar partition with a FAT
472 ;; file system.
473 (string-append "--modules=part_msdos part_gpt fat"))
474 ;; Move GRUB's core.efi to the removable media name.
475 (false-if-exception (delete-file boot-efi))
476 (rename-file core-efi boot-efi))))))
477 (inputs (list grub-efi))
478 (synopsis (package-synopsis grub-efi))
479 (description (package-description grub-efi))
480 (home-page (package-home-page grub-efi))
481 (license (package-license grub-efi))))
482
393(define-public syslinux 483(define-public syslinux
394 (let ((commit "bb41e935cc83c6242de24d2271e067d76af3585c")) 484 (let ((commit "bb41e935cc83c6242de24d2271e067d76af3585c"))
395 (package 485 (package