diff --git a/rust/pvimg/src/pv_utils/se_hdr/generic_flags.rs b/rust/pvimg/src/pv_utils/se_hdr/generic_flags.rs new file mode 100644 index 00000000..f8733b8c --- /dev/null +++ b/rust/pvimg/src/pv_utils/se_hdr/generic_flags.rs @@ -0,0 +1,855 @@ +// SPDX-License-Identifier: MIT +// +// Copyright IBM Corp. + +//! Generic control flags infrastructure for Secure Execution (SE) headers. +//! +//! This module provides the generic, reusable components for managing control flags +//! in IBM Secure Execution headers. It defines traits, generic types, and implementations +//! that can work with any flag enum type. +//! +//! # Core Components +//! +//! ## Traits +//! +//! - [`ControlFlagTrait`] - Core trait that flag enums must implement +//! - [`IntoEnumIterator`] - Enables iteration over flag enum variants +//! - [`IntoBitPosition`] - Converts types to bit positions +//! +//! ## Generic Types +//! +//! - [`ControlFlagsModel`] - Version-specific configuration model +//! - [`EffectiveControlFlags`] - Final flags after applying overrides +//! - [`FlagsOverride`] - Container for user-specified overrides +//! - [`FlagData`] - Pairs a flag with its state +//! - [`UnknownFlags`] - Tracks unknown/unsupported flag bits +//! +//! ## Supporting Types +//! +//! - [`FlagState`] - Enabled or Disabled state +//! - [`FlagValidationError`] - Validation errors +//! - [`Msb0FlagsConversionError`] - Conversion errors +//! +//! # Usage +//! +//! This module is not typically used directly. Instead, use the concrete implementations +//! in the [`flags`](super::flags) module which provide `SeHdrFlag`, `SeHdrControlFlagsModel`, +//! and related types built on top of this generic infrastructure. + +use std::collections::{HashMap, HashSet}; +use std::fmt::{Debug, Display}; +use std::hash::Hash; + +use pv::misc::{Flags, Msb0Flags64}; + +use super::brb::SeHdrVersion; + +#[derive(Debug)] +pub enum FlagValidationError { + UnknownFlag(), + NotSupported { model: &'static str, flag: T }, +} + +impl Display for FlagValidationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + FlagValidationError::UnknownFlag() => write!(f, "Unknown flag"), + FlagValidationError::NotSupported { model, flag } => { + write!(f, "Flag '{}' is not supported in {}", flag, model) + } + } + } +} + +impl std::error::Error for FlagValidationError {} + +/// Secure Execution target configuration. +/// +/// Specifies the target environment for which a Secure Execution boot image is being created. +/// This enum allows selecting the appropriate control flags and configuration based on the +/// target machine generation or SE header version. +/// +/// # Current Usage +/// +/// Currently, this enum is primarily used for selecting control flags configurations. +/// The target determines which control flags are available and their default values. +/// +/// # Purpose +/// +/// The target determines: +/// - Which control flags are available and their default values +/// - The SE header format version to use +/// - Compatibility with specific machine generations (future use) +/// +/// # Future Extensibility +/// +/// This design allows for future expansion when multiple variants of V1 or V2 configurations +/// may exist. +/// +/// # Examples +/// +/// ``` +/// use pvimg::uvdata::{SeHdrControlFlagsModel, SeTarget}; +/// +/// // Select latest V1 configuration for newest features +/// let target = SeTarget::V1Max; +/// +/// // Use target to get appropriate control flags +/// let pcf = SeHdrControlFlagsModel::pcf_for_target(target); +/// ``` +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum SeTarget { + /// Latest V1 configuration. + /// + /// Targets the most recent V1 SE header format with all available V1 control flags. + /// Use this for maximum compatibility with older machine generations that support V1. + V1Max, +} + +impl SeTarget { + /// Converts the target to the corresponding SeHdrVersion. + pub fn to_se_hdr_version(self) -> SeHdrVersion { + match self { + SeTarget::V1Max => SeHdrVersion::V1, + } + } + + /// Creates a target from a SeHdrVersion. + pub fn from_se_hdr_version(version: SeHdrVersion) -> Self { + match version { + SeHdrVersion::V1 => SeTarget::V1Max, + } + } +} + +impl Display for SeTarget { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SeTarget::V1Max => write!(f, "V1-max"), + } + } +} + +pub trait IntoEnumIterator { + /// Returns an iterator over all variants of this enum. + fn iter() -> impl Iterator; +} + +/// Trait for individual control flag types. +/// +/// This trait defines the interface for control flag enums, providing methods +/// to get the flag's bit position and create enabled/disabled flag data. +pub trait ControlFlagTrait: + Debug + Hash + Copy + Eq + Ord + Display + IntoEnumIterator + AsRef +{ + /// Returns the bit position of this flag. + /// + /// The bit position determines where this flag is set in the control flags bitfield. + fn bit_position(self) -> u8; + + /// Creates flag data with this flag in the enabled state. + fn enabled(self) -> FlagData { + FlagData::new(self, FlagState::Enabled) + } + + /// Creates flag data with this flag in the disabled state. + fn disabled(self) -> FlagData { + FlagData::new(self, FlagState::Disabled) + } +} + +/// Internal state of a control flag (enabled or disabled). +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] +pub enum FlagState { + /// Flag is enabled (bit set to 1) + Enabled, + /// Flag is disabled (bit set to 0) + Disabled, +} + +/// Represents a control flag with its associated state. +/// +/// This structure pairs a flag with its enabled/disabled state, used when +/// constructing or modifying `ControlFlags` instances. +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] +pub struct FlagData { + value: T, + state: FlagState, +} + +impl FlagData { + const fn new(value: T, state: FlagState) -> Self { + Self { value, state } + } +} + +/// Generic flags configuration for a specific SE header flags target. +/// +/// Contains the default and supported flags for a given target version. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ControlFlagsModel { + target: SeTarget, + default: HashSet, + supported: HashSet, +} + +impl ControlFlagsModel { + /// Creates a new Flags configuration. + pub(super) fn new(target: SeTarget, default: HashSet, supported: HashSet) -> Self { + Self { + target, + default, + supported, + } + } + + /// Returns the SE header flags target. + pub fn target(&self) -> SeTarget { + self.target + } + + /// Returns the SE header version corresponding to this target. + pub fn version(&self) -> SeHdrVersion { + self.target.to_se_hdr_version() + } + + /// Returns the set of default flags for this version. + pub fn default_flags(&self) -> &HashSet { + &self.default + } + + /// Returns the set of supported flags for this version. + pub fn supported_flags(&self) -> &HashSet { + &self.supported + } + + /// Checks if a flag is supported in this version. + pub fn supports>(&self, flag: F) -> bool { + self.supported.contains(flag.as_ref()) + } + + /// Checks if a flag is a default flag in this version. + #[must_use] + pub fn is_default>(&self, flag: F) -> bool { + self.default.contains(flag.as_ref()) + } + + /// Validates that all flags in the overrides are supported by this model. + /// + /// # Arguments + /// + /// * `overrides` - The overrides to validate + /// + /// # Errors + /// + /// Returns `FlagValidationError::NotSupported` if any override flag is not supported by this + /// model + pub fn validate_overrides( + &self, + overrides: &FlagsOverride, + ) -> Result<(), FlagValidationError> { + for (flag, _state) in overrides.iter() { + if !self.supports(flag) { + return Err(FlagValidationError::NotSupported { + model: std::any::type_name::(), + flag: *flag, + }); + } + } + Ok(()) + } + + /// Applies overrides to the default flags and returns the effective control flags. + /// + /// This method validates the overrides, applies them to the default flags, and returns + /// an `EffectiveControlFlags` instance containing the resulting configuration. + /// + /// # Arguments + /// + /// * `overrides` - Overrides to apply to the default flags + /// + /// # Returns + /// + /// An `EffectiveControlFlags` instance with the effective flags after applying overrides + /// + /// # Errors + /// + /// Returns `FlagValidationError::NotSupported` if an override flag is not supported by this + /// model + pub fn with_overrides( + &self, + overrides: &FlagsOverride, + ) -> Result, FlagValidationError> { + // Validate overrides first + self.validate_overrides(overrides)?; + let mut effective_flags = self.default.clone(); + + // Apply overrides + for (flag, state) in overrides.iter() { + match state { + FlagState::Enabled => { + effective_flags.insert(*flag); + } + FlagState::Disabled => { + effective_flags.remove(flag); + } + } + } + + Ok(EffectiveControlFlags { + version: self.version(), + known_flags: effective_flags, + unknown_flags: UnknownFlags::empty(), + }) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UnknownFlags(Msb0Flags64); + +/// Trait for types that can be converted to a bit position. +pub trait IntoBitPosition { + fn into_bit_position(self) -> u8; +} + +/// Implement IntoBitPosition for u8 directly +impl IntoBitPosition for u8 { + fn into_bit_position(self) -> u8 { + self + } +} + +/// Implement IntoBitPosition for types that implement ControlFlagTrait +impl IntoBitPosition for T { + fn into_bit_position(self) -> u8 { + self.bit_position() + } +} + +impl UnknownFlags { + pub fn empty() -> Self { + Self(Msb0Flags64::from(0u64)) + } + + pub fn from_bits(bits: Msb0Flags64) -> Self { + Self(bits) + } + + pub fn bits(self) -> u64 { + self.0.into() + } + + #[must_use] + pub fn is_empty(self) -> bool { + self.bits() == 0 + } + + /// Checks if a specific flag or bit position is set in the unknown flags. + /// + /// # Arguments + /// + /// * `flag` - Either a flag that implements `ControlFlagTrait`, a reference to such a flag, or + /// a raw bit position (u8) + /// + /// # Returns + /// + /// `true` if the bit position is set in the unknown flags, `false` otherwise + /// + /// # Examples + /// + /// ```ignore + /// // Using a raw bit position + /// unknown_flags.contains(5u8); + /// ``` + #[must_use] + pub fn contains(&self, position: u8) -> bool { + self.0.is_set(position) + } +} + +/// Represents the effective control flags after applying overrides. +/// +/// This structure contains the final set of flags that will be used, including both +/// known flags (from the model) and any unknown flags that were present in the input. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EffectiveControlFlags { + version: SeHdrVersion, + known_flags: HashSet, + unknown_flags: UnknownFlags, +} + +impl EffectiveControlFlags { + /// Creates a new EffectiveControlFlags instance. + /// + /// This is primarily used internally by the flags module. + pub(super) fn new( + version: SeHdrVersion, + known_flags: HashSet, + unknown_flags: UnknownFlags, + ) -> Self { + Self { + version, + known_flags, + unknown_flags, + } + } + + /// Returns the SE header version. + pub fn version(&self) -> SeHdrVersion { + self.version + } + + /// Returns the set of known flags. + pub fn known_flags(&self) -> &HashSet { + &self.known_flags + } + + /// Returns the unknown flags. + pub fn unknown_flags(&self) -> UnknownFlags { + self.unknown_flags + } + + /// Checks if a flag or bit position is enabled in the effective flags. + /// + /// This method accepts either a flag type or a raw bit position (u8). + /// + /// # Arguments + /// + /// * `position` - Either a flag that implements `ControlFlagTrait`, a reference to such a flag, + /// or a raw bit position (u8) + /// + /// # Returns + /// + /// `true` if the flag/bit is enabled, `false` otherwise + /// + /// # Examples + /// + /// ```ignore + /// // Using a flag + /// flags.has(SeHdrFlag::PckmoAes); + /// + /// // Using a raw bit position + /// flags.has(5u8); + /// ``` + pub fn has(&self, position: P) -> bool { + let bit_pos = position.into_bit_position(); + + // Check if any known flag has this bit position + for flag in &self.known_flags { + if flag.bit_position() == bit_pos { + return true; + } + } + + // Check unknown flags + self.unknown_flags.contains(bit_pos) + } + + /// Converts the effective flags to a u64 value. + /// + /// # Returns + /// + /// A u64 representation combining both known and unknown flags + pub fn to_u64(&self) -> u64 { + let flags: Msb0Flags64 = self.into(); + flags.into() + } +} + +/// Converts `EffectiveControlFlags` to `Msb0Flags64`. +/// +/// This combines both known and unknown flags into a single bitfield. +impl From> for Msb0Flags64 { + fn from(flags: EffectiveControlFlags) -> Self { + let mut value = Msb0Flags64::from(flags.unknown_flags.bits()); + for flag in &flags.known_flags { + value.set_bit(flag.bit_position()); + } + value + } +} + +/// Converts a reference to `EffectiveControlFlags` to `Msb0Flags64`. +impl From<&EffectiveControlFlags> for Msb0Flags64 { + fn from(flags: &EffectiveControlFlags) -> Self { + let mut value = Msb0Flags64::from(flags.unknown_flags.bits()); + for flag in &flags.known_flags { + value.set_bit(flag.bit_position()); + } + value + } +} + +/// Display implementation for `EffectiveControlFlags`. +/// +/// Provides two display formats: +/// - Normal format: Lists all enabled flags with " - " prefix, one per line +/// - Alternate format (`{:#}`): Shows the raw bitfield as 66-character binary string +/// +/// # Examples +/// +/// ```rust +/// use pvimg::uvdata::{FlagsOverride, SeHdrControlFlagsModel, SeHdrFlag, SeTarget}; +/// +/// let pcf_v1 = SeHdrControlFlagsModel::pcf_for_target(SeTarget::V1Max); +/// let mut overrides = FlagsOverride::new(); +/// overrides.enable(SeHdrFlag::ConfidentialDump); +/// let effective = pcf_v1.with_overrides(&overrides).unwrap(); +/// +/// // Normal format - lists enabled flags +/// println!("{}", effective); +/// +/// // Alternate format - shows binary representation +/// println!("{:#}", effective); +/// ``` +impl Display for EffectiveControlFlags { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if f.alternate() { + // Alternate format: show as binary + let flags: Msb0Flags64 = self.into(); + write!(f, "{:#066b}", ::from(flags)) + } else { + // Normal format: list enabled flags + let flags_s: Vec = self + .known_flags + .iter() + .map(|flag| format!(" - {flag}")) + .collect(); + + if flags_s.is_empty() && self.unknown_flags.is_empty() { + write!(f, "(no flags enabled)") + } else { + let mut output = flags_s.join("\n"); + if !self.unknown_flags.is_empty() { + if !output.is_empty() { + output.push('\n'); + } + output.push_str(&format!( + " - unknown flags: {:#018x}", + self.unknown_flags.bits() + )); + } + write!(f, "{}", output) + } + } + } +} + +/// Converts a reference to `ControlFlagsModel` to `EffectiveControlFlags` using default flags. +/// +/// This implementation allows conversion without consuming the model. +/// +/// # Examples +/// +/// ```rust +/// use pvimg::uvdata::{EffectiveControlFlags, SeHdrControlFlagsModel, SeTarget}; +/// +/// let pcf_v1 = SeHdrControlFlagsModel::pcf_for_target(SeTarget::V1Max); +/// let flags: EffectiveControlFlags<_> = (&pcf_v1).into(); +/// // pcf_v1 is still usable here +/// ``` +impl From<&ControlFlagsModel> for EffectiveControlFlags { + fn from(model: &ControlFlagsModel) -> Self { + EffectiveControlFlags { + version: model.version(), + known_flags: model.default.clone(), + unknown_flags: UnknownFlags::empty(), + } + } +} + +/// Converts `ControlFlagsModel` to `Msb0Flags64` using default flags. +/// +/// This consumes the model and converts it to a bitfield representation. +impl From> for Msb0Flags64 { + fn from(model: ControlFlagsModel) -> Self { + let mut value = Msb0Flags64::default(); + for flag in &model.default { + value.set_bit(flag.bit_position()); + } + value + } +} + +/// Converts a reference to `ControlFlagsModel` to `Msb0Flags64` using default flags. +/// +/// This implementation allows conversion without consuming the model. +impl From<&ControlFlagsModel> for Msb0Flags64 { + fn from(model: &ControlFlagsModel) -> Self { + let mut value = Msb0Flags64::default(); + for flag in &model.default { + value.set_bit(flag.bit_position()); + } + value + } +} +/// Display implementation for `ControlFlagsModel`. +/// +/// Provides two display formats: +/// - Normal format: Lists all default (enabled) flags with " - " prefix, one per line +/// - Alternate format (`{:#}`): Shows the raw bitfield as 66-character binary string +/// +/// Note: This displays only the flags in the model's `default` set. Unknown flags +/// are not tracked by `ControlFlagsModel` - they are returned separately by +/// `from_msb0_flags()` when parsing raw bitfields. +/// +/// # Examples +/// +/// ```rust +/// use pvimg::uvdata::{SeHdrControlFlagsModel, SeTarget}; +/// +/// let pcf_v1 = SeHdrControlFlagsModel::pcf_for_target(SeTarget::V1Max); +/// +/// // Normal format - lists default flags +/// println!("{}", pcf_v1); +/// +/// // Alternate format - shows binary representation +/// println!("{:#}", pcf_v1); +/// ``` +impl Display for ControlFlagsModel { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if f.alternate() { + // Alternate format: show as binary + let flags: Msb0Flags64 = self.into(); + write!(f, "{:#066b}", ::from(flags)) + } else { + // Normal format: list default (enabled) flags + let flags_s: Vec = self + .default + .iter() + .map(|flag| format!(" - {flag}")) + .collect(); + + if flags_s.is_empty() { + write!(f, "(no flags enabled)") + } else { + write!(f, "{}", flags_s.join("\n")) + } + } + } +} + +/// Error type for `TryFrom` conversion. +#[derive(Debug)] +// Will be used in an upcoming commit +#[expect(dead_code)] +pub enum Msb0FlagsConversionError { + /// A flag bit is set that is not supported in any version + UnsupportedFlag { bit_position: u8 }, + /// A flag bit is set that is not supported in the specified version + NotSupportedInVersion { flag: T, version: SeHdrVersion }, +} + +impl Display for Msb0FlagsConversionError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::UnsupportedFlag { bit_position } => { + write!(f, "Unsupported flag at bit position {}", bit_position) + } + Self::NotSupportedInVersion { flag, version } => { + write!(f, "Flag {} not supported in version {:?}", flag, version) + } + } + } +} + +impl std::error::Error for Msb0FlagsConversionError {} + +/// Override configuration for control flags. +/// +/// Allows specifying individual flag states that override the default configuration. +/// This is useful for customizing flag settings on a per-flag basis. +/// +/// # Type Parameters +/// +/// * `T` - The control flag enum type (e.g., [`Flag`]) +/// +/// # Examples +/// +/// ```rust +/// use pvimg::uvdata::{FlagsOverride, SeHdrFlag}; +/// +/// let mut overrides = FlagsOverride::new(); +/// overrides.enable(SeHdrFlag::ConfidentialDump); +/// overrides.disable(SeHdrFlag::PckmoAes); +/// ``` +#[derive(Debug, Clone)] +pub struct FlagsOverride { + overrides: HashMap, +} + +impl FlagsOverride { + /// Creates a new empty FlagsOverride. + pub fn new() -> Self { + Self { + overrides: HashMap::new(), + } + } + + /// Sets an override for a specific flag. + /// + /// # Arguments + /// + /// * `flag` - The flag to override + /// * `state` - The desired state (Enabled or Disabled) + pub(super) fn set(&mut self, flag: T, state: FlagState) { + self.overrides.insert(flag, state); + } + + /// Enables a specific flag by setting its override state to Enabled. + /// + /// This is a convenience method equivalent to `set(flag, FlagState::Enabled)`. + /// + /// # Arguments + /// + /// * `flag` - The flag to enable + /// + /// # Examples + /// + /// ```rust + /// use pvimg::uvdata::{FlagsOverride, SeHdrFlag}; + /// + /// let mut overrides = FlagsOverride::new(); + /// overrides.enable(SeHdrFlag::ConfidentialDump); + /// ``` + pub fn enable(&mut self, flag: T) { + self.set(flag, FlagState::Enabled); + } + + /// Disables a specific flag by setting its override state to Disabled. + /// + /// This is a convenience method equivalent to `set(flag, FlagState::Disabled)`. + /// + /// # Arguments + /// + /// * `flag` - The flag to disable + /// + /// # Examples + /// + /// ```rust + /// use pvimg::uvdata::{FlagsOverride, SeHdrFlag}; + /// + /// let mut overrides = FlagsOverride::new(); + /// overrides.disable(SeHdrFlag::PckmoAes); + /// ``` + pub fn disable(&mut self, flag: T) { + self.set(flag, FlagState::Disabled); + } + + /// Enables multiple flags at once from an iterator. + /// + /// This is a convenience method for enabling multiple flags in a single call. + /// + /// # Arguments + /// + /// * `flags` - An iterator over flags to enable + /// + /// # Examples + /// + /// ```rust + /// use pvimg::uvdata::{FlagsOverride, SeHdrFlag}; + /// + /// let mut overrides = FlagsOverride::new(); + /// overrides.enable_all([SeHdrFlag::ConfidentialDump, SeHdrFlag::PckmoAes]); + /// ``` + pub fn enable_all(&mut self, flags: I) + where + I: IntoIterator, + { + for flag in flags { + self.enable(flag); + } + } + + /// Disables multiple flags at once from an iterator. + /// + /// This is a convenience method for disabling multiple flags in a single call. + /// + /// # Arguments + /// + /// * `flags` - An iterator over flags to disable + /// + /// # Examples + /// + /// ```rust + /// use pvimg::uvdata::{FlagsOverride, SeHdrFlag}; + /// + /// let mut overrides = FlagsOverride::new(); + /// overrides.disable_all([SeHdrFlag::PckmoAes, SeHdrFlag::PckmoEcc]); + /// ``` + pub fn disable_all(&mut self, flags: I) + where + I: IntoIterator, + { + for flag in flags { + self.disable(flag); + } + } + + /// Removes an override for a specific flag. + /// + /// # Arguments + /// + /// * `flag` - The flag to remove the override for + /// + /// # Returns + /// + /// The previous state if it existed, None otherwise + pub fn remove(&mut self, flag: T) -> Option { + self.overrides.remove(&flag) + } + + /// Gets the override state for a specific flag. + /// + /// # Arguments + /// + /// * `flag` - The flag to query + /// + /// # Returns + /// + /// The override state if it exists, None otherwise + pub fn get(&self, flag: T) -> Option { + self.overrides.get(&flag).copied() + } + + /// Checks if an override exists for a specific flag. + /// + /// # Arguments + /// + /// * `flag` - The flag to check + pub fn has_override(&self, flag: T) -> bool { + self.overrides.contains_key(&flag) + } + + /// Returns an iterator over all overrides. + pub fn iter(&self) -> impl Iterator { + self.overrides.iter() + } + + /// Returns an iterator over all flags that have overrides. + pub fn flags(&self) -> impl Iterator { + self.overrides.keys() + } + + /// Returns the number of overrides. + pub fn len(&self) -> usize { + self.overrides.len() + } + + /// Checks if there are no overrides. + #[must_use] + pub fn is_empty(&self) -> bool { + self.overrides.is_empty() + } + + /// Clears all overrides. + pub fn clear(&mut self) { + self.overrides.clear(); + } +} + +impl Default for FlagsOverride { + fn default() -> Self { + Self::new() + } +}