mirror of
https://github.com/edera-dev/sprout.git
synced 2026-11-04 22:02:20 +00:00
fix(boot): count tries without using them, add XBOOTLDR once, and warn about dropped initrds
An entry that is not counted in strict mode still has its tries, so it can be bad. Strict mode adds the extended boot loader partition to the first BLS generator only. A chainload chain that does not list an initrd that the entry has now warns, as the kernel may not find its root without it, and strict autoconfigure says when it can't find the partition of Sprout.
This commit is contained in:
1 parent
47020c7b92
commit
5a4bfefb6e
5 files changed
+50
-11
No files matched your search
@@ -1,4 +1,5 @@
|
|||||||
use crate::context::SproutContext;
|
use crate::context::SproutContext;
|
||||||
|
use crate::generators::bls::BLS_INITRD_SLOTS;
|
||||||
use crate::phases::before_handoff;
|
use crate::phases::before_handoff;
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
@@ -160,6 +161,24 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
|
|||||||
.chain(configuration.linux_initrd_chain.iter())
|
.chain(configuration.linux_initrd_chain.iter())
|
||||||
.map(|item| context.stamp(item));
|
.map(|item| context.stamp(item));
|
||||||
|
|
||||||
|
// A BLS entry can have more initrds than the chain lists. Those would be dropped without a
|
||||||
|
// word, and then the kernel may not find its root, so say so.
|
||||||
|
let chain_length = configuration.linux_initrd_chain.len();
|
||||||
|
if chain_length > 0 {
|
||||||
|
for slot in chain_length..BLS_INITRD_SLOTS {
|
||||||
|
let placeholder = format!("$initrd-{}", slot);
|
||||||
|
let value = context.stamp(&placeholder);
|
||||||
|
if !value.is_empty() && value != placeholder {
|
||||||
|
warn!(
|
||||||
|
"the entry has an initrd for slot {}, but linux-initrd-chain only lists {}, \
|
||||||
|
so it is not loaded",
|
||||||
|
slot, chain_length
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Read each initrd and concatenate the contents in order.
|
// Read each initrd and concatenate the contents in order.
|
||||||
// Paths that are empty after stamping are skipped.
|
// Paths that are empty after stamping are skipped.
|
||||||
let mut initrd: Option<Vec<u8>> = None;
|
let mut initrd: Option<Vec<u8>> = None;
|
||||||
|
|||||||
@@ -140,13 +140,19 @@ pub fn autoconfigure(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// In strict mode, one generator reads both partitions, with the root of Sprout's partition.
|
// In strict mode, one generator reads both partitions, with the root of Sprout's partition.
|
||||||
if strict
|
if strict && strict_found {
|
||||||
&& strict_found
|
match own_root {
|
||||||
&& let Some(root) = own_root
|
Some(root) => {
|
||||||
&& let Err(error) = bls::add_generator(config, &root, true)
|
if let Err(error) = bls::add_generator(config, &root, true) {
|
||||||
{
|
|
||||||
warn!("unable to add the bls generator: {:#}", error);
|
warn!("unable to add the bls generator: {:#}", error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
None => warn!(
|
||||||
|
"found BLS entries, but not the partition that Sprout was loaded from, \
|
||||||
|
so none are used in strict mode"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,9 @@ pub struct BootCounterTarget {
|
|||||||
pub file_name: String,
|
pub file_name: String,
|
||||||
/// The extension of the file name, such as `.conf`, in its original case.
|
/// The extension of the file name, such as `.conf`, in its original case.
|
||||||
pub extension: String,
|
pub extension: String,
|
||||||
|
/// Whether booting the entry uses up a try. An entry whose tries are not used up still
|
||||||
|
/// has them, so it can be bad.
|
||||||
|
pub counting: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BootCounterTarget {
|
impl BootCounterTarget {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use alloc::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
use core::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
|
||||||
use core::{cmp::Ordering, str::FromStr};
|
use core::{cmp::Ordering, str::FromStr};
|
||||||
use edera_sprout_bls::{
|
use edera_sprout_bls::{
|
||||||
BlsEntry, BootCounter, is_reserved_entry_name, profile_id_suffix, sort_bls, strip_extension,
|
BlsEntry, BootCounter, is_reserved_entry_name, profile_id_suffix, sort_bls, strip_extension,
|
||||||
@@ -37,6 +38,10 @@ const ARCHITECTURE: &str = "x64";
|
|||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
const ARCHITECTURE: &str = "aa64";
|
const ARCHITECTURE: &str = "aa64";
|
||||||
|
|
||||||
|
/// Whether the extended boot loader partition was added by a generator in strict mode, which
|
||||||
|
/// does it once, so that more than one generator does not list its entries twice.
|
||||||
|
static STRICT_XBOOTLDR_ADDED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
/// The number of initrd slots set on each BLS entry.
|
/// The number of initrd slots set on each BLS entry.
|
||||||
/// Entries set `initrd-0` through `initrd-31`, and slots without an initrd are empty.
|
/// Entries set `initrd-0` through `initrd-31`, and slots without an initrd are empty.
|
||||||
pub const BLS_INITRD_SLOTS: usize = 32;
|
pub const BLS_INITRD_SLOTS: usize = 32;
|
||||||
@@ -311,9 +316,7 @@ fn generate_type1(
|
|||||||
// systemd-boot only counts the tries of the entries it boots as a kernel or as a unified
|
// systemd-boot only counts the tries of the entries it boots as a kernel or as a unified
|
||||||
// kernel image, and not those of a plain EFI program.
|
// kernel image, and not those of a plain EFI program.
|
||||||
let counted = !(strict && entry.linux.is_none() && entry.uki.is_none());
|
let counted = !(strict && entry.linux.is_none() && entry.uki.is_none());
|
||||||
if let Some(counter) = boot_counter
|
if let Some(counter) = boot_counter {
|
||||||
&& counted
|
|
||||||
{
|
|
||||||
boot.set_boot_counter(BootCounterTarget {
|
boot.set_boot_counter(BootCounterTarget {
|
||||||
counter,
|
counter,
|
||||||
filesystem: bls_resolved.filesystem_handle,
|
filesystem: bls_resolved.filesystem_handle,
|
||||||
@@ -321,6 +324,7 @@ fn generate_type1(
|
|||||||
id: name.clone(),
|
id: name.clone(),
|
||||||
file_name,
|
file_name,
|
||||||
extension,
|
extension,
|
||||||
|
counting: counted,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,6 +450,7 @@ fn generate_type2(
|
|||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
file_name: file_name.clone(),
|
file_name: file_name.clone(),
|
||||||
extension: extension.clone(),
|
extension: extension.clone(),
|
||||||
|
counting: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
found.push((entry, boot));
|
found.push((entry, boot));
|
||||||
@@ -532,7 +537,9 @@ pub fn generate(context: Rc<SproutContext>, bls: &BlsConfiguration) -> Result<Ve
|
|||||||
|
|
||||||
// Add the entries of the Extended Boot Loader Partition, which are sorted together with the
|
// Add the entries of the Extended Boot Loader Partition, which are sorted together with the
|
||||||
// others. A problem with it should not prevent booting from the entries that are found.
|
// others. A problem with it should not prevent booting from the entries that are found.
|
||||||
if bls.xbootldr || context.root().options().bls_strict_mode {
|
let strict_xbootldr = context.root().options().bls_strict_mode
|
||||||
|
&& !STRICT_XBOOTLDR_ADDED.swap(true, AtomicOrdering::Relaxed);
|
||||||
|
if bls.xbootldr || strict_xbootldr {
|
||||||
match xbootldr_root(&context) {
|
match xbootldr_root(&context) {
|
||||||
Ok(Some(root)) => {
|
Ok(Some(root)) => {
|
||||||
let xbootldr_uki = uki_path.as_ref().map(|_| format!("{}\\EFI\\Linux", root));
|
let xbootldr_uki = uki_path.as_ref().map(|_| format!("{}\\EFI\\Linux", root));
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ fn run(reboot_on_error: &mut bool) -> Result<()> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Acquire the entry that was saved by the previous boot.
|
// Acquire the entry that was saved by the previous boot.
|
||||||
let last_booted_entry = advisory(
|
let mut last_booted_entry = advisory(
|
||||||
BootloaderInterface::get_last_booted_entry()
|
BootloaderInterface::get_last_booted_entry()
|
||||||
.context("unable to get last booted entry from bootloader interface"),
|
.context("unable to get last booted entry from bootloader interface"),
|
||||||
);
|
);
|
||||||
@@ -692,12 +692,14 @@ fn run(reboot_on_error: &mut bool) -> Result<()> {
|
|||||||
BootloaderInterface::set_last_booted_entry(&id)
|
BootloaderInterface::set_last_booted_entry(&id)
|
||||||
.context("unable to save last booted entry in bootloader interface"),
|
.context("unable to save last booted entry in bootloader interface"),
|
||||||
);
|
);
|
||||||
|
last_booted_entry = Some(id.clone());
|
||||||
}
|
}
|
||||||
} else if last_booted_entry.is_some() {
|
} else if last_booted_entry.is_some() {
|
||||||
advisory(
|
advisory(
|
||||||
BootloaderInterface::remove_last_booted_entry()
|
BootloaderInterface::remove_last_booted_entry()
|
||||||
.context("unable to remove last booted entry in bootloader interface"),
|
.context("unable to remove last booted entry in bootloader interface"),
|
||||||
);
|
);
|
||||||
|
last_booted_entry = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -710,7 +712,9 @@ fn run(reboot_on_error: &mut bool) -> Result<()> {
|
|||||||
// still be marked as good.
|
// still be marked as good.
|
||||||
// The tries that were left before this boot used one up, if it did.
|
// The tries that were left before this boot used one up, if it did.
|
||||||
let mut consumed_tries_left = None;
|
let mut consumed_tries_left = None;
|
||||||
if let Some(target) = entry.boot_counter() {
|
if let Some(target) = entry.boot_counter()
|
||||||
|
&& target.counting
|
||||||
|
{
|
||||||
match target.consume() {
|
match target.consume() {
|
||||||
Ok(path) => {
|
Ok(path) => {
|
||||||
info!("updated boot counter of entry {}: {}", entry.name(), path);
|
info!("updated boot counter of entry {}: {}", entry.name(), path);
|
||||||
|
|||||||
Reference in new issue
Block a user