1#[allow(unused_imports)]
6use crate::{tpm_enum, TpmErrorKind, TpmNotDiscriminant, TpmParse};
7use core::{
8 convert::TryFrom,
9 fmt::{self, Debug, Display, Formatter},
10};
11
12pub const TPM_RC_VER1: u32 = 0x0100;
13pub const TPM_RC_FMT1: u32 = 0x0080;
14pub const TPM_RC_WARN: u32 = 0x0900;
15pub const TPM_RC_P_BIT: u32 = 1 << 6;
16pub const TPM_RC_N_SHIFT: u32 = 8;
17pub const TPM_RC_FMT1_ERROR_MASK: u32 = 0x003F;
18
19const MAX_HANDLE_INDEX: u8 = 7;
20const SESSION_INDEX_OFFSET: u8 = 8;
21
22#[derive(Debug, PartialEq, Eq, Copy, Clone)]
23pub enum TpmRcIndex {
24 Parameter(u8),
25 Handle(u8),
26 Session(u8),
27}
28
29impl Display for TpmRcIndex {
30 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
31 match self {
32 Self::Parameter(i) => write!(f, "parameter[{i}]"),
33 Self::Handle(i) => write!(f, "handle[{i}]"),
34 Self::Session(i) => write!(f, "session[{i}]"),
35 }
36 }
37}
38
39tpm_enum! {
40 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
41 #[allow(clippy::upper_case_acronyms)]
42 pub enum TpmRcBase(u32) {
43 (Success, 0x0000, "TPM_RC_SUCCESS"),
44 (BadTag, 0x001E, "TPM_RC_BAD_TAG"),
45 (Initialize, TPM_RC_VER1, "TPM_RC_INITIALIZE"),
46 (Failure, TPM_RC_VER1 | 0x001, "TPM_RC_FAILURE"),
47 (AuthMissing, TPM_RC_VER1 | 0x025, "TPM_RC_AUTH_MISSING"),
48 (CommandSize, TPM_RC_VER1 | 0x042, "TPM_RC_COMMAND_SIZE"),
49 (Sensitive, TPM_RC_VER1 | 0x055, "TPM_RC_SENSITIVE"),
50 (Asymmetric, TPM_RC_FMT1 | 0x001, "TPM_RC_ASYMMETRIC"),
51 (Attributes, TPM_RC_FMT1 | 0x002, "TPM_RC_ATTRIBUTES"),
52 (Value, TPM_RC_FMT1 | 0x004, "TPM_RC_VALUE"),
53 (Handle, TPM_RC_FMT1 | 0x00B, "TPM_RC_HANDLE"),
54 (AuthFail, TPM_RC_FMT1 | 0x00E, "TPM_RC_AUTH_FAIL"),
55 (Size, TPM_RC_FMT1 | 0x015, "TPM_RC_SIZE"),
56 (BadAuth, TPM_RC_FMT1 | 0x022, "TPM_RC_BAD_AUTH"),
57 (Curve, TPM_RC_FMT1 | 0x026, "TPM_RC_CURVE"),
58 (ContextGap, TPM_RC_WARN | 0x001, "TPM_RC_CONTEXT_GAP"),
59 (NvUnavailable, TPM_RC_WARN | 0x023, "TPM_RC_NV_UNAVAILABLE"),
60 }
61}
62
63fn get_base_code(value: u32) -> u32 {
65 if (value & TPM_RC_FMT1) != 0 {
66 TPM_RC_FMT1 | (value & TPM_RC_FMT1_ERROR_MASK)
67 } else {
68 value
69 }
70}
71
72#[must_use]
73#[derive(Debug, PartialEq, Eq, Copy, Clone)]
74pub struct TpmRc(u32);
75impl TpmRc {
76 pub fn base(self) -> Result<TpmRcBase, TpmErrorKind> {
84 TpmRcBase::try_from(get_base_code(self.0)).map_err(|()| TpmErrorKind::Unreachable)
85 }
86
87 #[must_use]
88 pub fn index(self) -> Option<TpmRcIndex> {
89 let value = self.0;
90 if (value & TPM_RC_FMT1) == 0 {
91 return None;
92 }
93 let is_parameter = (value & TPM_RC_P_BIT) != 0;
94 let n = ((value >> TPM_RC_N_SHIFT) & 0b1111) as u8;
95
96 match (is_parameter, n) {
97 (_, 0) => None,
98 (true, num) => Some(TpmRcIndex::Parameter(num)),
99 (false, num @ 1..=MAX_HANDLE_INDEX) => Some(TpmRcIndex::Handle(num)),
100 (false, num) => Some(TpmRcIndex::Session(num - SESSION_INDEX_OFFSET)),
101 }
102 }
103
104 #[must_use]
105 pub fn value(self) -> u32 {
106 self.0
107 }
108 #[must_use]
109 pub fn is_warning(self) -> bool {
110 (self.0 & TPM_RC_WARN) == TPM_RC_WARN
111 }
112 #[must_use]
113 pub fn is_error(self) -> bool {
114 !self.is_warning() && self.0 != 0
115 }
116}
117
118impl crate::TpmSized for TpmRc {
119 const SIZE: usize = core::mem::size_of::<u32>();
120 fn len(&self) -> usize {
121 Self::SIZE
122 }
123}
124
125impl crate::TpmBuild for TpmRc {
126 fn build(&self, writer: &mut crate::TpmWriter) -> crate::TpmResult<()> {
127 self.0.build(writer)
128 }
129}
130
131impl crate::TpmParse for TpmRc {
132 fn parse(buf: &[u8]) -> crate::TpmResult<(Self, &[u8])> {
133 let (val, remainder) = u32::parse(buf)?;
134 let rc = Self::try_from(val)?;
135 Ok((rc, remainder))
136 }
137}
138
139impl TryFrom<u32> for TpmRc {
140 type Error = TpmErrorKind;
141 fn try_from(value: u32) -> Result<Self, Self::Error> {
142 let base_code = get_base_code(value);
143 TpmRcBase::try_from(base_code).map_err(|()| {
144 TpmErrorKind::NotDiscriminant(
145 "TpmRcBase",
146 TpmNotDiscriminant::Unsigned(u64::from(base_code)),
147 )
148 })?;
149 Ok(Self(value))
150 }
151}
152
153impl From<TpmRcBase> for TpmRc {
154 fn from(value: TpmRcBase) -> Self {
155 Self(value as u32)
156 }
157}
158
159impl Display for TpmRc {
160 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
161 if let Ok(base) = self.base() {
162 if let Some(index) = self.index() {
163 write!(f, "[{base}, {index}]")
164 } else {
165 write!(f, "{base}")
166 }
167 } else {
168 write!(f, "TPM_RC_UNKNOWN(0x{:08X})", self.0)
169 }
170 }
171}