Skip to content

Commit

Permalink
Merge pull request #319422 from jmbaur/systemd-boot-devicetree
Browse files Browse the repository at this point in the history
  • Loading branch information
fpletz authored Aug 6, 2024
2 parents 7acc375 + 22199c7 commit 97ebf11
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class BootSpec:
toplevel: str
specialisations: dict[str, "BootSpec"]
sortKey: str # noqa: N815
devicetree: str | None = None # noqa: N815
initrdSecrets: str | None = None # noqa: N815

@dataclass
Expand Down Expand Up @@ -85,6 +86,7 @@ class DiskEntry:
kernel_params: str | None
machine_id: str | None
sort_key: str
devicetree: str | None

@classmethod
def from_path(cls: Type["DiskEntry"], path: Path) -> "DiskEntry":
Expand All @@ -109,7 +111,9 @@ def from_path(cls: Type["DiskEntry"], path: Path) -> "DiskEntry":
initrd=entry_map["initrd"],
kernel_params=entry_map.get("options"),
machine_id=entry_map.get("machine-id"),
sort_key=entry_map.get("sort_key", "nixos"))
sort_key=entry_map.get("sort_key", "nixos"),
devicetree=entry_map.get("devicetree"),
)
return disk_entry

def write(self, sorted_first: str) -> None:
Expand All @@ -128,7 +132,8 @@ def write(self, sorted_first: str) -> None:
f"initrd {self.initrd}",
f"options {self.kernel_params}" if self.kernel_params is not None else None,
f"machine-id {self.machine_id}" if self.machine_id is not None else None,
f"sort-key {default_sort_key if self.default else self.sort_key}"
f"sort-key {default_sort_key if self.default else self.sort_key}",
f"devicetree {self.devicetree}" if self.devicetree is not None else None,
]

f.write("\n".join(filter(None, boot_entry)))
Expand Down Expand Up @@ -236,10 +241,12 @@ def bootspec_from_json(bootspec_json: dict[str, Any]) -> BootSpec:
specialisations = {k: bootspec_from_json(v) for k, v in specialisations.items()}
systemdBootExtension = bootspec_json.get('org.nixos.systemd-boot', {})
sortKey = systemdBootExtension.get('sortKey', 'nixos')
devicetree = systemdBootExtension.get('devicetree')
return BootSpec(
**bootspec_json['org.nixos.bootspec.v1'],
specialisations=specialisations,
sortKey=sortKey
sortKey=sortKey,
devicetree=devicetree,
)


Expand All @@ -264,6 +271,7 @@ def write_entry(profile: str | None,
bootspec = bootspec.specialisations[specialisation]
kernel = copy_from_file(bootspec.kernel)
initrd = copy_from_file(bootspec.initrd)
devicetree = copy_from_file(bootspec.devicetree) if bootspec.devicetree is not None else None

title = "{name}{profile}{specialisation}".format(
name=DISTRO_NAME,
Expand Down Expand Up @@ -306,6 +314,7 @@ def write_entry(profile: str | None,
machine_id=machine_id,
description=f"Generation {generation} {bootspec.label}, built on {build_date}",
sort_key=bootspec.sortKey,
devicetree=devicetree,
default=current
).write(sorted_first)

Expand Down
14 changes: 14 additions & 0 deletions nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,15 @@ 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 @@ -369,6 +378,10 @@ 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: [
{
assertion = !(hasInfix "/" filename);
Expand Down Expand Up @@ -426,6 +439,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}";
};

system = {
Expand Down
19 changes: 18 additions & 1 deletion nixos/tests/systemd-boot.nix
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,23 @@ rec {
imports = [ common ];
specialisation.something.configuration = {
boot.loader.systemd-boot.sortKey = "something";

# Since qemu will dynamically create a devicetree blob when starting
# up, it is not straight forward to create an export of that devicetree
# blob without knowing before-hand all the flags we would pass to qemu
# (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;
hardware.deviceTree.name = "dummy.dtb";
hardware.deviceTree.package = lib.mkForce (pkgs.runCommand "dummy-devicetree-package" { } ''
mkdir -p $out
cp ${pkgs.emptyFile} $out/dummy.dtb
'');
};
};

testScript = ''
testScript = { nodes, ... }: ''
machine.start()
machine.wait_for_unit("multi-user.target")
Expand All @@ -188,6 +201,10 @@ rec {
machine.succeed(
"grep 'sort-key something' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
)
'' + pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isAarch64 ''
machine.succeed(
"grep 'devicetree .*dummy' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
)
'';
};

Expand Down

0 comments on commit 97ebf11

Please sign in to comment.