smbioslib/structs/types/
processor_additional_information.rs

1use crate::core::{Handle, UndefinedStruct};
2use crate::SMBiosStruct;
3use serde::{ser::SerializeStruct, Serialize, Serializer};
4use std::fmt;
5use std::ops::Deref;
6
7/// # Processor Additional Information (Type 44)
8///
9/// The information in this structure defines the processor additional information in case SMBIOS type 4 [super::SMBiosProcessorInformation] is
10/// not sufficient to describe processor characteristics. The SMBIOS type 44 structure has a reference
11/// handle field to link back to the related SMBIOS type 4 structure. There may be multiple SMBIOS type 44
12/// structures linked to the same SMBIOS type 4 structure. For example, when cores are not identical in a
13/// processor, SMBIOS type 44 structures describe different core-specific information.
14///
15/// SMBIOS type 44 defines the standard header for the processor-specific block, while the
16/// contents of processor-specific data are maintained by processor architecture workgroups or vendors in
17/// separate documents.
18///
19/// Compliant with:
20/// DMTF SMBIOS Reference Specification 3.7.0 (DSP0134)
21/// Document Date: 2023-07-21
22pub struct SMBiosProcessorAdditionalInformation<'a> {
23    parts: &'a UndefinedStruct,
24}
25
26impl<'a> SMBiosStruct<'a> for SMBiosProcessorAdditionalInformation<'a> {
27    const STRUCT_TYPE: u8 = 44u8;
28
29    fn new(parts: &'a UndefinedStruct) -> Self {
30        Self { parts }
31    }
32
33    fn parts(&self) -> &'a UndefinedStruct {
34        self.parts
35    }
36}
37
38impl<'a> SMBiosProcessorAdditionalInformation<'a> {
39    /// Offset of the ProcessorSpecificBlock field.
40    const PROCESSOR_SPECIFIC_BLOCK_OFFSET: usize = 0x06usize;
41
42    /// Handle, or instance number, associated with the
43    /// [super::SMBiosProcessorInformation] structure (SMBIOS type 4) which the
44    /// Processor Additional Information structure describes.
45    pub fn referenced_handle(&self) -> Option<Handle> {
46        self.parts.get_field_handle(0x04)
47    }
48
49    /// Processor-Specific Block
50    pub fn processor_specific_block(&self) -> Option<ProcessorSpecificBlock<'_>> {
51        ProcessorSpecificBlock::new(self)
52    }
53}
54
55impl fmt::Debug for SMBiosProcessorAdditionalInformation<'_> {
56    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
57        fmt.debug_struct(std::any::type_name::<
58            SMBiosProcessorAdditionalInformation<'_>,
59        >())
60        .field("header", &self.parts.header)
61        .field("referenced_handle", &self.referenced_handle())
62        .field("processor_specific_block", &self.processor_specific_block())
63        .finish()
64    }
65}
66
67impl Serialize for SMBiosProcessorAdditionalInformation<'_> {
68    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
69    where
70        S: Serializer,
71    {
72        let mut state = serializer.serialize_struct("SMBiosProcessorAdditionalInformation", 3)?;
73        state.serialize_field("header", &self.parts.header)?;
74        state.serialize_field("referenced_handle", &self.referenced_handle())?;
75        state.serialize_field("processor_specific_block", &self.processor_specific_block())?;
76        state.end()
77    }
78}
79
80/// # Processor Specific Block contained within [SMBiosProcessorAdditionalInformation]
81pub struct ProcessorSpecificBlock<'a> {
82    /// Raw byte slice for this processor specific block
83    pub raw: &'a [u8],
84}
85
86impl<'a> ProcessorSpecificBlock<'a> {
87    /// 'block_length' offset
88    const BLOCK_LENGTH_OFFSET: usize = 0x00usize;
89    /// 'processor_type' offset
90    const PROCESSOR_TYPE_OFFSET: usize = 0x01usize;
91    /// 'processor_specific_data' offset
92    const PROCESSOR_SPECIFIC_DATA_OFFSET: usize = 0x02usize;
93
94    fn new(additional_information: &'a SMBiosProcessorAdditionalInformation<'a>) -> Option<Self> {
95        additional_information
96            .parts()
97            .get_field_byte(
98                SMBiosProcessorAdditionalInformation::PROCESSOR_SPECIFIC_BLOCK_OFFSET
99                    + Self::BLOCK_LENGTH_OFFSET,
100            )
101            .and_then(|block_length| {
102                additional_information
103                    .parts()
104                    .get_field_data(
105                        SMBiosProcessorAdditionalInformation::PROCESSOR_SPECIFIC_BLOCK_OFFSET
106                            + Self::BLOCK_LENGTH_OFFSET,
107                        block_length as usize
108                            + SMBiosProcessorAdditionalInformation::PROCESSOR_SPECIFIC_BLOCK_OFFSET
109                            + Self::PROCESSOR_SPECIFIC_DATA_OFFSET,
110                    )
111                    .map(|raw| Self { raw })
112            })
113    }
114
115    /// Length of 'processor_specific_data'
116    pub fn block_length(&self) -> u8 {
117        self.raw[Self::BLOCK_LENGTH_OFFSET]
118    }
119
120    /// The processor architecture delineated by this 'ProcessorSpecificBlock'.
121    pub fn processor_type(&self) -> ProcessorArchitectureTypeData {
122        ProcessorArchitectureTypeData::from(self.raw[Self::PROCESSOR_TYPE_OFFSET])
123    }
124
125    /// Offset of the field within the structure referenced by the
126    /// _Referenced Handle_ for which additional information is provided
127    pub fn processor_specific_data(&self) -> &'a [u8] {
128        &self.raw[Self::PROCESSOR_SPECIFIC_DATA_OFFSET..]
129    }
130}
131
132impl fmt::Debug for ProcessorSpecificBlock<'_> {
133    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
134        fmt.debug_struct(std::any::type_name::<ProcessorSpecificBlock<'_>>())
135            .field("block_length", &self.block_length())
136            .field("processor_type", &self.processor_type())
137            .field("processor_specific_data", &self.processor_specific_data())
138            .finish()
139    }
140}
141
142impl Serialize for ProcessorSpecificBlock<'_> {
143    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
144    where
145        S: Serializer,
146    {
147        let mut state = serializer.serialize_struct("ProcessorSpecificBlock", 3)?;
148        state.serialize_field("block_length", &self.block_length())?;
149        state.serialize_field("processor_type", &self.processor_type())?;
150        state.serialize_field("processor_specific_data", &self.processor_specific_data())?;
151        state.end()
152    }
153}
154
155/// # Processor Architecture Types Data
156pub struct ProcessorArchitectureTypeData {
157    /// Raw value
158    ///
159    /// _raw_ is most useful when _value_ is None.
160    /// This is most likely to occur when the standard was updated but
161    /// this library code has not been updated to match the current
162    /// standard.
163    pub raw: u8,
164    /// The contained [ProcessorArchitectureType] value
165    pub value: ProcessorArchitectureType,
166}
167
168impl fmt::Debug for ProcessorArchitectureTypeData {
169    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
170        fmt.debug_struct(std::any::type_name::<ProcessorArchitectureTypeData>())
171            .field("raw", &self.raw)
172            .field("value", &self.value)
173            .finish()
174    }
175}
176
177impl Serialize for ProcessorArchitectureTypeData {
178    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
179    where
180        S: Serializer,
181    {
182        let mut state = serializer.serialize_struct("ProcessorArchitectureTypeData", 2)?;
183        state.serialize_field("raw", &self.raw)?;
184        state.serialize_field("value", &self.value)?;
185        state.end()
186    }
187}
188
189impl fmt::Display for ProcessorArchitectureTypeData {
190    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191        match &self.value {
192            ProcessorArchitectureType::None => write!(f, "{}", &self.raw),
193            _ => write!(f, "{:?}", &self.value),
194        }
195    }
196}
197
198impl Deref for ProcessorArchitectureTypeData {
199    type Target = ProcessorArchitectureType;
200
201    fn deref(&self) -> &Self::Target {
202        &self.value
203    }
204}
205
206/// # Processor Architecture Types
207#[derive(Serialize, Debug, PartialEq, Eq)]
208pub enum ProcessorArchitectureType {
209    /// IA32 (x86)
210    IA32,
211    /// x64 (x86-64, Intel64, AMD64, EM64T)
212    X64,
213    /// IntelĀ® ItaniumĀ® architecture
214    IntelItanium,
215    /// 32-bit ARM (Aarch32)
216    Arm32Bit,
217    /// 64-bit ARM (Aarch64)
218    Arm64Bit,
219    /// 32-bit RISC-V (RV32)
220    RiscV32Bit,
221    /// 64-bit RISC-V (RV64)
222    RiscV64Bit,
223    /// 128-bit RISC-V (RV128)
224    RiscV128Bit,
225    /// 32-bit LoongArch (LoongArch32)
226    LoongArch32,
227    /// 64-bit LoongArch (LoongArch64)
228    LoongArch64,
229    /// A value unknown to this standard, check the raw value
230    None,
231}
232
233impl From<u8> for ProcessorArchitectureTypeData {
234    fn from(raw: u8) -> Self {
235        ProcessorArchitectureTypeData {
236            value: match raw {
237                0x01 => ProcessorArchitectureType::IA32,
238                0x02 => ProcessorArchitectureType::X64,
239                0x03 => ProcessorArchitectureType::IntelItanium,
240                0x04 => ProcessorArchitectureType::Arm32Bit,
241                0x05 => ProcessorArchitectureType::Arm64Bit,
242                0x06 => ProcessorArchitectureType::RiscV32Bit,
243                0x07 => ProcessorArchitectureType::RiscV64Bit,
244                0x08 => ProcessorArchitectureType::RiscV128Bit,
245                0x09 => ProcessorArchitectureType::LoongArch32,
246                0x10 => ProcessorArchitectureType::LoongArch64,
247                _ => ProcessorArchitectureType::None,
248            },
249            raw,
250        }
251    }
252}
253
254#[cfg(test)]
255mod tests {
256    use super::*;
257
258    #[test]
259    fn unit_test() {
260        let block_length = 3u8;
261        let processor_type = 0x07u8; // RiscV64Bit
262
263        let struct_type44 = vec![
264            44u8,
265            6 + block_length + 2,
266            0x2E,
267            0x00, // header
268            0x08,
269            0x09, // referenced handle
270            block_length,
271            processor_type,
272            0x03,
273            0x02,
274            0x01,
275            0x00,
276            0x00,
277        ];
278
279        let parts = UndefinedStruct::new(&struct_type44);
280        let test_struct = SMBiosProcessorAdditionalInformation::new(&parts);
281
282        assert_eq!(*test_struct.referenced_handle().unwrap(), 0x0908);
283        let processor_specific_block = test_struct.processor_specific_block().unwrap();
284        assert_eq!(processor_specific_block.block_length(), 3);
285        assert_eq!(
286            *processor_specific_block.processor_type(),
287            ProcessorArchitectureType::RiscV64Bit
288        );
289        assert_eq!(
290            processor_specific_block.processor_specific_data(),
291            &[0x03, 0x02, 0x01]
292        );
293    }
294}