Merge pull request #31 from nix-community/aarch64

This commit is contained in:
Ryan Lahfa 2023-09-29 02:41:12 +02:00 committed by GitHub
commit 644dc8a269
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 147 additions and 22 deletions

View File

@ -106,11 +106,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1689951833,
"narHash": "sha256-wdpIgb5X0p85RRne74TeUOp9ti7a1k9KDSe4NzsaAGk=",
"lastModified": 1695859332,
"narHash": "sha256-w2a7NW3VtI5FgFPUKslYRGAj5Qb7y4i0I2QO0S/lBMQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ebf4e87429ce7faa51a86a36a7b2e615c8bcc735",
"rev": "248a83fffc10b627da67fa6b25d2c13fc7542628",
"type": "github"
},
"original": {

View File

@ -74,11 +74,12 @@
"x86_64-linux"
# Not actively tested, but may work:
# "aarch64-linux"
"aarch64-linux"
];
perSystem = { config, system, pkgs, ... }:
let
rustTarget = "${pkgs.hostPlatform.qemuArch}-unknown-uefi";
pkgs = import nixpkgs {
system = system;
overlays = [
@ -89,7 +90,7 @@
inherit (pkgs) lib;
uefi-rust-stable = pkgs.rust-bin.fromRustupToolchainFile ./rust/uefi/rust-toolchain.toml;
craneLib = crane.lib.x86_64-linux.overrideToolchain uefi-rust-stable;
craneLib = crane.lib.${system}.overrideToolchain uefi-rust-stable;
# Build attributes for a Rust application.
buildRustApp = lib.makeOverridable (
@ -145,7 +146,7 @@
stubCrane = buildRustApp {
pname = "lanzaboote-stub";
src = craneLib.cleanCargoSource ./rust/uefi;
target = "x86_64-unknown-uefi";
target = rustTarget;
doCheck = false;
};
@ -234,6 +235,7 @@
let
systemdUkify = pkgs.systemdMinimal.override {
withEfi = true;
withBootloader = true;
withUkify = true;
};
in

View File

@ -103,7 +103,10 @@ in
${sbctlWithPki}/bin/sbctl enroll-keys --yes-this-might-brick-my-machine
''}
# Use the system from the kernel's hostPlatform because this should
# always, even in the cross compilation case, be the right system.
${cfg.package}/bin/lzbt install \
--system ${config.boot.kernelPackages.stdenv.hostPlatform.system} \
--systemd ${config.systemd.package} \
--systemd-boot-loader-config ${loaderConfigFile} \
--public-key ${cfg.publicKeyFile} \

View File

@ -0,0 +1,35 @@
use std::path::PathBuf;
use anyhow::{bail, Result};
/// Supported system
#[non_exhaustive]
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Architecture {
X86,
AArch64,
}
impl Architecture {
pub fn efi_representation(&self) -> &str {
match self {
Self::X86 => "x64",
Self::AArch64 => "aa64",
}
}
pub fn efi_fallback_filename(&self) -> PathBuf {
format!("BOOT{}.EFI", self.efi_representation().to_ascii_uppercase()).into()
}
}
impl Architecture {
/// Converts from a NixOS system double to a supported system
pub fn from_nixos_system(system_double: &str) -> Result<Self> {
Ok(match system_double {
"x86_64-linux" => Self::X86,
"aarch64-linux" => Self::AArch64,
_ => bail!(format!("Unsupported NixOS system: {}.", system_double)),
})
}
}

View File

@ -3,14 +3,16 @@ use std::{
path::{Path, PathBuf},
};
use anyhow::{Context, Result};
use anyhow::{bail, Context, Result};
use indoc::indoc;
use crate::architecture::Architecture;
use crate::generation::Generation;
/// Generic ESP paths which can be specific to a bootloader
pub trait EspPaths<const N: usize> {
/// Build an ESP path structure out of the ESP root directory
fn new(esp: impl AsRef<Path>) -> Self;
fn new(esp: impl AsRef<Path>, arch: Architecture) -> Self;
/// Return the used file paths to store as garbage collection roots.
fn iter(&self) -> std::array::IntoIter<&PathBuf, N>;
@ -33,8 +35,17 @@ impl EspGenerationPaths {
pub fn new<const N: usize, P: EspPaths<N>>(
esp_paths: &P,
generation: &Generation,
system: Architecture,
) -> Result<Self> {
let bootspec = &generation.spec.bootspec.bootspec;
let bootspec_system: Architecture = Architecture::from_nixos_system(&bootspec.system)?;
if system != bootspec_system {
bail!(indoc! {r#"
The CPU architecture declared in your module differs from the one declared in the
bootspec of the current generation.
"#})
}
Ok(Self {
kernel: esp_paths

View File

@ -1,3 +1,4 @@
pub mod architecture;
pub mod esp;
pub mod gc;
pub mod generation;

View File

@ -0,0 +1,19 @@
use std::path::PathBuf;
use lanzaboote_tool::architecture::Architecture;
/// Systemd-specific architecture helpers
pub trait SystemdArchitectureExt {
fn systemd_stub_filename(&self) -> PathBuf;
fn systemd_filename(&self) -> PathBuf;
}
impl SystemdArchitectureExt for Architecture {
fn systemd_stub_filename(&self) -> PathBuf {
format!("linux{}.efi.stub", self.efi_representation()).into()
}
fn systemd_filename(&self) -> PathBuf {
format!("systemd-boot{}.efi", self.efi_representation()).into()
}
}

View File

@ -4,6 +4,7 @@ use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use crate::install;
use lanzaboote_tool::architecture::Architecture;
use lanzaboote_tool::signature::KeyPair;
/// The default log level.
@ -30,6 +31,10 @@ enum Commands {
#[derive(Parser)]
struct InstallCommand {
/// System for lanzaboote binaries, e.g. defines the EFI fallback path
#[arg(long)]
system: String,
/// Systemd path
#[arg(long)]
systemd: PathBuf,
@ -90,6 +95,7 @@ fn install(args: InstallCommand) -> Result<()> {
install::Installer::new(
PathBuf::from(lanzaboote_stub),
Architecture::from_nixos_system(&args.system)?,
args.systemd,
args.systemd_boot_loader_config,
key_pair,

View File

@ -1,5 +1,7 @@
use std::path::{Path, PathBuf};
use crate::architecture::SystemdArchitectureExt;
use lanzaboote_tool::architecture::Architecture;
use lanzaboote_tool::esp::EspPaths;
/// Paths to the boot files that are not specific to a generation.
@ -18,7 +20,7 @@ pub struct SystemdEspPaths {
}
impl EspPaths<10> for SystemdEspPaths {
fn new(esp: impl AsRef<Path>) -> Self {
fn new(esp: impl AsRef<Path>, architecture: Architecture) -> Self {
let esp = esp.as_ref();
let efi = esp.join("EFI");
let efi_nixos = efi.join("nixos");
@ -34,9 +36,9 @@ impl EspPaths<10> for SystemdEspPaths {
nixos: efi_nixos,
linux: efi_linux,
efi_fallback_dir: efi_efi_fallback_dir.clone(),
efi_fallback: efi_efi_fallback_dir.join("BOOTX64.EFI"),
efi_fallback: efi_efi_fallback_dir.join(architecture.efi_fallback_filename()),
systemd: efi_systemd.clone(),
systemd_boot: efi_systemd.join("systemd-bootx64.efi"),
systemd_boot: efi_systemd.join(architecture.systemd_filename()),
loader,
systemd_boot_loader_config,
}

View File

@ -10,8 +10,10 @@ use anyhow::{anyhow, Context, Result};
use nix::unistd::syncfs;
use tempfile::TempDir;
use crate::architecture::SystemdArchitectureExt;
use crate::esp::SystemdEspPaths;
use crate::version::SystemdVersion;
use lanzaboote_tool::architecture::Architecture;
use lanzaboote_tool::esp::{EspGenerationPaths, EspPaths};
use lanzaboote_tool::gc::Roots;
use lanzaboote_tool::generation::{Generation, GenerationLink};
@ -30,11 +32,14 @@ pub struct Installer {
configuration_limit: usize,
esp_paths: SystemdEspPaths,
generation_links: Vec<PathBuf>,
arch: Architecture,
}
impl Installer {
#[allow(clippy::too_many_arguments)]
pub fn new(
lanzaboote_stub: PathBuf,
arch: Architecture,
systemd: PathBuf,
systemd_boot_loader_config: PathBuf,
key_pair: KeyPair,
@ -43,7 +48,7 @@ impl Installer {
generation_links: Vec<PathBuf>,
) -> Self {
let mut gc_roots = Roots::new();
let esp_paths = SystemdEspPaths::new(esp);
let esp_paths = SystemdEspPaths::new(esp, arch);
gc_roots.extend(esp_paths.iter());
Self {
@ -56,6 +61,7 @@ impl Installer {
configuration_limit,
esp_paths,
generation_links,
arch,
}
}
@ -238,7 +244,7 @@ impl Installer {
let bootspec = &generation.spec.bootspec.bootspec;
let esp_gen_paths = EspGenerationPaths::new(&self.esp_paths, generation)?;
let esp_gen_paths = EspGenerationPaths::new(&self.esp_paths, generation, self.arch)?;
self.gc_roots.extend(esp_gen_paths.to_iter());
let initrd_content = fs::read(
@ -284,7 +290,7 @@ impl Installer {
let bootspec = &generation.spec.bootspec.bootspec;
let esp_gen_paths = EspGenerationPaths::new(&self.esp_paths, generation)?;
let esp_gen_paths = EspGenerationPaths::new(&self.esp_paths, generation, self.arch)?;
let kernel_cmdline =
assemble_kernel_cmdline(&bootspec.init, bootspec.kernel_params.clone());
@ -335,7 +341,8 @@ impl Installer {
fn install_systemd_boot(&self) -> Result<()> {
let systemd_boot = self
.systemd
.join("lib/systemd/boot/efi/systemd-bootx64.efi");
.join("lib/systemd/boot/efi")
.join(self.arch.systemd_filename());
let paths = [
(&systemd_boot, &self.esp_paths.efi_fallback),

View File

@ -0,0 +1 @@
pub mod architecture;

View File

@ -1,3 +1,4 @@
mod architecture;
mod cli;
mod esp;
mod install;

View File

@ -17,6 +17,23 @@ use rand::{thread_rng, Rng};
use serde_json::json;
use sha2::{Digest, Sha256};
use lanzaboote_tool::architecture::Architecture;
use lzbt_systemd::architecture::SystemdArchitectureExt;
/// Returns the host platform system
/// in the system double format for
/// our usual targets.
#[cfg(target_arch = "aarch64")]
pub static SYSTEM: &str = "aarch64-linux";
// We do not actually care much about 32 bit. However we can use this to easily test that lzbt
// works with another architecture.
#[cfg(target_arch = "x86")]
pub static SYSTEM: &str = "i686-linux";
#[cfg(target_arch = "x86_64")]
pub static SYSTEM: &str = "x86_64-linux";
/// Create a mock generation link.
///
/// Works like `setup_generation_link_from_toplevel` but already sets up toplevel.
@ -55,7 +72,7 @@ pub fn setup_generation_link_from_toplevel(
],
"label": "LanzaOS",
"toplevel": toplevel,
"system": "x86_64-linux",
"system": SYSTEM,
},
"org.nixos-community.lanzaboote": { "osRelease": toplevel.join("os-release") }
});
@ -78,13 +95,18 @@ pub fn setup_generation_link_from_toplevel(
/// Accepts the temporary directory as a parameter so that the invoking function retains control of
/// it (and when it goes out of scope).
pub fn setup_toplevel(tmpdir: &Path) -> Result<PathBuf> {
let system = Architecture::from_nixos_system(SYSTEM)?;
// Generate a random toplevel name so that multiple toplevel paths can live alongside each
// other in the same directory.
let toplevel = tmpdir.join(format!("toplevel-{}", random_string(8)));
fs::create_dir(&toplevel)?;
let test_systemd = systemd_location_from_env()?;
let test_systemd_stub = format!("{test_systemd}/lib/systemd/boot/efi/linuxx64.efi.stub");
let systemd_stub_filename = system.systemd_stub_filename();
let test_systemd_stub = format!(
"{test_systemd}/lib/systemd/boot/efi/{systemd_stub_filename}",
systemd_stub_filename = systemd_stub_filename.display()
);
let initrd_path = toplevel.join("initrd");
let kernel_path = toplevel.join("kernel");
@ -119,8 +141,13 @@ pub fn lanzaboote_install(
) -> Result<Output> {
// To simplify the test setup, we use the systemd stub here instead of the lanzaboote stub. See
// the comment in setup_toplevel for details.
let system = Architecture::from_nixos_system(SYSTEM)?;
let test_systemd = systemd_location_from_env()?;
let test_systemd_stub = format!("{test_systemd}/lib/systemd/boot/efi/linuxx64.efi.stub");
let systemd_stub_filename = system.systemd_stub_filename();
let test_systemd_stub = format!(
"{test_systemd}/lib/systemd/boot/efi/{systemd_stub_filename}",
systemd_stub_filename = systemd_stub_filename.display()
);
let test_loader_config_path = tempfile::NamedTempFile::new()?;
let test_loader_config = r"timeout 0\nconsole-mode 1\n";
@ -131,6 +158,8 @@ pub fn lanzaboote_install(
.env("LANZABOOTE_STUB", test_systemd_stub)
.arg("-vv")
.arg("install")
.arg("--system")
.arg(SYSTEM)
.arg("--systemd")
.arg(test_systemd)
.arg("--systemd-boot-loader-config")

View File

@ -2,11 +2,13 @@ use std::fs;
use std::path::PathBuf;
use anyhow::Result;
use lanzaboote_tool::architecture::Architecture;
use lzbt_systemd::architecture::SystemdArchitectureExt;
use tempfile::tempdir;
mod common;
use common::{hash_file, mtime, remove_signature, verify_signature};
use common::{hash_file, mtime, remove_signature, verify_signature, SYSTEM};
#[test]
fn keep_systemd_boot_binaries() -> Result<()> {
@ -113,9 +115,15 @@ fn overwrite_unsigned_systemd_boot_binaries() -> Result<()> {
}
fn systemd_boot_path(esp: &tempfile::TempDir) -> PathBuf {
esp.path().join("EFI/systemd/systemd-bootx64.efi")
let arch = Architecture::from_nixos_system(SYSTEM).unwrap();
esp.path()
.join("EFI/systemd/")
.join(arch.systemd_filename())
}
fn systemd_boot_fallback_path(esp: &tempfile::TempDir) -> PathBuf {
esp.path().join("EFI/BOOT/BOOTX64.EFI")
let arch = Architecture::from_nixos_system(SYSTEM).unwrap();
esp.path()
.join("EFI/BOOT/")
.join(arch.efi_fallback_filename())
}

View File

@ -1,4 +1,4 @@
[toolchain]
channel = "1.70.0"
components = [ "rust-src" ]
targets = [ "x86_64-unknown-uefi" ]
targets = [ "x86_64-unknown-uefi", "aarch64-unknown-uefi" ]