image: Add rock64 support.
[jackhill/guix/guix.git] / gnu / system / vm.scm
index 2e82e12..d7ae048 100644 (file)
   #:export (expression->derivation-in-linux-vm
             qemu-image
             virtualized-operating-system
-            system-qemu-image
 
             system-qemu-image/shared-store
             system-qemu-image/shared-store-script
-            system-disk-image-in-vm
             system-docker-image
 
             virtual-machine
 
 (define* (expression->derivation-in-linux-vm name exp
                                              #:key
-                                             (system (%current-system)) target
+                                             (system (%current-system))
                                              (linux linux-libre)
                                              initrd
                                              (qemu qemu-minimal)
@@ -199,6 +197,10 @@ substitutable."
                       (sync)
                       (reboot))))
 
+  (define-syntax-rule (check predicate)
+    (let-system (system target)
+      (predicate (or target system))))
+
   (let ((initrd (or initrd
                     (base-initrd file-systems
                                  #:on-error 'backtrace
@@ -220,16 +222,24 @@ substitutable."
               (use-modules (guix build utils)
                            (gnu build vm))
 
+              ;; Allow non-ASCII file names--e.g., 'nss-certs'--to be decoded
+              ;; by 'estimated-partition-size' below.
+              (setenv "GUIX_LOCPATH"
+                      #+(file-append glibc-utf8-locales "/lib/locale"))
+              (setlocale LC_ALL "en_US.utf8")
+
               (let* ((native-inputs
                       '#+(list qemu (canonical-package coreutils)))
-                     (linux   (string-append #$linux "/"
-                                             #$(system-linux-image-file-name)))
-                     (initrd  #$initrd)
-                     (loader  #$loader)
+                     (linux   (string-append
+                               #+linux "/"
+                               #+(system-linux-image-file-name system)))
+                     (initrd  #+initrd)
+                     (loader  #+loader)
                      (graphs  '#$(match references-graphs
                                    (((graph-files . _) ...) graph-files)
                                    (_ #f)))
-                     (target  #$(or (%current-target-system) (%current-system)))
+                     (target  #$(let-system (system target)
+                                  (or target system)))
                      (size    #$(if (eq? 'guess disk-image-size)
                                     #~(+ (* 70 (expt 2 20)) ;ESP
                                          (estimated-partition-size graphs))
@@ -244,12 +254,6 @@ substitutable."
                                   #:memory-size #$memory-size
                                   #:make-disk-image? #$make-disk-image?
                                   #:single-file-output? #$single-file-output?
-                                  ;; FIXME: ‘target-arm32?’ and
-                                  ;; ‘target-aarch64?’ may not operate on the
-                                  ;; right system/target values.  Rewrite
-                                  ;; using ‘let-system’ when available.
-                                  #:target-arm32? #$(target-arm32?)
-                                  #:target-aarch64? #$(target-aarch64?)
                                   #:disk-image-format #$disk-image-format
                                   #:disk-image-size size
                                   #:references-graphs graphs))))))
@@ -257,7 +261,7 @@ substitutable."
     (gexp->derivation name builder
                       ;; TODO: Require the "kvm" feature.
                       #:system system
-                      #:target target
+                      #:target #f             ;EXP is always executed natively
                       #:env-vars env-vars
                       #:guile-for-build guile-for-build
                       #:references-graphs references-graphs
@@ -277,6 +281,9 @@ substitutable."
                      (disk-image-size 'guess)
                      (disk-image-format "qcow2")
                      (file-system-type "ext4")
+                     (file-system-options '())
+                     (device-nodes 'linux)
+                     (extra-directives '())
                      file-system-label
                      file-system-uuid
                      os
@@ -290,7 +297,8 @@ substitutable."
 'qcow2' or 'raw'), with a root partition of type FILE-SYSTEM-TYPE.
 Optionally, FILE-SYSTEM-LABEL can be specified as the volume name for the root
 partition; likewise FILE-SYSTEM-UUID, if true, specifies the UUID of the root
-partition (a UUID object).
+partition (a UUID object).  FILE-SYSTEM-OPTIONS is an optional list of
+command-line options passed to 'mkfs.ext4' (or similar).
 
 The returned image is a full disk image that runs OS-DERIVATION,
 with a GRUB installation that uses GRUB-CONFIGURATION as its configuration
@@ -301,17 +309,39 @@ all of INPUTS into the image being built.  When REGISTER-CLOSURES? is true,
 register INPUTS in the store database of the image so that Guix can be used in
 the image.  By default, REGISTER-CLOSURES? is set to true only if a service of
 type GUIX-SERVICE-TYPE is present in the services definition of the operating
-system."
+system.
+
+When DEVICE-NODES is 'linux, create Linux-device block and character devices
+under /dev.  When it is 'hurd, do Hurdish things.
+
+EXTRA-DIRECTIVES is an optional list of directives to populate the root file
+system that is passed to 'populate-root-file-system'."
   (define schema
     (and register-closures?
          (local-file (search-path %load-path
                                   "guix/store/schema.sql"))))
 
+  (define preserve-target
+    (if target
+        (lambda (obj)
+          (with-parameters ((%current-target-system target))
+            obj))
+        identity))
+
+  (define inputs*
+    (map (match-lambda
+           ((name thing)
+            `(,name ,(preserve-target thing)))
+           ((name thing output)
+            `(,name ,(preserve-target thing) ,output)))
+         inputs))
+
   (expression->derivation-in-linux-vm
    name
    (with-extensions gcrypt-sqlite3&co
      (with-imported-modules `(,@(source-module-closure '((gnu build vm)
                                                          (gnu build bootloader)
+                                                         (gnu build hurd-boot)
                                                          (guix store database)
                                                          (guix build utils))
                                                        #:select? not-config?)
@@ -319,6 +349,10 @@ system."
        #~(begin
            (use-modules (gnu build bootloader)
                         (gnu build vm)
+                        ((gnu build hurd-boot)
+                         #:select (make-hurd-device-nodes))
+                        ((gnu build linux-boot)
+                         #:select (make-essential-device-nodes))
                         (guix store database)
                         (guix build utils)
                         (srfi srfi-26)
@@ -332,7 +366,7 @@ system."
            (setlocale LC_ALL "en_US.utf8")
 
            (let ((inputs
-                  '#$(append (list parted e2fsprogs dosfstools)
+                  '#+(append (list parted e2fsprogs dosfstools)
                              (map canonical-package
                                   (list sed grep coreutils findutils gawk))))
 
@@ -342,7 +376,7 @@ system."
                   '#$(map (match-lambda
                             ((name thing) thing)
                             ((name thing output) `(,thing ,output)))
-                          inputs)))
+                          inputs*)))
 
              (set-path-environment-variable "PATH" '("bin" "sbin") inputs)
 
@@ -350,10 +384,16 @@ system."
                                      (((names . _) ...)
                                       names)))
                     (initialize (root-partition-initializer
+                                 #:extra-directives '#$extra-directives
                                  #:closures graphs
                                  #:copy-closures? #$copy-inputs?
                                  #:register-closures? #$register-closures?
-                                 #:system-directory #$os
+                                 #:system-directory #$(preserve-target os)
+
+                                 #:make-device-nodes
+                                 #$(match device-nodes
+                                     ('linux #~make-essential-device-nodes)
+                                     ('hurd #~make-hurd-device-nodes))
 
                                  ;; Disable deduplication to speed things up,
                                  ;; and because it doesn't help much for a
@@ -376,6 +416,7 @@ system."
                              (uuid #$(and=> file-system-uuid
                                             uuid-bytevector))
                              (file-system #$file-system-type)
+                             (file-system-options '#$file-system-options)
                              (flags '(boot))
                              (initializer initialize)))
                       ;; Append a small EFI System Partition for use with UEFI
@@ -402,18 +443,17 @@ system."
                                      #:partitions partitions
                                      #:grub-efi grub-efi
                                      #:bootloader-package
-                                     #$(bootloader-package bootloader)
-                                     #:bootcfg #$bootcfg-drv
+                                     #+(bootloader-package bootloader)
+                                     #:bootcfg #$(preserve-target bootcfg-drv)
                                      #:bootcfg-location
                                      #$(bootloader-configuration-file bootloader)
                                      #:bootloader-installer
-                                     #$(bootloader-installer bootloader)))))))
+                                     #+(bootloader-installer bootloader)))))))
    #:system system
-   #:target target
    #:make-disk-image? #t
    #:disk-image-size disk-image-size
    #:disk-image-format disk-image-format
-   #:references-graphs inputs
+   #:references-graphs inputs*
    #:substitutable? substitutable?))
 
 (define* (system-docker-image os
@@ -517,129 +557,6 @@ the operating system."
      #:references-graphs `((,graph ,os)))))
 
 \f
-;;;
-;;; VM and disk images.
-;;;
-
-(define* (system-disk-image-in-vm os
-                                  #:key
-                                  (name "disk-image")
-                                  (file-system-type "ext4")
-                                  (disk-image-size (* 900 (expt 2 20)))
-                                  (volatile? #t)
-                                  (substitutable? #t))
-  "Return the derivation of a disk image of DISK-IMAGE-SIZE bytes of the
-system described by OS.  Said image can be copied on a USB stick as is.  When
-VOLATILE? is true, the root file system is made volatile; this is useful
-to USB sticks meant to be read-only.
-
-SUBSTITUTABLE? determines whether the returned derivation should be marked as
-substitutable."
-  (define root-label
-    "Guix_image")
-
-  (define (root-uuid os)
-    ;; UUID of the root file system, computed in a deterministic fashion.
-    ;; This is what we use to locate the root file system so it has to be
-    ;; different from the user's own file system UUIDs.
-    (operating-system-uuid os 'dce))
-
-  (define file-systems-to-keep
-    (remove (lambda (fs)
-              (string=? (file-system-mount-point fs) "/"))
-            (operating-system-file-systems os)))
-
-  (let* ((os (operating-system (inherit os)
-               ;; Since this is meant to be used on real hardware, don't
-               ;; install QEMU networking or anything like that.  Assume USB
-               ;; mass storage devices (usb-storage.ko) are available.
-               (initrd (lambda (file-systems . rest)
-                         (apply (operating-system-initrd os)
-                                file-systems
-                                #:volatile-root? volatile?
-                                rest)))
-
-               (bootloader (operating-system-bootloader os))
-
-               ;; Force our own root file system.  (We need a "/" file system
-               ;; to call 'root-uuid'.)
-               (file-systems (cons (file-system
-                                     (mount-point "/")
-                                     (device "/dev/placeholder")
-                                     (type file-system-type))
-                                   file-systems-to-keep))))
-         (uuid (root-uuid os))
-         (os (operating-system
-               (inherit os)
-               (file-systems (cons (file-system
-                                     (mount-point "/")
-                                     (device uuid)
-                                     (type file-system-type))
-                                   file-systems-to-keep))))
-        (bootcfg (operating-system-bootcfg os)))
-    (qemu-image #:name name
-                #:os os
-                #:bootcfg-drv bootcfg
-                #:bootloader (bootloader-configuration-bootloader
-                              (operating-system-bootloader os))
-                #:disk-image-size disk-image-size
-                #:disk-image-format "raw"
-                #:file-system-type file-system-type
-                #:file-system-label root-label
-                #:file-system-uuid uuid
-                #:copy-inputs? #t
-                #:inputs `(("system" ,os)
-                           ("bootcfg" ,bootcfg))
-                #:substitutable? substitutable?)))
-
-(define* (system-qemu-image os
-                            #:key
-                            (file-system-type "ext4")
-                            (disk-image-size (* 900 (expt 2 20))))
-  "Return the derivation of a freestanding QEMU image of DISK-IMAGE-SIZE bytes
-of the GNU system as described by OS."
-  (define file-systems-to-keep
-    ;; Keep only file systems other than root and not normally bound to real
-    ;; devices.
-    (remove (lambda (fs)
-              (let ((target (file-system-mount-point fs))
-                    (source (file-system-device fs)))
-                (or (string=? target "/")
-                    (string-prefix? "/dev/" source))))
-            (operating-system-file-systems os)))
-
-  (define root-uuid
-    ;; UUID of the root file system.
-    (operating-system-uuid os
-                           (if (string=? file-system-type "iso9660")
-                               'iso9660
-                               'dce)))
-
-
-  (let* ((os (operating-system (inherit os)
-               ;; Assume we have an initrd with the whole QEMU shebang.
-
-               ;; Force our own root file system.  Refer to it by UUID so that
-               ;; it works regardless of how the image is used ("qemu -hda",
-               ;; Xen, etc.).
-               (file-systems (cons (file-system
-                                     (mount-point "/")
-                                     (device root-uuid)
-                                     (type file-system-type))
-                                   file-systems-to-keep))))
-         (bootcfg (operating-system-bootcfg os)))
-    (qemu-image  #:os os
-                 #:bootcfg-drv bootcfg
-                 #:bootloader (bootloader-configuration-bootloader
-                               (operating-system-bootloader os))
-                 #:disk-image-size disk-image-size
-                 #:file-system-type file-system-type
-                 #:file-system-uuid root-uuid
-                 #:inputs `(("system" ,os)
-                            ("bootcfg" ,bootcfg))
-                 #:copy-inputs? #t)))
-
-\f
 ;;;
 ;;; VMs that share file systems with the host.
 ;;;
@@ -663,7 +580,8 @@ of the GNU system as described by OS."
        (device (file-system->mount-tag source))
        (type "9p")
        (flags (if writable? '() '(read-only)))
-       (options "trans=virtio,cache=loose")
+       (options (string-append "trans=virtio"
+                               (if writable? "" ",cache=loose")))
        (check? #f)
        (create-mount-point? #t)))))
 
@@ -730,6 +648,8 @@ environment with the store shared with the host.  MAPPINGS is a list of
 (define* (system-qemu-image/shared-store
           os
           #:key
+          (system (%current-system))
+          (target (%current-target-system))
           full-boot?
           (disk-image-size (* (if full-boot? 500 30) (expt 2 20))))
   "Return a derivation that builds a QEMU image of OS that shares its store
@@ -750,6 +670,8 @@ bootloader refers to: OS kernel, initrd, bootloader data, etc."
   ;; This is more than needed (we only need the kernel, initrd, GRUB for its
   ;; font, and the background image), but it's hard to filter that.
   (qemu-image #:os os
+              #:system system
+              #:target target
               #:bootcfg-drv bootcfg
               #:bootloader (bootloader-configuration-bootloader
                             (operating-system-bootloader os))
@@ -779,7 +701,6 @@ with '-virtfs' options for the host file systems listed in SHARED-FS."
             '())
 
      "-no-reboot"
-     "-nic" "user,model=virtio-net-pci"
      "-object" "rng-random,filename=/dev/urandom,id=guixsd-vm-rng"
      "-device" "virtio-rng-pci,rng=guixsd-vm-rng"
 
@@ -790,6 +711,8 @@ with '-virtfs' options for the host file systems listed in SHARED-FS."
 
 (define* (system-qemu-image/shared-store-script os
                                                 #:key
+                                                (system (%current-system))
+                                                (target (%current-target-system))
                                                 (qemu qemu)
                                                 (graphic? #t)
                                                 (memory-size 256)
@@ -813,6 +736,8 @@ it is mostly useful when FULL-BOOT?  is true."
   (mlet* %store-monad ((os ->  (virtualized-operating-system os mappings full-boot?))
                        (image  (system-qemu-image/shared-store
                                 os
+                                #:system system
+                                #:target target
                                 #:full-boot? full-boot?
                                 #:disk-image-size disk-image-size)))
     (define kernel-arguments
@@ -820,7 +745,8 @@ it is mostly useful when FULL-BOOT?  is true."
               #+@(operating-system-kernel-arguments os "/dev/vda1")))
 
     (define qemu-exec
-      #~(list (string-append #$qemu "/bin/" #$(qemu-command (%current-system)))
+      #~(list #+(file-append qemu "/bin/"
+                             (qemu-command (or target system)))
               #$@(if full-boot?
                      #~()
                      #~("-kernel" #$(operating-system-kernel-file os)
@@ -837,7 +763,7 @@ it is mostly useful when FULL-BOOT?  is true."
       #~(call-with-output-file #$output
           (lambda (port)
             (format port "#!~a~% exec ~a \"$@\"~%"
-                    #$(file-append bash "/bin/sh")
+                    #+(file-append bash "/bin/sh")
                     (string-join #$qemu-exec " "))
             (chmod port #o555))))
 
@@ -886,10 +812,11 @@ FORWARDINGS is a list of host-port/guest-port pairs."
 
 (define-gexp-compiler (virtual-machine-compiler (vm <virtual-machine>)
                                                 system target)
-  ;; XXX: SYSTEM and TARGET are ignored.
   (match vm
     (($ <virtual-machine> os qemu graphic? memory-size disk-image-size ())
      (system-qemu-image/shared-store-script os
+                                            #:system system
+                                            #:target target
                                             #:qemu qemu
                                             #:graphic? graphic?
                                             #:memory-size memory-size
@@ -902,6 +829,8 @@ FORWARDINGS is a list of host-port/guest-port pairs."
                        "user,model=virtio-net-pci,"
                        (port-forwardings->qemu-options forwardings)))))
        (system-qemu-image/shared-store-script os
+                                              #:system system
+                                              #:target target
                                               #:qemu qemu
                                               #:graphic? graphic?
                                               #:memory-size memory-size