system: Provide locale information to the bootloader.
[jackhill/guix/guix.git] / gnu / bootloader / grub.scm
CommitLineData
0ded70f3 1;;; GNU Guix --- Functional package management for GNU
9512ba6b 2;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
1ef8b72a 3;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
e0b2e930 4;;; Copyright © 2017 Leo Famulari <leo@famulari.name>
7feefb3b 5;;; Copyright © 2017, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
6a790fe3 6;;; Copyright © 2019, 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
aaffde38 7;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
536c53d3 8;;; Copyright © 2020 Stefan <stefan-guix@vodafonemail.de>
0ded70f3
LC
9;;;
10;;; This file is part of GNU Guix.
11;;;
12;;; GNU Guix is free software; you can redistribute it and/or modify it
13;;; under the terms of the GNU General Public License as published by
14;;; the Free Software Foundation; either version 3 of the License, or (at
15;;; your option) any later version.
16;;;
17;;; GNU Guix is distributed in the hope that it will be useful, but
18;;; WITHOUT ANY WARRANTY; without even the implied warranty of
19;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;;; GNU General Public License for more details.
21;;;
22;;; You should have received a copy of the GNU General Public License
23;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
24
b09a8da4 25(define-module (gnu bootloader grub)
c85f316a 26 #:use-module (guix build union)
0ded70f3 27 #:use-module (guix records)
c85f316a
S
28 #:use-module (guix store)
29 #:use-module (guix utils)
f6a7b21d 30 #:use-module (guix gexp)
84dfb458 31 #:use-module (gnu artwork)
b09a8da4 32 #:use-module (gnu bootloader)
9b336338 33 #:use-module (gnu system uuid)
a5acc17a 34 #:use-module (gnu system file-systems)
8d058e7b 35 #:use-module (gnu system keyboard)
6a7c4636 36 #:use-module (gnu packages bootloaders)
ffde82c9 37 #:autoload (gnu packages gtk) (guile-cairo guile-rsvg)
8d058e7b 38 #:autoload (gnu packages xorg) (xkeyboard-config)
0ded70f3 39 #:use-module (ice-9 match)
6b173ac0 40 #:use-module (ice-9 regex)
0ded70f3 41 #:use-module (srfi srfi-1)
6794653e 42 #:use-module (srfi srfi-2)
9cdb10d5 43 #:export (grub-theme
99ae9ceb 44 grub-theme?
9cdb10d5
S
45 grub-theme-image
46 grub-theme-resolution
99ae9ceb
LC
47 grub-theme-color-normal
48 grub-theme-color-highlight
9cdb10d5 49 grub-theme-gfxmode
99ae9ceb 50
c85f316a
S
51 install-grub-efi-netboot
52
b09a8da4
MO
53 grub-bootloader
54 grub-efi-bootloader
c85f316a 55 grub-efi-netboot-bootloader
cf189709 56 grub-mkrescue-bootloader
6a790fe3 57 grub-minimal-bootloader
d5b429ab 58
b09a8da4 59 grub-configuration))
0ded70f3
LC
60
61;;; Commentary:
62;;;
63;;; Configuration of GNU GRUB.
64;;;
65;;; Code:
66
e7b86a0d
MC
67(define* (normalize-file file mount-point store-directory-prefix)
68 "Strip MOUNT-POINT and prepend STORE-DIRECTORY-PREFIX, if any, to FILE, a
b460ba79
MC
69G-expression or other lowerable object denoting a file name."
70
71 (define (strip-mount-point mount-point file)
72 (if mount-point
73 (if (string=? mount-point "/")
74 file
75 #~(let ((file #$file))
76 (if (string-prefix? #$mount-point file)
77 (substring #$file #$(string-length mount-point))
78 file)))
79 file))
80
e7b86a0d
MC
81 (define (prepend-store-directory-prefix store-directory-prefix file)
82 (if store-directory-prefix
83 #~(string-append #$store-directory-prefix #$file)
b460ba79
MC
84 file))
85
e7b86a0d
MC
86 (prepend-store-directory-prefix store-directory-prefix
87 (strip-mount-point mount-point file)))
b460ba79
MC
88
89
0f65f54e 90
99ae9ceb 91(define-record-type* <grub-theme>
9cdb10d5 92 ;; Default theme contributed by Felipe López.
99ae9ceb
LC
93 grub-theme make-grub-theme
94 grub-theme?
9cdb10d5
S
95 (image grub-theme-image
96 (default (file-append %artwork-repository
97 "/grub/GuixSD-fully-black-4-3.svg")))
98 (resolution grub-theme-resolution
99 (default '(1024 . 768)))
99ae9ceb 100 (color-normal grub-theme-color-normal
9cdb10d5 101 (default '((fg . light-gray) (bg . black))))
99ae9ceb 102 (color-highlight grub-theme-color-highlight
9cdb10d5
S
103 (default '((fg . yellow) (bg . black))))
104 (gfxmode grub-theme-gfxmode
f52fe7c3 105 (default '("auto")))) ;list of string
99ae9ceb 106
99ae9ceb
LC
107\f
108;;;
109;;; Background image & themes.
110;;;
111
b09a8da4 112(define (bootloader-theme config)
9cdb10d5 113 "Return user defined theme in CONFIG if defined or a default theme
b09a8da4 114otherwise."
9cdb10d5 115 (or (bootloader-configuration-theme config) (grub-theme)))
b09a8da4 116
9cdb10d5
S
117(define* (image->png image #:key width height)
118 "Build a PNG of HEIGHT x WIDTH from IMAGE if its file suffix is \".svg\".
119Otherwise the picture in IMAGE is just copied."
46c296dc
LC
120 (computed-file "grub-image.png"
121 (with-imported-modules '((gnu build svg))
122 (with-extensions (list guile-rsvg guile-cairo)
9cdb10d5
S
123 #~(if (string-suffix? ".svg" #+image)
124 (begin
125 (use-modules (gnu build svg))
126 (svg->png #+image #$output
127 #:width #$width
128 #:height #$height))
129 (copy-file #+image #$output))))))
130
131(define* (grub-background-image config)
132 "Return the GRUB background image defined in CONFIG or #f if none was found.
133If the suffix of the image file is \".svg\", then it is converted into a PNG
134file with the resolution provided in CONFIG."
135 (let* ((theme (bootloader-theme config))
136 (image (grub-theme-image theme)))
46c296dc 137 (and image
9cdb10d5
S
138 (match (grub-theme-resolution theme)
139 (((? number? width) . (? number? height))
140 (image->png image #:width width #:height height))
141 (_ #f)))))
99ae9ceb 142
1ef8b72a 143(define* (eye-candy config store-device store-mount-point
536c53d3 144 #:key store-directory-prefix port)
b460ba79
MC
145 "Return a gexp that writes to PORT (a port-valued gexp) the 'grub.cfg' part
146concerned with graphics mode, background images, colors, and all that.
147STORE-DEVICE designates the device holding the store, and STORE-MOUNT-POINT is
148its mount point; these are used to determine where the background image and
536c53d3
S
149fonts must be searched for. STORE-DIRECTORY-PREFIX is a directory prefix to
150prepend to any store file name."
e0b2e930 151 (define (setup-gfxterm config font-file)
b09a8da4 152 (if (memq 'gfxterm (bootloader-configuration-terminal-outputs config))
536c53d3
S
153 #~(format #f "
154if loadfont ~a; then
155 set gfxmode=~a
156 insmod all_video
157 insmod gfxterm
158fi~%"
80352a2f 159 #+font-file
536c53d3
S
160 #$(string-join
161 (grub-theme-gfxmode (bootloader-theme config))
162 ";"))
b09a8da4 163 ""))
e0b2e930 164
99ae9ceb 165 (define (theme-colors type)
b09a8da4 166 (let* ((theme (bootloader-theme config))
99ae9ceb
LC
167 (colors (type theme)))
168 (string-append (symbol->string (assoc-ref colors 'fg)) "/"
169 (symbol->string (assoc-ref colors 'bg)))))
170
6b779207 171 (define font-file
b460ba79
MC
172 (normalize-file (file-append grub "/share/grub/unicode.pf2")
173 store-mount-point
e7b86a0d 174 store-directory-prefix))
6b779207 175
46c296dc 176 (define image
b460ba79
MC
177 (normalize-file (grub-background-image config)
178 store-mount-point
e7b86a0d 179 store-directory-prefix))
46c296dc
LC
180
181 (and image
182 #~(format #$port "
ccc2678b 183# Set 'root' to the partition that contains /gnu/store.
6b779207 184~a
ccc2678b 185
e0b2e930
LF
186~a
187~a
99ae9ceb
LC
188
189insmod png
190if background_image ~a; then
191 set color_normal=~a
192 set color_highlight=~a
193else
194 set menu_color_normal=cyan/blue
195 set menu_color_highlight=white/blue
196fi~%"
46c296dc
LC
197 #$(grub-root-search store-device font-file)
198 #$(setup-gfxterm config font-file)
199 #$(grub-setup-io config)
6b779207 200
b460ba79 201 #$image
46c296dc
LC
202 #$(theme-colors grub-theme-color-normal)
203 #$(theme-colors grub-theme-color-highlight))))
99ae9ceb
LC
204
205\f
206;;;
207;;; Configuration file.
208;;;
209
8d058e7b
LC
210(define* (keyboard-layout-file layout
211 #:key
212 (grub grub))
213 "Process the X keyboard layout description LAYOUT, a <keyboard-layout> record,
214and return a file in the format for GRUB keymaps. LAYOUT must be present in
215the 'share/X11/xkb/symbols/' directory of 'xkeyboard-config'."
216 (define builder
217 (with-imported-modules '((guix build utils))
218 #~(begin
219 (use-modules (guix build utils))
220
221 ;; 'grub-kbdcomp' passes all its arguments but '-o' to 'ckbcomp'
222 ;; (from the 'console-setup' package).
8cf7dd24 223 (invoke #+(file-append grub "/bin/grub-mklayout")
8d058e7b
LC
224 "-i" #+(keyboard-layout->console-keymap layout)
225 "-o" #$output))))
226
2729cb40
LC
227 (computed-file (string-append "grub-keymap."
228 (string-map (match-lambda
229 (#\, #\-)
230 (chr chr))
231 (keyboard-layout-name layout)))
8d058e7b
LC
232 builder))
233
e0b2e930
LF
234(define (grub-setup-io config)
235 "Return GRUB commands to configure the input / output interfaces. The result
236is a string that can be inserted in grub.cfg."
237 (let* ((symbols->string (lambda (list)
238 (string-join (map symbol->string list) " ")))
b09a8da4
MO
239 (outputs (bootloader-configuration-terminal-outputs config))
240 (inputs (bootloader-configuration-terminal-inputs config))
241 (unit (bootloader-configuration-serial-unit config))
242 (speed (bootloader-configuration-serial-speed config))
e0b2e930
LF
243
244 ;; Respectively, GRUB_TERMINAL_OUTPUT and GRUB_TERMINAL_INPUT,
245 ;; as documented in GRUB manual section "Simple Configuration
246 ;; Handling".
247 (valid-outputs '(console serial serial_0 serial_1 serial_2 serial_3
248 gfxterm vga_text mda_text morse spkmodem))
249 (valid-inputs '(console serial serial_0 serial_1 serial_2 serial_3
250 at_keyboard usb_keyboard))
251
252 (io (string-append
253 "terminal_output "
254 (symbols->string
255 (map
256 (lambda (output)
257 (if (memq output valid-outputs) output #f)) outputs)) "\n"
258 (if (null? inputs)
259 ""
260 (string-append
261 "terminal_input "
262 (symbols->string
263 (map
264 (lambda (input)
265 (if (memq input valid-inputs) input #f)) inputs)) "\n"))
266 ;; UNIT and SPEED are arguments to the same GRUB command
267 ;; ("serial"), so we process them together.
268 (if (or unit speed)
269 (string-append
270 "serial"
271 (if unit
272 ;; COM ports 1 through 4
273 (if (and (exact-integer? unit) (<= unit 3) (>= unit 0))
274 (string-append " --unit=" (number->string unit))
275 #f)
276 "")
277 (if speed
278 (if (exact-integer? speed)
279 (string-append " --speed=" (number->string speed))
280 #f)
281 ""))
282 ""))))
283 (format #f "~a" io)))
284
1ef8b72a
CM
285(define (grub-root-search device file)
286 "Return the GRUB 'search' command to look for DEVICE, which contains FILE,
6b779207
LC
287a gexp. The result is a gexp that can be inserted in the grub.cfg-generation
288code."
5babe521
LC
289 ;; Usually FILE is a file name gexp like "/gnu/store/…-linux/vmlinuz", but
290 ;; it can also be something like "(hd0,msdos1)/vmlinuz" in the case of
291 ;; custom menu entries. In the latter case, don't emit a 'search' command.
292 (if (and (string? file) (not (string-prefix? "/" file)))
293 ""
1ef8b72a
CM
294 (match device
295 ;; Preferably refer to DEVICE by its UUID or label. This is more
ecc4324f 296 ;; efficient and less ambiguous, see <http://bugs.gnu.org/22281>.
9b336338 297 ((? uuid? uuid)
5babe521 298 (format #f "search --fs-uuid --set ~a"
1ef8b72a 299 (uuid->string device)))
a5acc17a
LC
300 ((? file-system-label? label)
301 (format #f "search --label --set ~a"
302 (file-system-label->string label)))
8c4f1aa8
S
303 ((? (lambda (device)
304 (and (string? device) (string-contains device ":/"))) nfs-uri)
c85f316a
S
305 ;; If the device is an NFS share, then we assume that the expected
306 ;; file on that device (e.g. the GRUB background image or the kernel)
307 ;; has to be loaded over the network. Otherwise we would need an
308 ;; additional device information for some local disk to look for that
309 ;; file, which we do not have.
8c4f1aa8
S
310 ;;
311 ;; We explicitly set "root=(tftp)" here even though if grub.cfg
312 ;; had been loaded via TFTP, Grub would have set "root=(tftp)"
313 ;; automatically anyway. The reason is if you have a system that
314 ;; used to be on NFS but now is local, root would be set to local
315 ;; disk. If you then selected an older system generation that is
316 ;; supposed to boot from network in the Grub boot menu, Grub still
317 ;; wouldn't load those files from network otherwise.
318 ;;
319 ;; TFTP is preferred to HTTP because it is used more widely and
320 ;; specified in standards more widely--especially BOOTP/DHCPv4
321 ;; defines a TFTP server for DHCP option 66, but not HTTP.
322 ;;
323 ;; Note: DHCPv6 specifies option 59 to contain a boot-file-url,
324 ;; which can contain a HTTP or TFTP URL.
325 ;;
326 ;; Note: It is assumed that the file paths are of a similar
327 ;; setup on both the TFTP server and the NFS server (it is
328 ;; not possible to search for files on TFTP).
329 ;;
330 ;; TODO: Allow HTTP.
331 "set root=(tftp)")
a5acc17a 332 ((or #f (? string?))
5babe521 333 #~(format #f "search --file --set ~a" #$file)))))
6b779207 334
1ef8b72a 335(define* (grub-configuration-file config entries
fe6e3fe2
LC
336 #:key
337 (system (%current-system))
b460ba79 338 (old-entries '())
e7b86a0d 339 store-directory-prefix)
d5b429ab 340 "Return the GRUB configuration file corresponding to CONFIG, a
b09a8da4 341<bootloader-configuration> object, and where the store is available at
e7b86a0d
MC
342STORE-FS, a <file-system> object. OLD-ENTRIES is taken to be a list of menu
343entries corresponding to old generations of the system.
344STORE-DIRECTORY-PREFIX may be used to specify a store prefix, as is required
345when booting a root file system on a Btrfs subvolume."
d5b429ab 346 (define all-entries
1975c754
DM
347 (append entries (bootloader-configuration-menu-entries config)))
348 (define (menu-entry->gexp entry)
1244491a
JN
349 (let ((label (menu-entry-label entry))
350 (linux (menu-entry-linux entry))
351 (device (menu-entry-device entry))
352 (device-mount-point (menu-entry-device-mount-point entry)))
353 (if linux
354 (let ((arguments (menu-entry-linux-arguments entry))
355 (linux (normalize-file linux
356 device-mount-point
357 store-directory-prefix))
358 (initrd (normalize-file (menu-entry-initrd entry)
359 device-mount-point
360 store-directory-prefix)))
361 ;; Here DEVICE is the store and DEVICE-MOUNT-POINT is its mount point.
362 ;; Use the right file names for LINUX and INITRD in case
363 ;; DEVICE-MOUNT-POINT is not "/", meaning that the store is on a
364 ;; separate partition.
365
366 ;; When BTRFS-SUBVOLUME-FILE-NAME is defined, prepend it the linux and
367 ;; initrd paths, to allow booting from a Btrfs subvolume.
368 #~(format port "menuentry ~s {
6b779207 369 ~a
44d5f54e 370 linux ~a ~a
d9f0a237 371 initrd ~a
0ded70f3 372}~%"
1244491a
JN
373 #$label
374 #$(grub-root-search device linux)
375 #$linux (string-join (list #$@arguments))
376 #$initrd))
377 (let ((kernel (menu-entry-multiboot-kernel entry))
378 (arguments (menu-entry-multiboot-arguments entry))
379 (modules (menu-entry-multiboot-modules entry))
380 (root-index 1)) ; XXX EFI will need root-index 2
381 #~(format port "
382menuentry ~s {
383 multiboot ~a root=device:hd0s~a~a~a
384}~%"
385 #$label
386 #$kernel
387 #$root-index (string-join (list #$@arguments) " " 'prefix)
388 (string-join (map string-join '#$modules)
389 "\n module " 'prefix))))))
390
391 (define (sugar)
392 (let* ((entry (first all-entries))
393 (device (menu-entry-device entry))
394 (mount-point (menu-entry-device-mount-point entry)))
395 (eye-candy config
396 device
397 mount-point
398 #:store-directory-prefix store-directory-prefix
1244491a 399 #:port #~port)))
46c296dc 400
8d058e7b 401 (define keyboard-layout-config
b460ba79
MC
402 (let* ((layout (bootloader-configuration-keyboard-layout config))
403 (grub (bootloader-package
404 (bootloader-configuration-bootloader config)))
405 (keymap* (and layout
406 (keyboard-layout-file layout #:grub grub)))
407 (keymap (and keymap*
e7b86a0d
MC
408 (if store-directory-prefix
409 #~(string-append #$store-directory-prefix
b460ba79
MC
410 #$keymap*)
411 keymap*))))
412 #~(when #$keymap
413 (format port "\
8d058e7b 414insmod keylayouts
b460ba79 415keymap ~a~%" #$keymap))))
8d058e7b 416
46c296dc
LC
417 (define builder
418 #~(call-with-output-file #$output
419 (lambda (port)
420 (format port
59e80445 421 "# This file was generated from your Guix configuration. Any changes
fdf14c64
JD
422# will be lost upon reconfiguration.
423")
1244491a 424 #$(sugar)
8d058e7b 425 #$keyboard-layout-config
46c296dc 426 (format port "
f6a7b21d 427set default=~a
6c777cf8 428set timeout=~a~%"
46c296dc
LC
429 #$(bootloader-configuration-default-entry config)
430 #$(bootloader-configuration-timeout config))
431 #$@(map menu-entry->gexp all-entries)
99ae9ceb 432
46c296dc
LC
433 #$@(if (pair? old-entries)
434 #~((format port "
fe6e3fe2 435submenu \"GNU system, old configurations...\" {~%")
46c296dc
LC
436 #$@(map menu-entry->gexp old-entries)
437 (format port "}~%"))
b0d09586
BW
438 #~())
439 (format port "
440if [ \"${grub_platform}\" == efi ]; then
441 menuentry \"Firmware setup\" {
442 fwsetup
443 }
444fi~%"))))
0ded70f3 445
9512ba6b
LC
446 ;; Since this file is rather unique, there's no point in trying to
447 ;; substitute it.
448 (computed-file "grub.cfg" builder
449 #:options '(#:local-build? #t
450 #:substitutable? #f)))
0ded70f3 451
b09a8da4
MO
452\f
453
454;;;
455;;; Install procedures.
456;;;
457
458(define install-grub
459 #~(lambda (bootloader device mount-point)
b09a8da4
MO
460 (let ((grub (string-append bootloader "/sbin/grub-install"))
461 (install-dir (string-append mount-point "/boot")))
7e6a42f2
MO
462 ;; Install GRUB on DEVICE which is mounted at MOUNT-POINT. If DEVICE
463 ;; is #f, then we populate the disk-image rooted at MOUNT-POINT.
464 (if device
465 (begin
466 ;; Tell 'grub-install' that there might be a LUKS-encrypted
467 ;; /boot or root partition.
468 (setenv "GRUB_ENABLE_CRYPTODISK" "y")
469
470 ;; Hide potentially confusing messages from the user, such as
471 ;; "Installing for i386-pc platform."
472 (invoke/quiet grub "--no-floppy" "--target=i386-pc"
473 "--boot-directory" install-dir
474 device))
475 ;; When creating a disk-image, only install GRUB modules.
476 (copy-recursively (string-append bootloader "/lib/")
477 install-dir)))))
2941b347 478
7feefb3b
MO
479(define install-grub-disk-image
480 #~(lambda (bootloader root-index image)
481 ;; Install GRUB on the given IMAGE. The root partition index is
482 ;; ROOT-INDEX.
483 (let ((grub-mkimage
484 (string-append bootloader "/bin/grub-mkimage"))
485 (modules '("biosdisk" "part_msdos" "fat" "ext2"))
486 (grub-bios-setup
487 (string-append bootloader "/sbin/grub-bios-setup"))
488 (root-device (format #f "hd0,msdos~a" root-index))
489 (boot-img (string-append bootloader "/lib/grub/i386-pc/boot.img"))
490 (device-map "device.map"))
491
492 ;; Create a minimal, standalone GRUB image that will be written
493 ;; directly in the MBR-GAP (space between the end of the MBR and the
494 ;; first partition).
495 (apply invoke grub-mkimage
496 "-O" "i386-pc"
497 "-o" "core.img"
498 "-p" (format #f "(~a)/boot/grub" root-device)
499 modules)
500
501 ;; Create a device mapping file.
502 (call-with-output-file device-map
503 (lambda (port)
504 (format port "(hd0) ~a~%" image)))
505
506 ;; Copy the default boot.img, that will be written on the MBR sector
507 ;; by GRUB-BIOS-SETUP.
508 (copy-file boot-img "boot.img")
509
510 ;; Install both the "boot.img" and the "core.img" files on the given
511 ;; IMAGE. On boot, the MBR sector will execute the minimal GRUB
512 ;; written in the MBR-GAP. GRUB configuration and missing modules will
513 ;; be read from ROOT-DEVICE.
514 (invoke grub-bios-setup
515 "-m" device-map
516 "-r" root-device
517 "-d" "."
518 image))))
519
2941b347
AW
520(define install-grub-efi
521 #~(lambda (bootloader efi-dir mount-point)
522 ;; Install GRUB onto the EFI partition mounted at EFI-DIR, for the
523 ;; system whose root is mounted at MOUNT-POINT.
524 (let ((grub-install (string-append bootloader "/sbin/grub-install"))
aa5a549c 525 (install-dir (string-append mount-point "/boot"))
59e80445 526 ;; When installing Guix, it's common to mount EFI-DIR below
aa5a549c
MB
527 ;; MOUNT-POINT rather than /boot/efi on the live image.
528 (target-esp (if (file-exists? (string-append mount-point efi-dir))
529 (string-append mount-point efi-dir)
530 efi-dir)))
2941b347
AW
531 ;; Tell 'grub-install' that there might be a LUKS-encrypted /boot or
532 ;; root partition.
533 (setenv "GRUB_ENABLE_CRYPTODISK" "y")
21fcfe1e
LC
534 (invoke/quiet grub-install "--boot-directory" install-dir
535 "--bootloader-id=Guix"
536 "--efi-directory" target-esp))))
b09a8da4 537
c85f316a
S
538(define (install-grub-efi-netboot subdir)
539 "Define a grub-efi-netboot bootloader installer for installation in SUBDIR,
540which is usually efi/Guix or efi/boot."
541 (let* ((system (string-split (nix-system->gnu-triplet
542 (or (%current-target-system)
543 (%current-system)))
544 #\-))
545 (arch (first system))
546 (boot-efi-link (match system
547 ;; These are the supportend systems and the names
548 ;; defined by the UEFI standard for removable media.
549 (("i686" _ ...) "/bootia32.efi")
550 (("x86_64" _ ...) "/bootx64.efi")
551 (("arm" _ ...) "/bootarm.efi")
552 (("aarch64" _ ...) "/bootaa64.efi")
553 (("riscv" _ ...) "/bootriscv32.efi")
554 (("riscv64" _ ...) "/bootriscv64.efi")
555 ;; Other systems are not supported, although defined.
556 ;; (("riscv128" _ ...) "/bootriscv128.efi")
557 ;; (("ia64" _ ...) "/bootia64.efi")
558 ((_ ...) #f)))
559 (core-efi (string-append
560 ;; This is the arch dependent file name of GRUB, e.g.
561 ;; i368-efi/core.efi or arm64-efi/core.efi.
562 (match arch
563 ("i686" "i386")
564 ("aarch64" "arm64")
565 ("riscv" "riscv32")
566 (_ arch))
567 "-efi/core.efi")))
568 (with-imported-modules
569 '((guix build union))
570 #~(lambda (bootloader target mount-point)
571 "Install the BOOTLOADER, which must be the package grub, as e.g.
572bootx64.efi or bootaa64.efi into SUBDIR, which is usually efi/Guix or efi/boot,
573below the directory TARGET for the system whose root is mounted at MOUNT-POINT.
574
575MOUNT-POINT is the last argument in 'guix system init /etc/config.scm mnt/point'
576or '/' for other 'guix system' commands.
577
578TARGET is the target argument given to the bootloader-configuration in
579
580(operating-system
581 (bootloader (bootloader-configuration
582 (target \"/boot\")
583 …))
584 …)
585
586TARGET is required to be an absolute directory name, usually mounted via NFS,
587and finally needs to be provided by a TFTP server as the TFTP root directory.
588
589GRUB will load tftp://server/SUBDIR/grub.cfg and this file will instruct it to
590load more files from the store like tftp://server/gnu/store/…-linux…/Image.
591
592To make this possible two symlinks will be created. The first symlink points
593relatively form MOUNT-POINT/TARGET/SUBDIR/grub.cfg to
594MOUNT-POINT/boot/grub/grub.cfg, and the second symlink points relatively from
595MOUNT-POINT/TARGET/%store-prefix to MOUNT-POINT/%store-prefix.
596
597It is important to note that these symlinks need to be relativ, as the absolute
598paths on the TFTP server side are unknown.
599
600It is also important to note that both symlinks will point outside the TFTP root
601directory and that the TARGET/%store-prefix symlink makes the whole store
602accessible via TFTP. Possibly the TFTP server must be configured
603to allow accesses outside its TFTP root directory. This may need to be
604considered for security aspects."
605 (use-modules ((guix build union) #:select (symlink-relative)))
606 (let* ((net-dir (string-append mount-point target "/"))
607 (sub-dir (string-append net-dir #$subdir "/"))
608 (store (string-append mount-point (%store-prefix)))
609 (store-link (string-append net-dir (%store-prefix)))
610 (grub-cfg (string-append mount-point "/boot/grub/grub.cfg"))
611 (grub-cfg-link (string-append sub-dir (basename grub-cfg)))
612 (boot-efi-link (string-append sub-dir #$boot-efi-link)))
613 ;; Prepare the symlink to the store.
614 (mkdir-p (dirname store-link))
615 (false-if-exception (delete-file store-link))
616 (symlink-relative store store-link)
617 ;; Prepare the symlink to the grub.cfg, which points into the store.
618 (mkdir-p (dirname grub-cfg-link))
619 (false-if-exception (delete-file grub-cfg-link))
620 (symlink-relative grub-cfg grub-cfg-link)
621 ;; Install GRUB, which refers to the grub.cfg, with support for
622 ;; encrypted partitions,
623 (setenv "GRUB_ENABLE_CRYPTODISK" "y")
624 (invoke/quiet (string-append bootloader "/bin/grub-mknetdir")
625 (string-append "--net-directory=" net-dir)
626 (string-append "--subdir=" #$subdir))
627 ;; Prepare the bootloader symlink, which points to core.efi of GRUB.
628 (false-if-exception (delete-file boot-efi-link))
629 (symlink #$core-efi boot-efi-link))))))
630
b09a8da4
MO
631\f
632
633;;;
634;;; Bootloader definitions.
635;;;
3f2bd9df
S
636;;; For all these grub-bootloader variables the path to /boot/grub/grub.cfg
637;;; is fixed. Inheriting and overwriting the field 'configuration-file' will
638;;; break 'guix system delete-generations', 'guix system switch-generation',
639;;; and 'guix system roll-back'.
b09a8da4
MO
640
641(define grub-bootloader
642 (bootloader
643 (name 'grub)
644 (package grub)
645 (installer install-grub)
7feefb3b 646 (disk-image-installer install-grub-disk-image)
b09a8da4
MO
647 (configuration-file "/boot/grub/grub.cfg")
648 (configuration-file-generator grub-configuration-file)))
649
f70c2bd9 650(define grub-minimal-bootloader
6a790fe3 651 (bootloader
7202895e
MO
652 (inherit grub-bootloader)
653 (package grub-minimal)))
6a790fe3 654
f70c2bd9 655(define grub-efi-bootloader
b09a8da4
MO
656 (bootloader
657 (inherit grub-bootloader)
2941b347 658 (installer install-grub-efi)
7feefb3b 659 (disk-image-installer #f)
b09a8da4
MO
660 (name 'grub-efi)
661 (package grub-efi)))
662
c85f316a
S
663(define grub-efi-netboot-bootloader
664 (bootloader
665 (inherit grub-efi-bootloader)
666 (name 'grub-efi-netboot-bootloader)
667 (installer (install-grub-efi-netboot "efi/Guix"))))
668
f70c2bd9 669(define grub-mkrescue-bootloader
cf189709
DM
670 (bootloader
671 (inherit grub-efi-bootloader)
672 (package grub-hybrid)))
673
b09a8da4
MO
674\f
675;;;
676;;; Compatibility macros.
677;;;
678
679(define-syntax grub-configuration
680 (syntax-rules (grub)
681 ((_ (grub package) fields ...)
682 (if (eq? package grub)
683 (bootloader-configuration
684 (bootloader grub-bootloader)
685 fields ...)
686 (bootloader-configuration
687 (bootloader grub-efi-bootloader)
688 fields ...)))
689 ((_ fields ...)
690 (bootloader-configuration
691 (bootloader grub-bootloader)
692 fields ...))))
693
0ded70f3 694;;; grub.scm ends here