use std::{
convert::From,
error,
fmt::{Debug, Display},
io,
};
use std::os::raw::c_int;
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u32)]
pub enum SevError {
InvalidPlatformState = 0x0001,
InvalidGuestState = 0x0002,
InvalidConfig = 0x0003,
InvalidLen = 0x0004,
AlreadyOwned = 0x0005,
InvalidCertificate = 0x0006,
PolicyFailure = 0x0007,
Inactive = 0x0008,
InvalidAddress = 0x0009,
BadSignature = 0x000A,
BadMeasurement = 0x000B,
AsidOwned = 0x000C,
InvalidAsid = 0x000D,
WbinvdRequired = 0x000E,
DfFlushRequired = 0x000F,
InvalidGuest = 0x0010,
InvalidCommand = 0x0011,
Active = 0x0012,
HardwarePlatform = 0x0013,
HardwareUnsafe = 0x0014,
Unsupported = 0x0015,
InvalidParam = 0x0016,
ResourceLimit = 0x0017,
SecureDataInvalid = 0x0018,
InvalidPageSize = 0x0019,
InvalidPageState = 0x001A,
InvalidMdataEntry = 0x001B,
InvalidPageOwner = 0x001C,
AEADOFlow = 0x001D,
RbModeExited = 0x001F,
RMPInitRequired = 0x0020,
BadSvn = 0x0021,
BadVersion = 0x0022,
ShutdownRequired = 0x0023,
UpdateFailed = 0x0024,
RestoreRequired = 0x0025,
RMPInitFailed = 0x0026,
InvalidKey = 0x0027,
UnknownError = 0x0000,
}
impl std::fmt::Display for SevError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let code = *self as u32;
match self {
SevError::InvalidPlatformState => {
write!(f, "Status Code: 0x{:x}: Invalid platform state.", code)
}
SevError::InvalidGuestState => {
write!(f, "Status Code: 0x{:x}: Invalid guest state.", code)
}
SevError::InvalidConfig => write!(
f,
"Status Code: 0x{:x}: Platform configuration invalid.",
code
),
SevError::InvalidLen => {
write!(f, "Status Code: 0x{:x}: Memory buffer too small.", code)
}
SevError::AlreadyOwned => {
write!(f, "Status Code: 0x{:x}: Platform is already owned.", code)
}
SevError::InvalidCertificate => {
write!(f, "Status Code: 0x{:x}: Invalid certificate.", code)
}
SevError::PolicyFailure => write!(f, "Status Code: 0x{:x}: Policy failure.", code),
SevError::Inactive => write!(f, "Status Code: 0x{:x}: Guest is inactive.", code),
SevError::InvalidAddress => {
write!(f, "Status Code: 0x{:x}: Provided address is invalid.", code)
}
SevError::BadSignature => write!(
f,
"Status Code: 0x{:x}: Provided signature is invalid.",
code
),
SevError::BadMeasurement => write!(
f,
"Status Code: 0x{:x}: Provided measurement is invalid.",
code
),
SevError::AsidOwned => write!(f, "Status Code: 0x{:x}: ASID is already owned.", code),
SevError::InvalidAsid => write!(f, "Status Code: 0x{:x}: ASID is invalid.", code),
SevError::WbinvdRequired => {
write!(f, "Status Code: 0x{:x}: WBINVD instruction required.", code)
}
SevError::DfFlushRequired => write!(
f,
"Status Code: 0x{:x}: DF_FLUSH invocation required.",
code
),
SevError::InvalidGuest => {
write!(f, "Status Code: 0x{:x}: Guest handle is invalid.", code)
}
SevError::InvalidCommand => {
write!(f, "Status Code: 0x{:x}: Issued command is invalid.", code)
}
SevError::Active => write!(f, "Status Code: 0x{:x}: Guest is active.", code),
SevError::HardwarePlatform => {
write!(
f,
"Status Code: 0x{:x}: Hardware condition occured, safe to re-allocate parameter buffers.",
code
)
}
SevError::HardwareUnsafe => {
write!(
f,
"Status Code: 0x{:x}: Hardware condition occured, unsafe to re-allocate parameter buffers.",
code
)
}
SevError::Unsupported => {
write!(f, "Status Code: 0x{:x}: Feature is unsupported.", code)
}
SevError::InvalidParam => {
write!(f, "Status Code: 0x{:x}: Given parameter is invalid.", code)
}
SevError::ResourceLimit => {
write!(
f,
"Status Code: 0x{:x}: SEV firmware has run out of required resources to carry out command.",
code
)
}
SevError::SecureDataInvalid => write!(
f,
"Status Code: 0x{:x}: SEV platform observed a failed integrity check.",
code
),
SevError::InvalidPageSize => write!(
f,
"Status Code: 0x{:x}: The RMP page size is incorrect.",
code
),
SevError::InvalidPageState => write!(
f,
"Status Code: 0x{:x}: The RMP page state is incorrect.",
code
),
SevError::InvalidMdataEntry => write!(
f,
"Status Code: 0x{:x}: The metadata entry is invalid.",
code
),
SevError::InvalidPageOwner => write!(
f,
"Status Code: 0x{:x}: The page ownership is incorrect.",
code
),
SevError::AEADOFlow => write!(
f,
"Status Code: 0x{:x}: The AEAD algorithm would have overflowed.",
code
),
SevError::RbModeExited => write!(
f,
"Status Code: 0x{:x}: A Mailbox mode command was sent while the SEV FW was in Ring Buffer \
mode. Ring Buffer mode has been exited; the Mailbox mode command has \
been ignored. Retry is recommended.",
code
),
SevError::RMPInitRequired => write!(
f,
"Status Code: 0x{:x}: The RMP must be reinitialized.",
code
),
SevError::BadSvn => write!(
f,
"Status Code: 0x{:x}: SVN of provided image is lower than the committed SVN.",
code
),
SevError::BadVersion => write!(
f,
"Status Code: 0x{:x}: Firmware version anti-rollback.",
code
),
SevError::ShutdownRequired => write!(
f,
"Status Code: 0x{:x}: An invocation of SNP_SHUTDOWN is required to complete this action.",
code
),
SevError::UpdateFailed => write!(
f,
"Status Code: 0x{:x}: Update of the firmware internal state or a guest context page has failed.",
code
),
SevError::RestoreRequired => write!(
f,
"Status Code: 0x{:x}: Installation of the committed firmware image required.",
code
),
SevError::RMPInitFailed => write!(
f,
"Status Code: 0x{:x}: The RMP initialization failed.",
code
),
SevError::InvalidKey => write!(
f,
"Status Code: 0x{:x}: The key requested is invalid, not present, or not allowed.",
code
),
SevError::UnknownError => write!(f, "Unknown SEV Error"),
}
}
}
impl From<u64> for SevError {
fn from(value: u64) -> Self {
Self::from(value as u32)
}
}
impl From<u32> for SevError {
#[inline]
fn from(error: u32) -> SevError {
match error {
0x01 => SevError::InvalidPlatformState,
0x02 => SevError::InvalidGuestState,
0x03 => SevError::InvalidConfig,
0x04 => SevError::InvalidLen,
0x05 => SevError::AlreadyOwned,
0x06 => SevError::InvalidCertificate,
0x07 => SevError::PolicyFailure,
0x08 => SevError::Inactive,
0x09 => SevError::InvalidAddress,
0x0A => SevError::BadSignature,
0x0B => SevError::BadMeasurement,
0x0C => SevError::AsidOwned,
0x0D => SevError::InvalidAsid,
0x0E => SevError::WbinvdRequired,
0x0F => SevError::DfFlushRequired,
0x10 => SevError::InvalidGuest,
0x11 => SevError::InvalidCommand,
0x12 => SevError::Active,
0x13 => SevError::HardwarePlatform,
0x14 => SevError::HardwareUnsafe,
0x15 => SevError::Unsupported,
0x16 => SevError::InvalidParam,
0x17 => SevError::ResourceLimit,
0x18 => SevError::SecureDataInvalid,
0x19 => SevError::InvalidPageSize,
0x1A => SevError::InvalidPageState,
0x1B => SevError::InvalidMdataEntry,
0x1C => SevError::InvalidPageOwner,
0x1D => SevError::AEADOFlow,
0x1F => SevError::RbModeExited,
0x20 => SevError::RMPInitRequired,
0x21 => SevError::BadSvn,
0x22 => SevError::BadVersion,
0x23 => SevError::ShutdownRequired,
0x24 => SevError::UpdateFailed,
0x25 => SevError::RestoreRequired,
0x26 => SevError::RMPInitFailed,
0x27 => SevError::InvalidKey,
_ => SevError::UnknownError,
}
}
}
impl From<SevError> for c_int {
fn from(err: SevError) -> Self {
match err {
SevError::InvalidPlatformState => 0x01,
SevError::InvalidGuestState => 0x02,
SevError::InvalidConfig => 0x03,
SevError::InvalidLen => 0x04,
SevError::AlreadyOwned => 0x05,
SevError::InvalidCertificate => 0x06,
SevError::PolicyFailure => 0x07,
SevError::Inactive => 0x08,
SevError::InvalidAddress => 0x09,
SevError::BadSignature => 0x0A,
SevError::BadMeasurement => 0x0B,
SevError::AsidOwned => 0x0C,
SevError::InvalidAsid => 0x0D,
SevError::WbinvdRequired => 0x0E,
SevError::DfFlushRequired => 0x0F,
SevError::InvalidGuest => 0x10,
SevError::InvalidCommand => 0x11,
SevError::Active => 0x12,
SevError::HardwarePlatform => 0x13,
SevError::HardwareUnsafe => 0x14,
SevError::Unsupported => 0x15,
SevError::InvalidParam => 0x16,
SevError::ResourceLimit => 0x17,
SevError::SecureDataInvalid => 0x18,
SevError::InvalidPageSize => 0x19,
SevError::InvalidPageState => 0x1A,
SevError::InvalidMdataEntry => 0x1B,
SevError::InvalidPageOwner => 0x1C,
SevError::AEADOFlow => 0x1D,
SevError::RbModeExited => 0x1F,
SevError::RMPInitRequired => 0x20,
SevError::BadSvn => 0x21,
SevError::BadVersion => 0x22,
SevError::ShutdownRequired => 0x23,
SevError::UpdateFailed => 0x24,
SevError::RestoreRequired => 0x25,
SevError::RMPInitFailed => 0x26,
SevError::InvalidKey => 0x27,
SevError::UnknownError => -1,
}
}
}
impl std::error::Error for SevError {}
#[derive(Debug)]
pub enum FirmwareError {
KnownSev(SevError),
UnknownSev(u32),
Io(std::io::Error),
}
impl error::Error for FirmwareError {}
impl Display for FirmwareError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let err_description = match self {
FirmwareError::KnownSev(error) => format!("Known SEV FW Error: {error}"),
FirmwareError::UnknownSev(code) => {
format!("Unknown SEV FW Error Encountered: {code}")
}
FirmwareError::Io(error) => format!("IO Error Encountered: {error}"),
};
write!(f, "{err_description}")
}
}
impl std::convert::From<SevError> for FirmwareError {
fn from(sev_error: SevError) -> Self {
match sev_error {
SevError::UnknownError => FirmwareError::UnknownSev(sev_error as u32),
_ => FirmwareError::KnownSev(sev_error),
}
}
}
impl From<io::Error> for FirmwareError {
#[inline]
fn from(error: io::Error) -> FirmwareError {
FirmwareError::Io(error)
}
}
impl From<u64> for FirmwareError {
fn from(value: u64) -> Self {
Self::from(value as u32)
}
}
impl From<u32> for FirmwareError {
#[inline]
fn from(error: u32) -> FirmwareError {
match error {
0x00 => FirmwareError::Io(io::Error::last_os_error()),
0x01..0x027 => FirmwareError::KnownSev(error.into()),
_ => FirmwareError::UnknownSev(error),
}
}
}
impl From<FirmwareError> for c_int {
fn from(err: FirmwareError) -> Self {
match err {
FirmwareError::UnknownSev(_) | FirmwareError::Io(_) => -0x01,
FirmwareError::KnownSev(e) => e.into(),
}
}
}