feat(bls): one entry for each profile of a unified kernel image

A unified kernel image can have several profiles, each started by a
.profile section and made of the sections after it on top of the base.
Every profile is an entry. The first has the id of the file, and the
others add @ and the identifier or the number of the profile, with a
title that names the profile and the profile number as the load options.
The profiles share the boot counter of the file, sort in the order they
are in the image, and a profile after the first is not picked as the
default entry when no default was asked for.

The PE reader keeps every section in order, so repeated names and the
sections that a profile removes can be told apart, and reads images with
more than 96 sections.
This commit is contained in:
alex authored and Alex Zenla committed 2026-10-03 20:23:57 -07:00
1 parent ac49899294
commit 50f62f5bb6
7 files changed
+628 -86

No files matched your search

+25 -6
View File
@@ -4,7 +4,9 @@ use alloc::{
vec::Vec,
};
use anyhow::{Context, Result, anyhow, bail};
use edera_sprout_bls::{BlsEntry, PeImage, ReadAt, UKI_SECTIONS, read_pe, strip_extension};
use edera_sprout_bls::{
BlsEntry, PeImage, ProfileInfo, ReadAt, UKI_SECTIONS, read_pe, strip_extension, uki_profiles,
};
use log::warn;
use uefi::{
CString16, Handle, Status,
@@ -18,9 +20,19 @@ pub struct UkiFile {
pub file_name: String,
/// The machine type of the image.
pub machine: u16,
/// Whether the image has an `.osrel` section, which unified kernel images always have.
/// The profiles of the image. An image without profiles has one.
pub profiles: Vec<UkiProfileEntry>,
}
/// One profile of a unified kernel image.
pub struct UkiProfileEntry {
/// The number of the profile, or None if the image has no profiles.
pub index: Option<u32>,
/// The metadata of the profile.
pub info: ProfileInfo,
/// Whether the profile has an `.osrel` section, which unified kernel images always have.
pub has_osrel: bool,
/// The entry made from the sections of the image.
/// The entry made from the sections of the profile.
pub entry: BlsEntry,
}
@@ -94,9 +106,16 @@ pub fn scan(filesystem: Handle, directory: &str) -> Result<Vec<UkiFile>> {
Ok(image) => found.push(UkiFile {
file_name,
machine: image.machine,
has_osrel: image.sections.contains_key(".osrel"),
// The sections are dropped here, so only the small entry is kept per image.
entry: BlsEntry::from_uki(&image.sections, &path),
// The sections are dropped here, so only the small entries are kept per image.
profiles: uki_profiles(&image.sections)
.into_iter()
.map(|profile| UkiProfileEntry {
index: profile.index,
has_osrel: profile.sections.contains_key(".osrel"),
entry: BlsEntry::from_uki_profile(&profile, &path),
info: profile.info,
})
.collect(),
}),
Err(error) => warn!("unable to read unified kernel image {}: {:#}", path, error),
}