aboutsummaryrefslogtreecommitdiff
path: root/gnu/build
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/build')
-rw-r--r--gnu/build/bootloader.scm37
-rw-r--r--gnu/build/linux-boot.scm107
-rw-r--r--gnu/build/vm.scm44
3 files changed, 178 insertions, 10 deletions
diff --git a/gnu/build/bootloader.scm b/gnu/build/bootloader.scm
new file mode 100644
index 0000000000..d00674dd40
--- /dev/null
+++ b/gnu/build/bootloader.scm
@@ -0,0 +1,37 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu build bootloader)
+ #:use-module (ice-9 binary-ports)
+ #:export (write-file-on-device))
+
+
+;;;
+;;; Writing utils.
+;;;
+
+(define (write-file-on-device file size device offset)
+ "Write SIZE bytes from FILE to DEVICE starting at OFFSET."
+ (call-with-input-file file
+ (lambda (input)
+ (let ((bv (get-bytevector-n input size)))
+ (call-with-output-file device
+ (lambda (output)
+ (seek output offset SEEK_SET)
+ (put-bytevector output bv))
+ #:binary #t)))))
diff --git a/gnu/build/linux-boot.scm b/gnu/build/linux-boot.scm
index 2547f1e0af..4dd740174e 100644
--- a/gnu/build/linux-boot.scm
+++ b/gnu/build/linux-boot.scm
@@ -22,8 +22,11 @@
#:use-module (system repl error-handling)
#:autoload (system repl repl) (start-repl)
#:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-9)
#:use-module (srfi srfi-26)
#:use-module (ice-9 match)
+ #:use-module (ice-9 rdelim)
+ #:use-module (ice-9 regex)
#:use-module (ice-9 ftw)
#:use-module (guix build utils)
#:use-module ((guix build syscalls)
@@ -35,6 +38,7 @@
linux-command-line
find-long-option
make-essential-device-nodes
+ make-static-device-nodes
configure-qemu-networking
bind-mount
@@ -105,6 +109,109 @@ with the given MAJOR number, starting with MINOR."
'block-special #o644 (device-number major (+ minor i)))
(loop (+ i 1)))))
+;; Representation of a /dev node.
+(define-record-type <device-node>
+ (device-node name type major minor module)
+ device-node?
+ (name device-node-name)
+ (type device-node-type)
+ (major device-node-major)
+ (minor device-node-minor)
+ (module device-node-module))
+
+(define (read-static-device-nodes port)
+ "Read from PORT a list of <device-node> written in the format used by
+/lib/modules/*/*.devname files."
+ (let loop ((line (read-line port)))
+ (if (eof-object? line)
+ '()
+ (match (string-split line #\space)
+ (((? (cut string-prefix? "#" <>)) _ ...)
+ (loop (read-line port)))
+ ((module-name device-name device-spec)
+ (let* ((device-parts
+ (string-match "([bc])([0-9][0-9]*):([0-9][0-9]*)"
+ device-spec))
+ (type-string (match:substring device-parts 1))
+ (type (match type-string
+ ("c" 'char-special)
+ ("b" 'block-special)))
+ (major-string (match:substring device-parts 2))
+ (major (string->number major-string 10))
+ (minor-string (match:substring device-parts 3))
+ (minor (string->number minor-string 10)))
+ (cons (device-node device-name type major minor module-name)
+ (loop (read-line port)))))
+ (_
+ (begin
+ (format (current-error-port)
+ "read-static-device-nodes: ignored devname line '~a'~%" line)
+ (loop (read-line port))))))))
+
+(define* (mkdir-p* dir #:optional (mode #o755))
+ "This is a variant of 'mkdir-p' that works around
+<http://bugs.gnu.org/24659> by passing MODE explicitly in each 'mkdir' call."
+ (define absolute?
+ (string-prefix? "/" dir))
+
+ (define not-slash
+ (char-set-complement (char-set #\/)))
+
+ (let loop ((components (string-tokenize dir not-slash))
+ (root (if absolute?
+ ""
+ ".")))
+ (match components
+ ((head tail ...)
+ (let ((path (string-append root "/" head)))
+ (catch 'system-error
+ (lambda ()
+ (mkdir path mode)
+ (loop tail path))
+ (lambda args
+ (if (= EEXIST (system-error-errno args))
+ (loop tail path)
+ (apply throw args))))))
+ (() #t))))
+
+(define (report-system-error name . args)
+ "Report a system error for the file NAME."
+ (let ((errno (system-error-errno args)))
+ (format (current-error-port) "could not create '~a': ~a~%" name
+ (strerror errno))))
+
+;; Catch a system-error, log it and don't die from it.
+(define-syntax-rule (catch-system-error name exp)
+ (catch 'system-error
+ (lambda ()
+ exp)
+ (lambda args
+ (apply report-system-error name args))))
+
+;; Create a device node like the <device-node> passed here on the filesystem.
+(define create-device-node
+ (match-lambda
+ (($ <device-node> xname type major minor module)
+ (let ((name (string-append "/dev/" xname)))
+ (mkdir-p* (dirname name))
+ (catch-system-error name
+ (mknod name type #o600 (device-number major minor)))))))
+
+(define* (make-static-device-nodes linux-release-module-directory)
+ "Create static device nodes required by the given Linux release.
+This is required in order to solve a chicken-or-egg problem:
+The Linux kernel has a feature to autoload modules when a device is first
+accessed.
+And udev has a feature to set the permissions of static nodes correctly
+when it is starting up and also to automatically create nodes when hardware
+is hotplugged. That leaves universal device files which are not linked to
+one specific hardware device. These we have to create."
+ (let ((devname-name (string-append linux-release-module-directory "/"
+ "modules.devname")))
+ (for-each create-device-node
+ (call-with-input-file devname-name
+ read-static-device-nodes))))
+
(define* (make-essential-device-nodes #:key (root "/"))
"Make essential device nodes under ROOT/dev."
;; The hand-made devtmpfs/udev!
diff --git a/gnu/build/vm.scm b/gnu/build/vm.scm
index 20ee12709b..404f324045 100644
--- a/gnu/build/vm.scm
+++ b/gnu/build/vm.scm
@@ -1,7 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016 Christopher Allan Webber <cwebber@dustycloud.org>
-;;; Copyright © 2016 Leo Famulari <leo@famulari.name>
+;;; Copyright © 2016, 2017 Leo Famulari <leo@famulari.name>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2017 Marius Bakke <mbakke@fastmail.com>
;;;
@@ -77,6 +77,7 @@
linux initrd
make-disk-image?
single-file-output?
+ target-arm32?
(disk-image-size (* 100 (expt 2 20)))
(disk-image-format "qcow2")
(references-graphs '()))
@@ -91,6 +92,31 @@ access it via /dev/hda.
REFERENCES-GRAPHS can specify a list of reference-graph files as produced by
the #:references-graphs parameter of 'derivation'."
+
+ (define arch-specific-flags
+ `(;; On ARM, a machine has to be specified. Use "virt" machine to avoid
+ ;; hardware limits imposed by other machines.
+ ,@(if target-arm32? '("-M" "virt") '())
+
+ ;; Only enable kvm if we see /dev/kvm exists. This allows users without
+ ;; hardware virtualization to still use these commands. KVM support is
+ ;; still buggy on some ARM32 boards. Do not use it even if available.
+ ,@(if (and (file-exists? "/dev/kvm")
+ (not target-arm32?))
+ '("-enable-kvm")
+ '())
+ "-append"
+ ;; The serial port name differs between emulated architectures/machines.
+ ,@(if target-arm32?
+ `(,(string-append "console=ttyAMA0 --load=" builder))
+ `(,(string-append "console=ttyS0 --load=" builder)))
+ ;; NIC is not supported on ARM "virt" machine, so use a user mode
+ ;; network stack instead.
+ ,@(if target-arm32?
+ '("-device" "virtio-net-pci,netdev=mynet"
+ "-netdev" "user,id=mynet")
+ '("-net" "nic,model=virtio"))))
+
(when make-disk-image?
(format #t "creating ~a image of ~,2f MiB...~%"
disk-image-format (/ disk-image-size (expt 2 20)))
@@ -113,7 +139,8 @@ the #:references-graphs parameter of 'derivation'."
(unless (zero?
(apply system* qemu "-nographic" "-no-reboot"
"-m" (number->string memory-size)
- "-net" "nic,model=virtio"
+ "-object" "rng-random,filename=/dev/urandom,id=guixsd-vm-rng"
+ "-device" "virtio-rng-pci,rng=guixsd-vm-rng"
"-virtfs"
(string-append "local,id=store_dev,path="
(%store-directory)
@@ -127,15 +154,12 @@ the #:references-graphs parameter of 'derivation'."
builder)
(append
(if make-disk-image?
- `("-drive" ,(string-append "file=" output
- ",if=virtio"))
+ `("-device" "virtio-blk,drive=myhd"
+ "-drive" ,(string-append "if=none,file=" output
+ ",format=" disk-image-format
+ ",id=myhd"))
'())
- ;; Only enable kvm if we see /dev/kvm exists.
- ;; This allows users without hardware virtualization to still
- ;; use these commands.
- (if (file-exists? "/dev/kvm")
- '("-enable-kvm")
- '()))))
+ arch-specific-flags)))
(error "qemu failed" qemu))
;; When MAKE-DISK-IMAGE? is true, the image is in OUTPUT already.