use thiserror::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TeeErrorOrigin {
NotTrustedOs,
TrustedOs,
TrustedApplication,
Api,
Unknown,
}
impl From<optee_teec::ErrorOrigin> for TeeErrorOrigin {
fn from(o: optee_teec::ErrorOrigin) -> Self {
match o {
optee_teec::ErrorOrigin::COMMS => Self::NotTrustedOs,
optee_teec::ErrorOrigin::TEE => Self::TrustedOs,
optee_teec::ErrorOrigin::TA => Self::TrustedApplication,
optee_teec::ErrorOrigin::API => Self::Api,
_ => Self::Unknown,
}
}
}
#[derive(Debug, Error)]
pub enum TeeError {
#[error("failed to initialise TEE context: {0}")]
Context(#[source] optee_teec::Error),
#[error("failed to open TEE session: {0}")]
Session(#[source] optee_teec::Error),
#[error("TEE command failed (code={code:#010x}, origin={origin:?})")]
Invoke {
code: u32,
origin: TeeErrorOrigin,
#[source]
source: optee_teec::Error,
},
#[error("TEE parameter type mismatch")]
ParamMismatch,
#[error("TEE output buffer too small: need {need} bytes, have {have}")]
BufferTooSmall { need: usize, have: usize },
#[error("TEE commands accept at most 4 parameters, got {0}")]
TooManyParams(usize),
#[error("TEE async task failed: {0}")]
JoinError(#[from] tokio::task::JoinError),
#[error("all TEE sessions are busy")]
Busy,
}
impl TeeError {
pub fn is_transient(&self) -> bool {
match self {
Self::Busy => true,
Self::Session(e) | Self::Context(e) => {
matches!(e.kind(), optee_teec::ErrorKind::Busy)
}
_ => false,
}
}
pub fn ta_error_code(&self) -> Option<u32> {
match self {
Self::Invoke { code, .. } => Some(*code),
_ => None,
}
}
}
pub type TeeResult<T> = Result<T, TeeError>;
impl From<optee_teec::Error> for TeeError {
fn from(e: optee_teec::Error) -> Self {
let code = e.raw_code();
let origin = e
.origin()
.map(TeeErrorOrigin::from)
.unwrap_or(TeeErrorOrigin::Unknown);
TeeError::Invoke {
code,
origin,
source: e,
}
}
}