diff --git a/nixos/modules/system/boot/loader/raspberrypi/builder.sh b/nixos/modules/system/boot/loader/raspberrypi/builder.sh
index f627d093eafb..8adc8a6a7e11 100644
--- a/nixos/modules/system/boot/loader/raspberrypi/builder.sh
+++ b/nixos/modules/system/boot/loader/raspberrypi/builder.sh
@@ -109,11 +109,15 @@ copyForced $fwdir/bootcode.bin /boot/bootcode.bin
copyForced $fwdir/fixup.dat /boot/fixup.dat
copyForced $fwdir/fixup_cd.dat /boot/fixup_cd.dat
copyForced $fwdir/fixup_db.dat /boot/fixup_db.dat
+copyForced $fwdir/fixup_x.dat /boot/fixup_x.dat
copyForced $fwdir/start.elf /boot/start.elf
copyForced $fwdir/start_cd.elf /boot/start_cd.elf
copyForced $fwdir/start_db.elf /boot/start_db.elf
copyForced $fwdir/start_x.elf /boot/start_x.elf
+# Add the config.txt
+copyForced @configTxt@ /boot/config.txt
+
# Remove obsolete files from /boot and /boot/old.
for fn in /boot/old/*linux* /boot/old/*initrd-initrd* /boot/bcm*.dtb; do
if ! test "${filesCopied[$fn]}" = 1; then
diff --git a/nixos/modules/system/boot/loader/raspberrypi/builder_uboot.nix b/nixos/modules/system/boot/loader/raspberrypi/builder_uboot.nix
new file mode 100644
index 000000000000..47f25a9c2b1b
--- /dev/null
+++ b/nixos/modules/system/boot/loader/raspberrypi/builder_uboot.nix
@@ -0,0 +1,34 @@
+{ config, pkgs, configTxt }:
+
+let
+ cfg = config.boot.loader.raspberryPi;
+ isAarch64 = pkgs.stdenv.isAarch64;
+
+ uboot =
+ if cfg.version == 1 then
+ pkgs.ubootRaspberryPi
+ else if cfg.version == 2 then
+ pkgs.ubootRaspberryPi2
+ else
+ if isAarch64 then
+ pkgs.ubootRaspberryPi3_64bit
+ else
+ pkgs.ubootRaspberryPi3_32bit;
+
+ extlinuxConfBuilder =
+ import ../generic-extlinux-compatible/extlinux-conf-builder.nix {
+ inherit pkgs;
+ };
+in
+pkgs.substituteAll {
+ src = ./builder_uboot.sh;
+ isExecutable = true;
+ inherit (pkgs) bash;
+ path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep];
+ firmware = pkgs.raspberrypifw;
+ inherit uboot;
+ inherit configTxt;
+ inherit extlinuxConfBuilder;
+ version = cfg.version;
+}
+
diff --git a/nixos/modules/system/boot/loader/raspberrypi/builder_uboot.sh b/nixos/modules/system/boot/loader/raspberrypi/builder_uboot.sh
new file mode 100644
index 000000000000..36bf15066274
--- /dev/null
+++ b/nixos/modules/system/boot/loader/raspberrypi/builder_uboot.sh
@@ -0,0 +1,29 @@
+#! @bash@/bin/sh -e
+
+copyForced() {
+ local src="$1"
+ local dst="$2"
+ cp $src $dst.tmp
+ mv $dst.tmp $dst
+}
+
+# Call the extlinux builder
+"@extlinuxConfBuilder@" "$@"
+
+# Add the firmware files
+fwdir=@firmware@/share/raspberrypi/boot/
+copyForced $fwdir/bootcode.bin /boot/bootcode.bin
+copyForced $fwdir/fixup.dat /boot/fixup.dat
+copyForced $fwdir/fixup_cd.dat /boot/fixup_cd.dat
+copyForced $fwdir/fixup_db.dat /boot/fixup_db.dat
+copyForced $fwdir/fixup_x.dat /boot/fixup_x.dat
+copyForced $fwdir/start.elf /boot/start.elf
+copyForced $fwdir/start_cd.elf /boot/start_cd.elf
+copyForced $fwdir/start_db.elf /boot/start_db.elf
+copyForced $fwdir/start_x.elf /boot/start_x.elf
+
+# Add the uboot file
+copyForced @uboot@/u-boot.bin /boot/u-boot-rpi.bin
+
+# Add the config.txt
+copyForced @configTxt@ /boot/config.txt
diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
index f246d04284ca..adf13ce6098c 100644
--- a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
+++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
@@ -5,42 +5,99 @@ with lib;
let
cfg = config.boot.loader.raspberryPi;
- builder = pkgs.substituteAll {
+ builderGeneric = pkgs.substituteAll {
src = ./builder.sh;
isExecutable = true;
inherit (pkgs) bash;
path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep];
firmware = pkgs.raspberrypifw;
version = cfg.version;
+ inherit configTxt;
};
platform = pkgs.stdenv.platform;
+ builderUboot = import ./builder_uboot.nix { inherit config; inherit pkgs; inherit configTxt; };
+
+ builder =
+ if cfg.uboot.enable then
+ "${builderUboot} -g ${toString cfg.uboot.configurationLimit} -t ${timeoutStr} -c"
+ else
+ builderGeneric;
+
+ blCfg = config.boot.loader;
+ timeoutStr = if blCfg.timeout == null then "-1" else toString blCfg.timeout;
+
+ isAarch64 = pkgs.stdenv.isAarch64;
+ optional = pkgs.stdenv.lib.optionalString;
+
+ configTxt =
+ pkgs.writeText "config.txt" (''
+ # U-Boot used to need this to work, regardless of whether UART is actually used or not.
+ # TODO: check when/if this can be removed.
+ enable_uart=1
+
+ # Prevent the firmware from smashing the framebuffer setup done by the mainline kernel
+ # when attempting to show low-voltage or overtemperature warnings.
+ avoid_warnings=1
+ '' + optional isAarch64 ''
+ # Boot in 64-bit mode.
+ arm_control=0x200
+ '' + optional cfg.uboot.enable ''
+ kernel=u-boot-rpi.bin
+ '');
+
in
{
options = {
- boot.loader.raspberryPi.enable = mkOption {
- default = false;
- type = types.bool;
- description = ''
- Whether to create files with the system generations in
- /boot.
- /boot/old will hold files from old generations.
- '';
- };
+ boot.loader.raspberryPi = {
+ enable = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ Whether to create files with the system generations in
+ /boot.
+ /boot/old will hold files from old generations.
+ '';
+ };
- boot.loader.raspberryPi.version = mkOption {
- default = 2;
- type = types.enum [ 1 2 3 ];
- description = ''
- '';
- };
+ version = mkOption {
+ default = 2;
+ type = types.enum [ 1 2 3 ];
+ description = ''
+ '';
+ };
+ uboot = {
+ enable = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ Enable using uboot as bootmanager for the raspberry pi.
+ '';
+ };
+
+ configurationLimit = mkOption {
+ default = 20;
+ example = 10;
+ type = types.int;
+ description = ''
+ Maximum number of configurations in the boot menu.
+ '';
+ };
+
+ };
+ };
};
- config = mkIf config.boot.loader.raspberryPi.enable {
+ config = mkIf cfg.enable {
+ assertions = singleton {
+ assertion = !pkgs.stdenv.isAarch64 || cfg.version == 3;
+ message = "Only Raspberry Pi 3 supports aarch64.";
+ };
+
system.build.installBootLoader = builder;
system.boot.loader.id = "raspberrypi";
system.boot.loader.kernelFile = platform.kernelTarget;