#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum WipeEvidence {
WipeNotCompleted,
WipedBestEffort,
WipedAttested,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum PhysicalProtection {
ProtectionAttested,
ProtectionConfirmedAbsent,
ProtectionUnknown,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum AccountingPosture {
Charged,
Reconciled,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum PendingStage {
Wipe,
ProtectionRemoval,
AccountingReconciliation,
Disposal,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum LifecyclePosture {
Live,
Closing {
stage: PendingStage,
},
Quarantined {
pending_stage: PendingStage,
},
PermanentlyQuarantined {
pending_stage: PendingStage,
},
Tombstoned {
last_stage: PendingStage,
disposition: AllocationPresence,
},
Closed,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum AllocationPresence {
Unknown,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum ProviderHealth {
Healthy,
Degraded,
Exhausted,
Shutdown,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum ResourceKind {
Identities,
LogicalBytes,
EffectivePages,
RegistryEntries,
RetryAttempts,
MaintenanceWork,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ProviderLimits {
pub max_identities: usize,
pub max_logical_bytes: usize,
pub max_effective_pages: usize,
pub max_registry_entries: usize,
pub max_retry_attempts: usize,
pub max_maintenance_work: usize,
pub page_size: usize,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ProtectionRequest {
logical_bytes: usize,
reserved_pages: usize,
attested: bool,
}
impl ProtectionRequest {
pub(crate) fn new(
logical_bytes: usize,
page_size: usize,
attested: bool,
) -> Result<Self, ProtectionError> {
if page_size == 0 {
return Err(ProtectionError::InvalidLimits);
}
let reserved_pages = if logical_bytes == 0 {
0
} else {
logical_bytes
.checked_add(page_size - 1)
.and_then(|len| len.checked_add(page_size - 1))
.map(|worst_case| worst_case / page_size)
.ok_or(ProtectionError::LengthOverflow)?
};
Ok(Self {
logical_bytes,
reserved_pages,
attested,
})
}
#[must_use]
pub const fn logical_bytes(self) -> usize {
self.logical_bytes
}
#[must_use]
pub const fn reserved_pages(self) -> usize {
self.reserved_pages
}
#[must_use]
pub const fn requires_attestation(self) -> bool {
self.attested
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum ProtectionError {
StaleAssurance,
ProtectionUnavailable,
ProviderUnavailable,
ProtectionResourceExhausted(ResourceKind),
LengthOverflow,
InvalidLimits,
ActualRangeExceededReservation,
}
impl core::fmt::Display for ProtectionError {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter.write_str(match self {
Self::StaleAssurance => "stale assurance evidence",
Self::ProtectionUnavailable => "required protected storage is unavailable",
Self::ProviderUnavailable => "protected-memory provider is unavailable",
Self::ProtectionResourceExhausted(_) => "protected-memory resource exhausted",
Self::LengthOverflow => "protected-memory length overflow",
Self::InvalidLimits => "invalid protected-memory limits",
Self::ActualRangeExceededReservation => {
"actual protected range exceeded its reservation"
}
})
}
}
#[cfg(feature = "std")]
impl std::error::Error for ProtectionError {}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum TeardownOperation {
Wipe,
ProtectionRemoval,
AccountingReconciliation,
Disposal,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum JournalDisposition {
NotApplied,
Applied,
Indeterminate,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct TeardownCursor {
pub operation: TeardownOperation,
pub disposition: JournalDisposition,
pub progress: usize,
}
impl TeardownCursor {
pub(crate) const fn new() -> Self {
Self {
operation: TeardownOperation::Wipe,
disposition: JournalDisposition::NotApplied,
progress: 0,
}
}
pub(crate) fn begin(&mut self, operation: TeardownOperation) {
self.operation = operation;
self.disposition = JournalDisposition::NotApplied;
self.progress = 0;
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum DisposalDisposition {
Applied,
NotApplied,
AllocationPresenceUnknown,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum CleanupOutcome {
Closed,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct CleanupReport {
pub outcome: CleanupOutcome,
pub wipe: WipeEvidence,
pub physical_protection: PhysicalProtection,
pub accounting: AccountingPosture,
pub lifecycle: LifecyclePosture,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct CleanupError {
pub pending_stage: PendingStage,
pub wipe: WipeEvidence,
pub physical_protection: PhysicalProtection,
pub accounting: AccountingPosture,
pub lifecycle: LifecyclePosture,
pub pending_substage: JournalDisposition,
pub retry_attempt: usize,
pub provider_health: ProviderHealth,
}
impl core::fmt::Display for CleanupError {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
formatter,
"protected cleanup stopped at {:?}",
self.pending_stage
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for CleanupError {}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ProviderReport {
pub health: ProviderHealth,
pub health_generation: usize,
pub protection_generation: usize,
pub active_and_reserved: usize,
pub quarantined: usize,
pub permanently_quarantined: usize,
pub tombstoned: usize,
pub charged_logical_bytes: usize,
pub charged_effective_pages: usize,
}