system: Use 'source-module-closure' where needed.
[jackhill/guix/guix.git] / gnu / system / linux-initrd.scm
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2016 Mark H Weaver <mhw@netris.org>
4 ;;; Copyright © 2016 Jan Nieuwenhuizen <janneke@gnu.org>
5 ;;;
6 ;;; This file is part of GNU Guix.
7 ;;;
8 ;;; GNU Guix is free software; you can redistribute it and/or modify it
9 ;;; under the terms of the GNU General Public License as published by
10 ;;; the Free Software Foundation; either version 3 of the License, or (at
11 ;;; your option) any later version.
12 ;;;
13 ;;; GNU Guix is distributed in the hope that it will be useful, but
14 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;;; GNU General Public License for more details.
17 ;;;
18 ;;; You should have received a copy of the GNU General Public License
19 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
20
21 (define-module (gnu system linux-initrd)
22 #:use-module (guix monads)
23 #:use-module (guix store)
24 #:use-module (guix gexp)
25 #:use-module (guix utils)
26 #:use-module ((guix store)
27 #:select (%store-prefix))
28 #:use-module ((guix derivations)
29 #:select (derivation->output-path))
30 #:use-module (guix modules)
31 #:use-module (gnu packages compression)
32 #:use-module (gnu packages linux)
33 #:use-module (gnu packages guile)
34 #:use-module ((gnu packages make-bootstrap)
35 #:select (%guile-static-stripped))
36 #:use-module (gnu system file-systems)
37 #:use-module (gnu system mapped-devices)
38 #:use-module (ice-9 match)
39 #:use-module (ice-9 regex)
40 #:use-module (srfi srfi-1)
41 #:use-module (srfi srfi-26)
42 #:export (expression->initrd
43 base-initrd))
44
45 \f
46 ;;; Commentary:
47 ;;;
48 ;;; Tools to build initial RAM disks (initrd's) for Linux-Libre, and in
49 ;;; particular initrd's that run Guile.
50 ;;;
51 ;;; Code:
52
53
54 (define* (expression->initrd exp
55 #:key
56 (guile %guile-static-stripped)
57 (gzip gzip)
58 (name "guile-initrd")
59 (system (%current-system)))
60 "Return a derivation that builds a Linux initrd (a gzipped cpio archive)
61 containing GUILE and that evaluates EXP, a G-expression, upon booting. All
62 the derivations referenced by EXP are automatically copied to the initrd."
63
64 ;; General Linux overview in `Documentation/early-userspace/README' and
65 ;; `Documentation/filesystems/ramfs-rootfs-initramfs.txt'.
66
67 (mlet %store-monad ((init (gexp->script "init" exp
68 #:guile guile)))
69 (define builder
70 (with-imported-modules (source-module-closure
71 '((gnu build linux-initrd)))
72 #~(begin
73 (use-modules (gnu build linux-initrd))
74
75 (mkdir #$output)
76 (build-initrd (string-append #$output "/initrd")
77 #:guile #$guile
78 #:init #$init
79 ;; Copy everything INIT refers to into the initrd.
80 #:references-graphs '("closure")
81 #:gzip (string-append #$gzip "/bin/gzip")))))
82
83 (gexp->derivation name builder
84 #:references-graphs `(("closure" ,init)))))
85
86 (define (flat-linux-module-directory linux modules)
87 "Return a flat directory containing the Linux kernel modules listed in
88 MODULES and taken from LINUX."
89 (define build-exp
90 (with-imported-modules (source-module-closure
91 '((guix build utils)
92 (gnu build linux-modules)))
93 #~(begin
94 (use-modules (ice-9 match) (ice-9 regex)
95 (srfi srfi-1)
96 (guix build utils)
97 (gnu build linux-modules))
98
99 (define (string->regexp str)
100 ;; Return a regexp that matches STR exactly.
101 (string-append "^" (regexp-quote str) "$"))
102
103 (define module-dir
104 (string-append #$linux "/lib/modules"))
105
106 (define (lookup module)
107 (let ((name (ensure-dot-ko module)))
108 (match (find-files module-dir (string->regexp name))
109 ((file)
110 file)
111 (()
112 (error "module not found" name module-dir))
113 ((_ ...)
114 (error "several modules by that name"
115 name module-dir)))))
116
117 (define modules
118 (let ((modules (map lookup '#$modules)))
119 (append modules
120 (recursive-module-dependencies modules
121 #:lookup-module lookup))))
122
123 (mkdir #$output)
124 (for-each (lambda (module)
125 (format #t "copying '~a'...~%" module)
126 (copy-file module
127 (string-append #$output "/"
128 (basename module))))
129 (delete-duplicates modules)))))
130
131 (gexp->derivation "linux-modules" build-exp))
132
133 (define* (base-initrd file-systems
134 #:key
135 (linux linux-libre)
136 (mapped-devices '())
137 qemu-networking?
138 (virtio? #t)
139 volatile-root?
140 (extra-modules '()))
141 "Return a monadic derivation that builds a generic initrd, with kernel
142 modules taken from LINUX. FILE-SYSTEMS is a list of file-systems to be
143 mounted by the initrd, possibly in addition to the root file system specified
144 on the kernel command line via '--root'. MAPPED-DEVICES is a list of device
145 mappings to realize before FILE-SYSTEMS are mounted.
146
147 When QEMU-NETWORKING? is true, set up networking with the standard QEMU
148 parameters. When VIRTIO? is true, load additional modules so the initrd can
149 be used as a QEMU guest with the root file system on a para-virtualized block
150 device.
151
152 When VOLATILE-ROOT? is true, the root file system is writable but any changes
153 to it are lost.
154
155 The initrd is automatically populated with all the kernel modules necessary
156 for FILE-SYSTEMS and for the given options. However, additional kernel
157 modules can be listed in EXTRA-MODULES. They will be added to the initrd, and
158 loaded at boot time in the order in which they appear."
159 (define virtio-modules
160 ;; Modules for Linux para-virtualized devices, for use in QEMU guests.
161 '("virtio_pci" "virtio_balloon" "virtio_blk" "virtio_net"
162 "virtio_console"))
163
164 (define cifs-modules
165 ;; Modules needed to mount CIFS file systems.
166 '("md4" "ecb" "cifs"))
167
168 (define virtio-9p-modules
169 ;; Modules for the 9p paravirtualized file system.
170 '("9p" "9pnet_virtio"))
171
172 (define (file-system-type-predicate type)
173 (lambda (fs)
174 (string=? (file-system-type fs) type)))
175
176 (define linux-modules
177 ;; Modules added to the initrd and loaded from the initrd.
178 `("ahci" ;for SATA controllers
179 "usb-storage" "uas" ;for the installation image etc.
180 "usbhid" "hid-generic" "hid-apple" ;keyboards during early boot
181 "dm-crypt" "xts" "serpent_generic" "wp512" ;for encrypted root partitions
182 "nvme" ;for new SSD NVMe devices
183 ,@(if (string-match "^(x86_64|i[3-6]86)-" (%current-system))
184 '("pata_acpi" "pata_atiixp" ;for ATA controllers
185 "isci") ;for SAS controllers like Intel C602
186 '())
187 ,@(if (or virtio? qemu-networking?)
188 virtio-modules
189 '())
190 ,@(if (find (file-system-type-predicate "cifs") file-systems)
191 cifs-modules
192 '())
193 ,@(if (find (file-system-type-predicate "9p") file-systems)
194 virtio-9p-modules
195 '())
196 ,@(if volatile-root?
197 '("fuse")
198 '())
199 ,@extra-modules))
200
201 (define helper-packages
202 ;; Packages to be copied on the initrd.
203 `(,@(if (find (lambda (fs)
204 (string-prefix? "ext" (file-system-type fs)))
205 file-systems)
206 (list e2fsck/static)
207 '())
208 ,@(if volatile-root?
209 (list unionfs-fuse/static)
210 '())))
211
212 (define device-mapping-commands
213 ;; List of gexps to open the mapped devices.
214 (map (lambda (md)
215 (let* ((source (mapped-device-source md))
216 (target (mapped-device-target md))
217 (type (mapped-device-type md))
218 (open (mapped-device-kind-open type)))
219 (open source target)))
220 mapped-devices))
221
222 (mlet %store-monad ((kodir (flat-linux-module-directory linux
223 linux-modules)))
224 (expression->initrd
225 (with-imported-modules (source-module-closure
226 '((gnu build linux-boot)
227 (guix build utils)
228 (guix build bournish)
229 (gnu build file-systems)))
230 #~(begin
231 (use-modules (gnu build linux-boot)
232 (guix build utils)
233 (guix build bournish) ;add the 'bournish' meta-command
234 (srfi srfi-26)
235
236 ;; FIXME: The following modules are for
237 ;; LUKS-DEVICE-MAPPING. We should instead propagate
238 ;; this info via gexps.
239 ((gnu build file-systems)
240 #:select (find-partition-by-luks-uuid))
241 (rnrs bytevectors))
242
243 (with-output-to-port (%make-void-port "w")
244 (lambda ()
245 (set-path-environment-variable "PATH" '("bin" "sbin")
246 '#$helper-packages)))
247
248 (boot-system #:mounts '#$(map file-system->spec file-systems)
249 #:pre-mount (lambda ()
250 (and #$@device-mapping-commands))
251 #:linux-modules '#$linux-modules
252 #:linux-module-directory '#$kodir
253 #:qemu-guest-networking? #$qemu-networking?
254 #:volatile-root? '#$volatile-root?)))
255 #:name "base-initrd")))
256
257 ;;; linux-initrd.scm ends here