2019-12-24 08:17:14 +03:00
|
|
|
{ config, pkgs, lib, utils, ... }:
|
2019-09-22 05:40:24 +03:00
|
|
|
|
|
|
|
let
|
2019-12-21 08:37:24 +03:00
|
|
|
inherit (pkgs)
|
|
|
|
busybox
|
|
|
|
makeInitrd
|
|
|
|
mkExtraUtils
|
|
|
|
runCommandNoCC
|
|
|
|
udev
|
2019-12-23 22:06:57 +03:00
|
|
|
writeText
|
|
|
|
;
|
|
|
|
inherit (lib)
|
2019-12-24 08:17:14 +03:00
|
|
|
concatMap
|
|
|
|
concatStringsSep
|
|
|
|
filter
|
2019-12-23 22:06:57 +03:00
|
|
|
flatten
|
2019-12-25 03:49:54 +03:00
|
|
|
mkOption
|
2019-12-23 22:06:57 +03:00
|
|
|
optionalString
|
|
|
|
optionals
|
2019-12-25 03:49:54 +03:00
|
|
|
types
|
2019-12-23 22:06:57 +03:00
|
|
|
;
|
|
|
|
inherit (builtins)
|
2019-12-24 08:17:14 +03:00
|
|
|
listToAttrs
|
2019-12-23 22:06:57 +03:00
|
|
|
toJSON
|
2019-12-21 08:37:24 +03:00
|
|
|
;
|
2019-12-23 06:36:17 +03:00
|
|
|
|
|
|
|
initWrapperRealInit = "/actual-init";
|
|
|
|
|
2019-12-23 06:36:48 +03:00
|
|
|
# TODO: define as an option
|
|
|
|
# This is a bit buggy:
|
|
|
|
# * fast burst of \n-delimited output will not work as expected
|
|
|
|
# * `printk.devkmsg=on` is required on the kernel cmdline for better results
|
|
|
|
# A better implementation would be to have a binary who's sole purpose is to
|
|
|
|
# duplicate the stdout/stderr to /dev/kmsg while still outputting them to
|
|
|
|
# stdout/stderr as they do currently.
|
|
|
|
#
|
|
|
|
# Reminder: redirecting to kmsg is useful *mainly* for getting data through
|
|
|
|
# console_ramoops on devices without serial and without any other means to
|
|
|
|
# get the initial data out.
|
|
|
|
withKmsg = false;
|
|
|
|
|
2019-12-23 06:36:17 +03:00
|
|
|
# TODO: define as an option
|
|
|
|
withStrace = false;
|
|
|
|
|
2019-12-23 06:36:48 +03:00
|
|
|
initWrapperEnabled = withKmsg || withStrace;
|
2019-12-21 08:37:24 +03:00
|
|
|
|
2019-09-22 05:40:24 +03:00
|
|
|
device_config = config.mobile.device;
|
2019-12-21 08:37:24 +03:00
|
|
|
device_name = device_config.name;
|
|
|
|
|
2019-09-22 05:40:24 +03:00
|
|
|
stage-1 = config.mobile.boot.stage-1;
|
2019-12-21 08:37:24 +03:00
|
|
|
|
2019-12-25 03:49:54 +03:00
|
|
|
mobile-nixos-init = pkgs.pkgsStatic.callPackage ../boot/init {
|
|
|
|
inherit (config.mobile.boot.stage-1) tasks;
|
|
|
|
};
|
|
|
|
|
2019-12-21 08:37:24 +03:00
|
|
|
init = "${mobile-nixos-init}/bin/init";
|
|
|
|
|
2019-12-23 06:36:17 +03:00
|
|
|
shell = "${extraUtils}/bin/sh";
|
|
|
|
debugInit = pkgs.writeScript "debug-init" ''
|
|
|
|
#!${shell}
|
|
|
|
|
|
|
|
echo
|
|
|
|
echo "***************************************"
|
|
|
|
echo "* Mobile NixOS stage-0 script wrapper *"
|
|
|
|
echo "***************************************"
|
|
|
|
echo
|
|
|
|
|
|
|
|
PS4="=> "
|
|
|
|
set -x
|
|
|
|
|
|
|
|
export LD_LIBRARY_PATH="${extraUtils}/lib"
|
|
|
|
|
2019-12-23 06:36:48 +03:00
|
|
|
${optionalString withKmsg ''
|
|
|
|
${extraUtils}/bin/mknod /.kmsg c 1 11
|
|
|
|
exec > /.kmsg 2>&1
|
|
|
|
''}
|
|
|
|
|
2019-12-23 06:36:17 +03:00
|
|
|
exec ${optionalString withStrace "${extraUtils}/bin/strace -f"} ${initWrapperRealInit}
|
|
|
|
'';
|
|
|
|
|
2019-12-23 22:06:57 +03:00
|
|
|
bootConfig = {
|
|
|
|
device = {
|
|
|
|
inherit (device_config) name;
|
|
|
|
};
|
|
|
|
kernel = {
|
2019-12-24 23:07:38 +03:00
|
|
|
inherit (config.mobile.boot.stage-1.kernel) modules;
|
2019-12-23 22:06:57 +03:00
|
|
|
};
|
|
|
|
|
2019-12-24 05:53:00 +03:00
|
|
|
# Literally transmit some nixos configurations.
|
|
|
|
nixos = {
|
|
|
|
boot.specialFileSystems = config.boot.specialFileSystems;
|
|
|
|
};
|
2019-12-24 08:17:14 +03:00
|
|
|
|
|
|
|
inherit bootFileSystems;
|
2019-12-24 22:17:03 +03:00
|
|
|
|
|
|
|
boot = {
|
|
|
|
inherit (config.mobile.boot.stage-1) fail;
|
|
|
|
};
|
2019-12-23 22:06:57 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
bootConfigFile = writeText "${device_name}-boot-config" (toJSON bootConfig);
|
|
|
|
|
2019-12-21 08:37:24 +03:00
|
|
|
contents =
|
|
|
|
(optionals (stage-1 ? contents) (flatten stage-1.contents))
|
|
|
|
++ [
|
|
|
|
# Populate /bin/sh to stay POSIXLY compliant.
|
2019-12-23 22:08:15 +03:00
|
|
|
{ object = "${extraUtils}/bin/sh"; symlink = "/bin/sh"; }
|
2019-12-21 08:37:24 +03:00
|
|
|
|
2019-12-23 22:06:57 +03:00
|
|
|
# The mostly device-specific configuration for the bootloader.
|
|
|
|
{ object = bootConfigFile; symlink = "/etc/boot/config"; }
|
|
|
|
|
2019-12-21 08:37:24 +03:00
|
|
|
# FIXME: udev/udevRules module.
|
|
|
|
{ object = udevRules; symlink = "/etc/udev/rules.d"; }
|
2019-12-23 06:36:17 +03:00
|
|
|
]
|
|
|
|
++ optionals (!initWrapperEnabled) [
|
2019-12-21 08:37:24 +03:00
|
|
|
{ object = init; symlink = "/init"; }
|
|
|
|
]
|
2019-12-23 06:36:17 +03:00
|
|
|
++ optionals initWrapperEnabled [
|
|
|
|
{ object = init; symlink = initWrapperRealInit; }
|
|
|
|
{ object = debugInit; symlink = "/init"; }
|
|
|
|
]
|
2019-12-21 08:37:24 +03:00
|
|
|
;
|
|
|
|
|
2019-12-24 08:17:14 +03:00
|
|
|
# The initrd only has to mount `/` or any FS marked as necessary for
|
|
|
|
# booting (such as the FS containing `/nix/store`, or an FS needed for
|
|
|
|
# mounting `/`, like `/` on a loopback).
|
|
|
|
bootFileSystems = listToAttrs (map (item: { inherit (item._module.args) name; value = item; })
|
|
|
|
(filter utils.fsNeededForBoot config.system.build.fileSystems)
|
|
|
|
);
|
|
|
|
|
2019-12-21 08:37:24 +03:00
|
|
|
udevRules = runCommandNoCC "udev-rules" {
|
|
|
|
allowedReferences = [ extraUtils ];
|
|
|
|
preferLocalBuild = true;
|
|
|
|
} ''
|
|
|
|
mkdir -p $out
|
|
|
|
|
|
|
|
# These 00-env rules are used both by udev to set the environment, and
|
|
|
|
# by our bespoke init.
|
|
|
|
# This makes it a one-stop-shop for preparing the init environment.
|
|
|
|
echo 'ENV{LD_LIBRARY_PATH}="${extraUtils}/lib"' > $out/00-env.rules
|
|
|
|
echo 'ENV{PATH}="${extraUtils}/bin"' >> $out/00-env.rules
|
|
|
|
|
|
|
|
cp -v ${udev}/lib/udev/rules.d/60-cdrom_id.rules $out/
|
|
|
|
cp -v ${udev}/lib/udev/rules.d/60-persistent-storage.rules $out/
|
|
|
|
cp -v ${udev}/lib/udev/rules.d/80-drivers.rules $out/
|
|
|
|
cp -v ${pkgs.lvm2}/lib/udev/rules.d/*.rules $out/
|
|
|
|
|
|
|
|
for i in $out/*.rules; do
|
|
|
|
substituteInPlace $i \
|
|
|
|
--replace ata_id ${extraUtils}/bin/ata_id \
|
|
|
|
--replace scsi_id ${extraUtils}/bin/scsi_id \
|
|
|
|
--replace cdrom_id ${extraUtils}/bin/cdrom_id \
|
|
|
|
--replace ${pkgs.coreutils}/bin/basename ${extraUtils}/bin/basename \
|
|
|
|
--replace ${pkgs.utillinux}/bin/blkid ${extraUtils}/bin/blkid \
|
|
|
|
--replace ${pkgs.lvm2}/sbin ${extraUtils}/bin \
|
|
|
|
--replace ${pkgs.mdadm}/sbin ${extraUtils}/sbin \
|
|
|
|
--replace ${pkgs.bash}/bin/sh ${extraUtils}/bin/sh \
|
|
|
|
--replace ${udev}/bin/udevadm ${extraUtils}/bin/udevadm
|
|
|
|
done
|
|
|
|
|
|
|
|
# Work around a bug in QEMU, which doesn't implement the "READ
|
|
|
|
# DISC INFORMATION" SCSI command:
|
|
|
|
# https://bugzilla.redhat.com/show_bug.cgi?id=609049
|
|
|
|
# As a result, `cdrom_id' doesn't print
|
|
|
|
# ID_CDROM_MEDIA_TRACK_COUNT_DATA, which in turn prevents the
|
|
|
|
# /dev/disk/by-label symlinks from being created. We need these
|
|
|
|
# in the NixOS installation CD, so use ID_CDROM_MEDIA in the
|
|
|
|
# corresponding udev rules for now. This was the behaviour in
|
|
|
|
# udev <= 154. See also
|
|
|
|
# http://www.spinics.net/lists/hotplug/msg03935.html
|
|
|
|
substituteInPlace $out/60-persistent-storage.rules \
|
|
|
|
--replace ID_CDROM_MEDIA_TRACK_COUNT_DATA ID_CDROM_MEDIA
|
|
|
|
''; # */
|
|
|
|
|
|
|
|
extraUtils = mkExtraUtils {
|
|
|
|
name = "${device_name}-extra-utils";
|
|
|
|
packages = [
|
|
|
|
busybox
|
|
|
|
]
|
2019-12-23 06:36:17 +03:00
|
|
|
++ optionals (stage-1 ? extraUtils) stage-1.extraUtils
|
|
|
|
++ [{
|
2019-12-21 08:37:24 +03:00
|
|
|
package = runCommandNoCC "empty" {} "mkdir -p $out";
|
|
|
|
extraCommand =
|
2019-12-23 06:36:17 +03:00
|
|
|
let
|
|
|
|
inherit (pkgs) udev;
|
|
|
|
in
|
2019-12-21 08:37:24 +03:00
|
|
|
''
|
|
|
|
# Copy udev.
|
|
|
|
copy_bin_and_libs ${udev}/lib/systemd/systemd-udevd
|
|
|
|
copy_bin_and_libs ${udev}/bin/udevadm
|
|
|
|
for BIN in ${udev}/lib/udev/*_id; do
|
|
|
|
copy_bin_and_libs $BIN
|
|
|
|
done
|
|
|
|
''
|
|
|
|
;
|
|
|
|
}]
|
2019-12-23 06:36:17 +03:00
|
|
|
++ optionals withStrace [
|
|
|
|
{
|
|
|
|
package = runCommandNoCC "empty" {} "mkdir -p $out";
|
|
|
|
extraCommand = with pkgs; ''
|
|
|
|
copy_bin_and_libs ${strace}/bin/strace
|
|
|
|
cp -fpv ${glibc.out}/lib/libgcc_s.so* $out/lib
|
|
|
|
'';
|
|
|
|
}
|
|
|
|
]
|
2019-12-21 08:37:24 +03:00
|
|
|
;
|
|
|
|
};
|
|
|
|
|
|
|
|
initrd = makeInitrd {
|
|
|
|
name = "initrd-${device_config.name}";
|
|
|
|
inherit contents;
|
|
|
|
};
|
2019-09-22 05:40:24 +03:00
|
|
|
in
|
2019-12-21 08:37:24 +03:00
|
|
|
{
|
2019-12-25 03:49:54 +03:00
|
|
|
options = {
|
|
|
|
mobile.boot.stage-1.tasks = mkOption {
|
|
|
|
type = with types; listOf (either package path);
|
|
|
|
default = [];
|
|
|
|
internal = true;
|
|
|
|
description = "
|
|
|
|
Add tasks to the boot/init program.
|
|
|
|
The build system for boot/init will `find -iname '*.rb'` the given paths.
|
|
|
|
";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = {
|
|
|
|
system.build.initrd = "${initrd}/initrd";
|
|
|
|
# HACK: as we're using isContainer to bypass some NixOS stuff
|
|
|
|
# See <nixpkgs/nixos/modules/tasks/filesystems.nix>
|
|
|
|
boot.specialFileSystems = {
|
|
|
|
"/sys" = { fsType = "sysfs"; options = [ "nosuid" "noexec" "nodev" ]; };
|
|
|
|
};
|
2019-12-24 05:53:00 +03:00
|
|
|
};
|
2019-12-21 08:37:24 +03:00
|
|
|
}
|