summaryrefslogtreecommitdiff
path: root/nongnu/system/linux-initrd.scm
blob: 5f34e7952852b75eb9a236acc9cde581a1efeaa2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
;;; SPDX-License-Identifier: GPL-3.0-or-later
;;; Copyright © 2020 Alex Griffin <a@ajgrf.com>

(define-module (nongnu system linux-initrd)
  #:use-module (gnu system linux-initrd)
  #:use-module (guix gexp)
  #:use-module (guix modules)
  #:use-module (guix utils)
  #:use-module (nongnu packages linux)
  #:use-module (nonguix modules)
  #:export (microcode-initrd))

;; See https://www.kernel.org/doc/Documentation/x86/microcode.txt

(define* (microcode-initrd file-systems
                           #:key
                           (initrd base-initrd)
                           (microcode-packages (list amd-microcode
                                                     intel-microcode))
                           #:allow-other-keys
                           #:rest rest)
  "Build INITRD, extended to include x86 processor microcode from
MICROCODE-PACKAGES."
  (let ((args (strip-keyword-arguments '(#:initrd #:microcode-packages) rest)))
    (combined-initrd (microcode-initrd* microcode-packages)
                     (apply initrd file-systems
                            args))))

(define (microcode-initrd* microcode-packages)
  "Build an uncompressed initrd containing x86 processor microcode from
MICROCODE-PACKAGES, in the format expected by the kernel."
  (define builder
    (with-imported-modules (source-module-closure
                            '((gnu build linux-initrd)
                              (guix build utils)
                              (nonguix build utils))
                            #:select? import-nonguix-module?)
      #~(begin
          (use-modules (gnu build linux-initrd)
                       (guix build utils)
                       (nonguix build utils))

          (let* ((initrd (string-append #$output "/initrd.cpio"))
                 (dest-dir "kernel/x86/microcode")
                 (amd-bin   (string-append dest-dir "/AuthenticAMD.bin"))
                 (intel-bin (string-append dest-dir "/GenuineIntel.bin")))
            (mkdir-p dest-dir)
            (for-each
             (lambda (package)
               (let ((intel-ucode (string-append package
                                                 "/lib/firmware/intel-ucode"))
                     (amd-ucode (string-append package
                                               "/lib/firmware/amd-ucode")))
                 (when (directory-exists? intel-ucode)
                   (concatenate-files (find-files intel-ucode ".*")
                                      intel-bin))
                 (when (directory-exists? amd-ucode)
                   (concatenate-files (find-files amd-ucode
                                                  "^microcode_amd.*\\.bin$")
                                      amd-bin))))
             '#$microcode-packages)

            (mkdir-p #$output)
            (write-cpio-archive initrd "kernel" #:compress? #f)))))

  (file-append (computed-file "microcode-initrd" builder)
               "/initrd.cpio"))

(define (combined-initrd . initrds)
  "Return a combined initrd, the result of concatenating INITRDS.  This relies
on the kernel ability to detect and load multiple initrds archives from a
single file."
  (define builder
    (with-imported-modules (source-module-closure
                            '((guix build utils)
                              (nonguix build utils))
                            #:select? import-nonguix-module?)
      #~(begin
          (use-modules (guix build utils)
                       (nonguix build utils)
                       (srfi srfi-1))

          ;; Use .img suffix since the result is no longer easily inspected by
          ;; standard tools like cpio and gzip.
          ;;
          ;; The initrds may contain "references" files to keep some items
          ;; such as the static guile alive.  Concatenate them in a single,
          ;; top-level references file.
          (let ((initrd (string-append #$output "/initrd.img"))
                (references
                 (filter-map
                  (lambda (initrd)
                    (let ((ref (string-append (dirname initrd)
                                              "/references")))
                      (and (file-exists? ref) ref)))
                  '#$initrds))
                (new-references
                 (string-append #$output "/references")))
            (mkdir-p #$output)
            (concatenate-files '#$initrds initrd)
            (concatenate-files references new-references)))))

  (file-append (computed-file "combined-initrd" builder)
               "/initrd.img"))