linux-initrd.scm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2016 Mark H Weaver <mhw@netris.org>
  4. ;;; Copyright © 2016 Jan Nieuwenhuizen <janneke@gnu.org>
  5. ;;; Copyright © 2017, 2019 Mathieu Othacehe <m.othacehe@gmail.com>
  6. ;;; Copyright © 2019, 2020 Tobias Geerinckx-Rice <me@tobias.gr>
  7. ;;;
  8. ;;; This file is part of GNU Guix.
  9. ;;;
  10. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  11. ;;; under the terms of the GNU General Public License as published by
  12. ;;; the Free Software Foundation; either version 3 of the License, or (at
  13. ;;; your option) any later version.
  14. ;;;
  15. ;;; GNU Guix is distributed in the hope that it will be useful, but
  16. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ;;; GNU General Public License for more details.
  19. ;;;
  20. ;;; You should have received a copy of the GNU General Public License
  21. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  22. (define-module (gnu system linux-initrd)
  23. #:use-module (guix gexp)
  24. #:use-module (guix utils)
  25. #:use-module ((guix store)
  26. #:select (%store-prefix))
  27. #:use-module ((guix derivations)
  28. #:select (derivation->output-path))
  29. #:use-module (guix modules)
  30. #:use-module (gnu packages compression)
  31. #:use-module (gnu packages disk)
  32. #:use-module (gnu packages linux)
  33. #:use-module (gnu packages file-systems)
  34. #:use-module (gnu packages guile)
  35. #:use-module ((gnu packages xorg)
  36. #:select (console-setup xkeyboard-config))
  37. #:use-module ((gnu packages make-bootstrap)
  38. #:select (%guile-static-stripped))
  39. #:use-module (gnu system file-systems)
  40. #:use-module (gnu system mapped-devices)
  41. #:use-module (gnu system keyboard)
  42. #:use-module (ice-9 match)
  43. #:use-module (ice-9 regex)
  44. #:use-module (ice-9 vlist)
  45. #:use-module (srfi srfi-1)
  46. #:use-module (srfi srfi-26)
  47. #:export (expression->initrd
  48. %base-initrd-modules
  49. raw-initrd
  50. file-system-packages
  51. base-initrd))
  52. ;;; Commentary:
  53. ;;;
  54. ;;; Tools to build initial RAM disks (initrd's) for Linux-Libre, and in
  55. ;;; particular initrd's that run Guile.
  56. ;;;
  57. ;;; Code:
  58. (define* (expression->initrd exp
  59. #:key
  60. (guile %guile-static-stripped)
  61. (gzip gzip)
  62. (name "guile-initrd")
  63. (system (%current-system)))
  64. "Return as a file-like object a Linux initrd (a gzipped cpio archive)
  65. containing GUILE and that evaluates EXP, a G-expression, upon booting. All
  66. the derivations referenced by EXP are automatically copied to the initrd."
  67. ;; General Linux overview in `Documentation/early-userspace/README' and
  68. ;; `Documentation/filesystems/ramfs-rootfs-initramfs.txt'.
  69. (define init
  70. (program-file "init" exp #:guile guile))
  71. (define (import-module? module)
  72. ;; Since we don't use deduplication support in 'populate-store', don't
  73. ;; import (guix store deduplication) and its dependencies, which includes
  74. ;; Guile-Gcrypt. That way we can run tests with '--bootstrap'.
  75. (and (guix-module-name? module)
  76. (not (equal? module '(guix store deduplication)))))
  77. (define builder
  78. ;; Do not use "guile-zlib" extension here, otherwise it would drag the
  79. ;; non-static "zlib" package to the initrd closure. It is not needed
  80. ;; anyway because the modules are stored uncompressed within the initrd.
  81. (with-imported-modules (source-module-closure
  82. '((gnu build linux-initrd))
  83. #:select? import-module?)
  84. #~(begin
  85. (use-modules (gnu build linux-initrd))
  86. (mkdir #$output)
  87. ;; The guile used in the initrd must be present in the store, so
  88. ;; that module loading works once the root is switched.
  89. ;;
  90. ;; To ensure that is the case, add an explicit reference to the
  91. ;; guile package used in the initrd to the output.
  92. ;;
  93. ;; This fixes guix-patches bug #28399, "Fix mysql activation, and
  94. ;; add a basic test".
  95. (call-with-output-file (string-append #$ output "/references")
  96. (lambda (port)
  97. (simple-format port "~A\n" #$guile)))
  98. (build-initrd (string-append #$output "/initrd.cpio.gz")
  99. #:guile #$guile
  100. #:init #$init
  101. ;; Copy everything INIT refers to into the initrd.
  102. #:references-graphs '("closure")
  103. #:gzip (string-append #+gzip "/bin/gzip")))))
  104. (file-append (computed-file name builder
  105. #:options
  106. `(#:references-graphs (("closure" ,init))))
  107. "/initrd.cpio.gz"))
  108. (define (flat-linux-module-directory linux modules)
  109. "Return a flat directory containing the Linux kernel modules listed in
  110. MODULES and taken from LINUX."
  111. (define imported-modules
  112. (source-module-closure '((gnu build linux-modules)
  113. (guix build utils))))
  114. (define build-exp
  115. (with-imported-modules imported-modules
  116. (with-extensions (list guile-zlib)
  117. #~(begin
  118. (use-modules (gnu build linux-modules)
  119. (guix build utils)
  120. (srfi srfi-1)
  121. (srfi srfi-26))
  122. (define module-dir
  123. (string-append #$linux "/lib/modules"))
  124. (define modules
  125. (let* ((lookup (cut find-module-file module-dir <>))
  126. (modules (map lookup '#$modules)))
  127. (append modules
  128. (recursive-module-dependencies
  129. modules
  130. #:lookup-module lookup))))
  131. (define (maybe-uncompress file)
  132. ;; If FILE is a compressed module, uncompress it, as the initrd
  133. ;; is already gzipped as a whole.
  134. (cond
  135. ((string-contains file ".ko.gz")
  136. (invoke #+(file-append gzip "/bin/gunzip") file))))
  137. (mkdir #$output)
  138. (for-each (lambda (module)
  139. (let ((out-module
  140. (string-append #$output "/"
  141. (basename module))))
  142. (format #t "copying '~a'...~%" module)
  143. (copy-file module out-module)
  144. (maybe-uncompress out-module)))
  145. (delete-duplicates modules))
  146. ;; Hyphen or underscore? This database tells us.
  147. (write-module-name-database #$output)))))
  148. (computed-file "linux-modules" build-exp))
  149. (define* (raw-initrd file-systems
  150. #:key
  151. (linux linux-libre)
  152. (linux-modules '())
  153. (mapped-devices '())
  154. (keyboard-layout #f)
  155. (helper-packages '())
  156. qemu-networking?
  157. volatile-root?
  158. (on-error 'debug))
  159. "Return as a file-like object a raw initrd, with kernel
  160. modules taken from LINUX. FILE-SYSTEMS is a list of file-systems to be
  161. mounted by the initrd, possibly in addition to the root file system specified
  162. on the kernel command line via '--root'. LINUX-MODULES is a list of kernel
  163. modules to be loaded at boot time. MAPPED-DEVICES is a list of device
  164. mappings to realize before FILE-SYSTEMS are mounted.
  165. HELPER-PACKAGES is a list of packages to be copied in the initrd. It may include
  166. e2fsck/static or other packages needed by the initrd to check root partition.
  167. When true, KEYBOARD-LAYOUT is a <keyboard-layout> record denoting the desired
  168. console keyboard layout. This is done before MAPPED-DEVICES are set up and
  169. before FILE-SYSTEMS are mounted such that, should the user need to enter a
  170. passphrase or use the REPL, this happens using the intended keyboard layout.
  171. When QEMU-NETWORKING? is true, set up networking with the standard QEMU
  172. parameters.
  173. When VOLATILE-ROOT? is true, the root file system is writable but any changes
  174. to it are lost.
  175. ON-ERROR is passed to 'call-with-error-handling'; it determines what happens
  176. upon error."
  177. (define device-mapping-commands
  178. ;; List of gexps to open the mapped devices.
  179. (map (lambda (md)
  180. (let* ((source (mapped-device-source md))
  181. (targets (mapped-device-targets md))
  182. (type (mapped-device-type md))
  183. (open (mapped-device-kind-open type)))
  184. (open source targets)))
  185. mapped-devices))
  186. (define file-system-scan-commands
  187. ;; File systems like btrfs need help to assemble multi-device file systems
  188. ;; but do not use manually-specified <mapped-devices>.
  189. (let ((file-system-types (map file-system-type file-systems)))
  190. (if (member "btrfs" file-system-types)
  191. ;; Ignore errors: if the system manages to boot anyway, the better.
  192. #~((system* (string-append #$btrfs-progs/static "/bin/btrfs")
  193. "device" "scan"))
  194. #~())))
  195. (define kodir
  196. (flat-linux-module-directory linux linux-modules))
  197. (expression->initrd
  198. (with-imported-modules (source-module-closure
  199. '((gnu build linux-boot)
  200. (guix build utils)
  201. (guix build bournish)
  202. (gnu system file-systems)
  203. (gnu build file-systems)))
  204. #~(begin
  205. (use-modules (gnu build linux-boot)
  206. (gnu system file-systems)
  207. ((guix build utils) #:hide (delete))
  208. (guix build bournish) ;add the 'bournish' meta-command
  209. (srfi srfi-1) ;for lvm-device-mapping
  210. (srfi srfi-26)
  211. ;; FIXME: The following modules are for
  212. ;; LUKS-DEVICE-MAPPING. We should instead propagate
  213. ;; this info via gexps.
  214. ((gnu build file-systems)
  215. #:select (find-partition-by-luks-uuid))
  216. (rnrs bytevectors))
  217. (with-output-to-port (%make-void-port "w")
  218. (lambda ()
  219. (set-path-environment-variable "PATH" '("bin" "sbin")
  220. '#$helper-packages)))
  221. (parameterize ((current-warning-port (%make-void-port "w")))
  222. (boot-system #:mounts
  223. (map spec->file-system
  224. '#$(map file-system->spec file-systems))
  225. #:pre-mount (lambda ()
  226. (and #$@device-mapping-commands
  227. #$@file-system-scan-commands))
  228. #:linux-modules '#$linux-modules
  229. #:linux-module-directory '#$kodir
  230. #:keymap-file #+(and=> keyboard-layout
  231. keyboard-layout->console-keymap)
  232. #:qemu-guest-networking? #$qemu-networking?
  233. #:volatile-root? '#$volatile-root?
  234. #:on-error '#$on-error))))
  235. #:name "raw-initrd"))
  236. (define* (file-system-packages file-systems #:key (volatile-root? #f))
  237. "Return the list of statically-linked, stripped packages to check
  238. FILE-SYSTEMS."
  239. `(,@(if (find (lambda (fs)
  240. (string-prefix? "ext" (file-system-type fs)))
  241. file-systems)
  242. (list e2fsck/static)
  243. '())
  244. ,@(if (find (lambda (fs)
  245. (string-suffix? "fat" (file-system-type fs)))
  246. file-systems)
  247. (list fatfsck/static)
  248. '())
  249. ,@(if (find (file-system-type-predicate "bcachefs") file-systems)
  250. (list bcachefs/static)
  251. '())
  252. ,@(if (find (file-system-type-predicate "btrfs") file-systems)
  253. (list btrfs-progs/static)
  254. '())
  255. ,@(if (find (file-system-type-predicate "jfs") file-systems)
  256. (list jfs_fsck/static)
  257. '())
  258. ,@(if (find (file-system-type-predicate "ntfs") file-systems)
  259. (list ntfsfix/static)
  260. '())
  261. ,@(if (find (file-system-type-predicate "f2fs") file-systems)
  262. (list f2fs-fsck/static)
  263. '())
  264. ,@(if (find (file-system-type-predicate "xfs") file-systems)
  265. (list xfs_repair/static)
  266. '())))
  267. (define-syntax vhash ;TODO: factorize
  268. (syntax-rules (=>)
  269. "Build a vhash with the given key/value mappings."
  270. ((_)
  271. vlist-null)
  272. ((_ (key others ... => value) rest ...)
  273. (vhash-cons key value
  274. (vhash (others ... => value) rest ...)))
  275. ((_ (=> value) rest ...)
  276. (vhash rest ...))))
  277. (define-syntax lookup-procedure
  278. (syntax-rules (else)
  279. "Return a procedure that lookups keys in the given dictionary."
  280. ((_ mapping ... (else default))
  281. (let ((table (vhash mapping ...)))
  282. (lambda (key)
  283. (match (vhash-assoc key table)
  284. (#f default)
  285. ((key . value) value)))))))
  286. (define file-system-type-modules
  287. ;; Given a file system type, return the list of modules it needs.
  288. (lookup-procedure ("cifs" => '("md4" "ecb" "cifs"))
  289. ("9p" => '("9p" "9pnet_virtio"))
  290. ("bcachefs" => '("bcachefs"))
  291. ("btrfs" => '("btrfs"))
  292. ("iso9660" => '("isofs"))
  293. ("jfs" => '("jfs"))
  294. ("f2fs" => '("f2fs" "crc32_generic"))
  295. ("xfs" => '("xfs"))
  296. (else '())))
  297. (define (file-system-modules file-systems)
  298. "Return the list of Linux modules needed to mount FILE-SYSTEMS."
  299. (append-map (compose file-system-type-modules file-system-type)
  300. file-systems))
  301. (define* (default-initrd-modules
  302. #:optional
  303. (system (or (%current-target-system)
  304. (%current-system))))
  305. "Return the list of modules included in the initrd by default."
  306. (define virtio-modules
  307. ;; Modules for Linux para-virtualized devices, for use in QEMU guests.
  308. '("virtio_pci" "virtio_balloon" "virtio_blk" "virtio_net"
  309. "virtio_console" "virtio-rng"))
  310. `("ahci" ;for SATA controllers
  311. "usb-storage" "uas" ;for the installation image etc.
  312. "usbhid" "hid-generic" "hid-apple" ;keyboards during early boot
  313. "dm-crypt" "xts" "serpent_generic" "wp512" ;for encrypted root partitions
  314. "nls_iso8859-1" ;for `mkfs.fat`, et.al
  315. ,@(if (string-match "^(x86_64|i[3-6]86)-" system)
  316. '("pata_acpi" "pata_atiixp" ;for ATA controllers
  317. "isci") ;for SAS controllers like Intel C602
  318. '())
  319. ,@virtio-modules))
  320. (define-syntax %base-initrd-modules
  321. ;; This more closely matches our naming convention.
  322. (identifier-syntax (default-initrd-modules)))
  323. (define* (base-initrd file-systems
  324. #:key
  325. (linux linux-libre)
  326. (linux-modules '())
  327. (mapped-devices '())
  328. (keyboard-layout #f)
  329. qemu-networking?
  330. volatile-root?
  331. (extra-modules '()) ;deprecated
  332. (on-error 'debug))
  333. "Return as a file-like object a generic initrd, with kernel
  334. modules taken from LINUX. FILE-SYSTEMS is a list of file-systems to be
  335. mounted by the initrd, possibly in addition to the root file system specified
  336. on the kernel command line via '--root'. MAPPED-DEVICES is a list of device
  337. mappings to realize before FILE-SYSTEMS are mounted.
  338. When true, KEYBOARD-LAYOUT is a <keyboard-layout> record denoting the desired
  339. console keyboard layout. This is done before MAPPED-DEVICES are set up and
  340. before FILE-SYSTEMS are mounted such that, should the user need to enter a
  341. passphrase or use the REPL, this happens using the intended keyboard layout.
  342. QEMU-NETWORKING? and VOLATILE-ROOT? behaves as in raw-initrd.
  343. The initrd is automatically populated with all the kernel modules necessary
  344. for FILE-SYSTEMS and for the given options. Additional kernel
  345. modules can be listed in LINUX-MODULES. They will be added to the initrd, and
  346. loaded at boot time in the order in which they appear."
  347. (define linux-modules*
  348. ;; Modules added to the initrd and loaded from the initrd.
  349. `(,@linux-modules
  350. ,@(file-system-modules file-systems)
  351. ,@(if volatile-root?
  352. '("overlay")
  353. '())
  354. ,@extra-modules))
  355. (define helper-packages
  356. (append (file-system-packages file-systems
  357. #:volatile-root? volatile-root?)
  358. (if keyboard-layout
  359. (list loadkeys-static)
  360. '())))
  361. (raw-initrd file-systems
  362. #:linux linux
  363. #:linux-modules linux-modules*
  364. #:mapped-devices mapped-devices
  365. #:helper-packages helper-packages
  366. #:keyboard-layout keyboard-layout
  367. #:qemu-networking? qemu-networking?
  368. #:volatile-root? volatile-root?
  369. #:on-error on-error))
  370. ;;; linux-initrd.scm ends here