Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ in
let
builderArgs =
"-g ${toString cfg.configurationLimit} -t ${timeoutStr}"
+ lib.optionalString (dtCfg.name != null) " -n ${dtCfg.name}"
+ lib.optionalString config.boot.loader.loadDeviceTree " -n ${dtCfg.name}"
+ lib.optionalString (!cfg.useGenerationDeviceTree) " -r";
installBootLoader = pkgs.writeScript "install-extlinux-conf.sh" (
''
Expand Down
4 changes: 4 additions & 0 deletions nixos/modules/system/boot/loader/grub/grub.nix
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,10 @@ in

environment.systemPackages = mkIf (grub != null) [ grub ];

boot.bootspec.extensions."org.nixos.grub" = {
devicetree = lib.mkIf config.boot.loader.loadDeviceTree "${config.hardware.deviceTree.package}/${config.hardware.deviceTree.name}";
};

boot.loader.grub.extraPrepareConfig = concatStrings (
mapAttrsToList (
fileName: sourcePath:
Expand Down
12 changes: 11 additions & 1 deletion nixos/modules/system/boot/loader/grub/install-grub.pl
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,9 @@ sub GrubFs {
# Setup the graphics stack for bios and efi systems
if [ \"\${grub_platform}\" = \"efi\" ]; then
insmod efi_gop
insmod efi_uga
if [ \"\${grub_cpu}\" = \"i386\" -o \"\${grub_cpu}\" = \"x86_64\"]; then
insmod efi_uga
fi
else
insmod vbe
fi
Expand Down Expand Up @@ -465,6 +467,13 @@ sub addEntry {

my $kernel = copyToKernelsDir(Cwd::abs_path("$path/kernel"));
my $initrd = copyToKernelsDir(Cwd::abs_path("$path/initrd"));
my $json_text = read_file("$path/boot.json");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are already consuming the bootspec file here, it would also make sense to pull the kernel and initrd from here

Copy link
Contributor Author

@qbisi qbisi Oct 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You remind me, i think it is more appropriate we use bootspec "org.nixos.boot" instead of "org.nixos.device-tree" here, as it allows us to include more information (e.g. kernel initrd) in it.
However, this won’t be an easy migration. We still need backward compatibility for generations that currently place the kernel and initrd under $path, and we should warn users when we will drop the backward compatiblity. The same difficulty happen if we want migrate bootspec "org.nixos.systemd-boot".devicetree to "org.nixos.boot".devicetree.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There already exists "org.nixos.bootspec.v1", we can put devicetree information under it.

my $data = decode_json($json_text);
my $devicetree;
if (exists $data->{"org.nixos.grub"} && exists $data->{"org.nixos.grub"}->{devicetree}) {
$devicetree = $data->{"org.nixos.grub"}->{devicetree};
}
my $fdtfile = defined $devicetree ? copyToKernelsDir(Cwd::abs_path("$devicetree")) : undef;

# Include second initrd with secrets
if (-e -x "$path/append-initrd-secrets") {
Expand Down Expand Up @@ -516,6 +525,7 @@ sub addEntry {
}
$conf .= " $extraPerEntryConfig\n" if $extraPerEntryConfig;
$conf .= " multiboot $xen $xenParams\n" if $xen;
$conf .= " devicetree $fdtfile\n" if $fdtfile;
$conf .= " " . ($xen ? "module" : "linux") . " $kernel $kernelParams\n";
$conf .= " " . ($xen ? "module" : "initrd") . " $initrd\n";
$conf .= "}\n\n";
Expand Down
36 changes: 29 additions & 7 deletions nixos/modules/system/boot/loader/loader.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ lib, ... }:
{ config, lib, ... }:

with lib;

Expand All @@ -9,12 +9,34 @@ with lib;
];

options = {
boot.loader.timeout = mkOption {
default = 5;
type = types.nullOr types.int;
description = ''
Timeout (in seconds) until loader boots the default menu item. Use null if the loader menu should be displayed indefinitely.
'';
boot.loader = {
timeout = mkOption {
default = 5;
type = types.nullOr types.int;
description = ''
Timeout (in seconds) until loader boots the default menu item. Use null if the loader menu should be displayed indefinitely.
'';
};
loadDeviceTree = mkOption {
default = with config.hardware.deviceTree; enable && name != null;
defaultText = ''with config.hardware.deviceTree; enable && name != null'';
description = ''
Load the devicetree blob specified by `config.hardware.deviceTree.name`
and instruct bootloader to pass this DTB to linux.
'';
};
};
};

config = {
assertions = [
{
assertion =
config.boot.loader.loadDeviceTree
-> config.hardware.deviceTree.enable
-> config.hardware.deviceTree.name != null;
message = "Cannot load devicetree without 'config.hardware.deviceTree.enable' enabled and 'config.hardware.deviceTree.name' set";
}
];
};
}
31 changes: 14 additions & 17 deletions nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,19 @@ in
]
(config: lib.strings.removeSuffix ".conf" config.boot.loader.systemd-boot.netbootxyz.entryFilename)
)
(mkRenamedOptionModule
[
"boot"
"loader"
"systemd-boot"
"installDeviceTree"
]
[
"boot"
"loader"
"loadDeviceTree"
]
)
];

options.boot.loader.systemd-boot = {
Expand Down Expand Up @@ -244,15 +257,6 @@ in
'';
};

installDeviceTree = mkOption {
default = with config.hardware.deviceTree; enable && name != null;
defaultText = ''with config.hardware.deviceTree; enable && name != null'';
description = ''
Install the devicetree blob specified by `config.hardware.deviceTree.name`
to the ESP and instruct systemd-boot to pass this DTB to linux.
'';
};

extraInstallCommands = mkOption {
default = "";
example = ''
Expand Down Expand Up @@ -535,13 +539,6 @@ in
assertion = (config.boot.kernelPackages.kernel.features or { efiBootStub = true; }) ? efiBootStub;
message = "This kernel does not support the EFI boot stub";
}
{
assertion =
cfg.installDeviceTree
-> config.hardware.deviceTree.enable
-> config.hardware.deviceTree.name != null;
message = "Cannot install devicetree without 'config.hardware.deviceTree.enable' enabled and 'config.hardware.deviceTree.name' set";
}
]
++ concatMap (filename: [
{
Expand Down Expand Up @@ -626,7 +623,7 @@ in

boot.bootspec.extensions."org.nixos.systemd-boot" = {
inherit (config.boot.loader.systemd-boot) sortKey;
devicetree = lib.mkIf cfg.installDeviceTree "${config.hardware.deviceTree.package}/${config.hardware.deviceTree.name}";
devicetree = lib.mkIf config.boot.loader.loadDeviceTree "${config.hardware.deviceTree.package}/${config.hardware.deviceTree.name}";
};

system = {
Expand Down
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ in
dendrite = runTest ./matrix/dendrite.nix;
dep-scan = runTest ./dep-scan.nix;
dependency-track = runTest ./dependency-track.nix;
device-tree = import ./device-tree.nix { inherit pkgs runTestOn; };
devpi-server = runTest ./devpi-server.nix;
dex-oidc = runTest ./dex-oidc.nix;
dhparams = runTest ./dhparams.nix;
Expand Down
80 changes: 80 additions & 0 deletions nixos/tests/device-tree.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{
pkgs,
runTestOn,
}:

let
supportedSystems = [
"aarch64-linux"
];
common =
{
config,
lib,
pkgs,
...
}:
let
inherit (pkgs.stdenv.hostPlatform) qemuArch;
in
{
virtualisation.useBootLoader = true;
virtualisation.useEFIBoot = true;

hardware.deviceTree = {
name = "qemu-${qemuArch}-virt.dtb";
package = lib.mkForce (
pkgs.runCommand "qemu-dtb" { } ''
mkdir $out
${pkgs.qemu}/bin/qemu-system-${qemuArch} \
-cpu max -machine virt,gic-version=max,accel=kvm:tcg,dumpdtb=$out/${config.hardware.deviceTree.name}
''
);
};
};
testScript =
{ nodes, ... }:
''
machine.start()
machine.wait_for_unit("multi-user.target")

machine.succeed("grep 'linux,dummy-virt' /sys/firmware/devicetree/base/model")
'';
in

{
systemd-boot = runTestOn supportedSystems {
name = "device-tree-systemd-boot";
meta.maintainers = with pkgs.lib.maintainers; [
qbisi
];

nodes.machine = {
imports = [ common ];

boot.loader.systemd-boot.enable = true;
};

inherit testScript;
};

grub = runTestOn supportedSystems {
name = "device-tree-grub";
meta.maintainers = with pkgs.lib.maintainers; [
qbisi
];

nodes.machine = {
imports = [ common ];

boot.loader.grub = {
enable = true;
device = "nodev";
efiSupport = true;
efiInstallAsRemovable = true;
};
};

inherit testScript;
};
}
2 changes: 1 addition & 1 deletion nixos/tests/systemd-boot.nix
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ in
# (we would then be able to use `dumpdtb`). Thus, the following config
# will not boot, but it does allow us to assert that the boot entry has
# the correct contents.
boot.loader.systemd-boot.installDeviceTree = pkgs.stdenv.hostPlatform.isAarch64;
boot.loader.loadDeviceTree = pkgs.stdenv.hostPlatform.isAarch64;
hardware.deviceTree.name = "dummy.dtb";
hardware.deviceTree.package = lib.mkForce (
pkgs.runCommand "dummy-devicetree-package" { } ''
Expand Down
Loading