smbios-lib-0.9.2/.cargo/config.toml000064400000000000000000000000661046102023000152110ustar 00000000000000[target.x86_64-unknown-linux-gnu] runner = 'sudo -E' smbios-lib-0.9.2/.cargo_vcs_info.json0000644000000001360000000000100131040ustar { "git": { "sha1": "1d82e36a90d51bd23f66857765e5afadabe0dd6f" }, "path_in_vcs": "" }smbios-lib-0.9.2/.devcontainer/devcontainer.json000064400000000000000000000022571046102023000200150ustar 00000000000000// For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/rust { "name": "Rust", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile "image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye", "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined", "--privileged" ] // Use 'mounts' to make the cargo cache persistent in a Docker Volume. // "mounts": [ // { // "source": "devcontainer-cargo-cache-${devcontainerId}", // "target": "/usr/local/cargo", // "type": "volume" // } // ] // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], // Use 'postCreateCommand' to run commands after the container is created. // "postCreateCommand": "rustc --version", // Configure tool-specific properties. // "customizations": {}, // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. // "remoteUser": "root" } smbios-lib-0.9.2/.github/workflows/smbios_ci.yml000064400000000000000000000010121046102023000177550ustar 00000000000000name: smbioslib_ci on: push: branches: [ main ] pull_request: branches: [ main ] types: [ labeled ] env: CARGO_TERM_COLOR: always jobs: build: if: ${{ github.event.label.name == 'Ready for Review' }} || github.event_name == 'push' runs-on: ${{ matrix.os }} strategy: matrix: os: [macos-latest, ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v2 - name: Build run: cargo build --verbose - name: Run tests run: cargo test --verbosesmbios-lib-0.9.2/.gitignore000064400000000000000000000005001046102023000136570ustar 00000000000000# Generated by Cargo # will have compiled files and executables /target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk smbios-lib-0.9.2/CODE_OF_CONDUCT.md000064400000000000000000000121321046102023000144720ustar 00000000000000# Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at jrgerber. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. smbios-lib-0.9.2/Cargo.lock0000644000000076730000000000100110740ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "core-foundation" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "getopts" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ "unicode-width", ] [[package]] name = "io-kit-sys" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b" dependencies = [ "core-foundation-sys", "mach2", ] [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "libc" version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "mach2" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" dependencies = [ "libc", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "proc-macro2" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "serde" version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "smbios-lib" version = "0.9.2" dependencies = [ "core-foundation", "core-foundation-sys", "getopts", "io-kit-sys", "libc", "mach2", "serde", "serde_json", ] [[package]] name = "syn" version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "unicode-ident" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-width" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" smbios-lib-0.9.2/Cargo.toml0000644000000036050000000000100111060ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "smbios-lib" version = "0.9.2" authors = [ "Jeffrey R. Gerber ", "Ante Čulo ", "Juan Zuluaga ", ] build = false autobins = false autoexamples = false autotests = false autobenches = false description = "SMBIOS Library" homepage = "https://github.com/jrgerber/smbios-lib" readme = "README.md" keywords = [ "bios", "smbios", "dmtf", ] categories = ["hardware-support"] license-file = "LICENSE" repository = "https://github.com/jrgerber/smbios-lib" [lib] name = "smbioslib" path = "src/lib.rs" [[bin]] name = "smbiosdump" path = "src/main.rs" [[test]] name = "integration_test" path = "tests/integration_test.rs" [dependencies.getopts] version = "0.2.21" [dependencies.serde] version = "1" features = ["derive"] [dependencies.serde_json] version = "~1.0" [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.core-foundation] version = "~0.10" [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.core-foundation-sys] version = "~0.8" [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.io-kit-sys] version = "~0.4" [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.libc] version = "~0.2" [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.mach2] version = "~0.4" [target."cfg(windows)".dependencies.libc] version = "0.2" smbios-lib-0.9.2/Cargo.toml.orig000064400000000000000000000017241046102023000145670ustar 00000000000000[package] name = "smbios-lib" version = "0.9.2" authors = ["Jeffrey R. Gerber ", "Ante Čulo ", "Juan Zuluaga "] license-file = "LICENSE" edition = "2018" description = "SMBIOS Library" homepage = "https://github.com/jrgerber/smbios-lib" repository = "https://github.com/jrgerber/smbios-lib" readme = "README.md" keywords = ["bios", "smbios", "dmtf"] categories = ["hardware-support"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] name = "smbioslib" path = "src/lib.rs" [[bin]] name = "smbiosdump" path = "src/main.rs" [dependencies] getopts = "0.2.21" serde = { version = "1", features = ["derive"] } serde_json = "~1.0" [target.'cfg(windows)'.dependencies] libc = "0.2" [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] libc = "~0.2" mach2 = "~0.4" core-foundation = "~0.10" core-foundation-sys = "~0.8" io-kit-sys = "~0.4" smbios-lib-0.9.2/LICENSE000064400000000000000000000020511046102023000126770ustar 00000000000000MIT License Copyright (c) 2021 jrgerber Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. smbios-lib-0.9.2/README.md000064400000000000000000000135611046102023000131610ustar 00000000000000# smbios-lib An SMBIOS Library created in Rust that reads and parses raw BIOS data [![crates.io](https://img.shields.io/crates/v/smbios-lib.svg)](https://crates.io/crates/smbios-lib) [![smbioslib_ci](https://github.com/jrgerber/smbios-lib/actions/workflows/smbios_ci.yml/badge.svg)](https://github.com/jrgerber/smbios-lib/actions/workflows/smbios_ci.yml) ![LOC](https://tokei.rs/b1/github/jrgerber/smbios-lib?category=code) ## Table of contents * [General info](#general-info) * [Dependencies](#dependencies) * [Security](#security) * [Examples](#examples) ## General info This project reads raw [SMBIOS](https://en.wikipedia.org/wiki/BIOS) data from either a device or file and provides the data as an API. For an example project using this library take a look at [dmidecode-rs](https://github.com/jrgerber/dmidecode-rs). ### Supports * [DMTF System Management BIOS (SMBIOS) Reference Specification 3.7.0](https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.0.pdf) * Linux * MacOS * Windows family > SMBIOS 3.7.0 contains 49 defined structure types, all of which are covered by this library (types 0-46, 126, and 127). Support via extensibility exists for types 128-255 (reserved for OEMs). Extensibility also applies in the case when this library has not been updated for the latest specification version or a pre-released specification and a new type is introduced. ### Project Status In early development. The current development stage is to finalize the API design. ## Dependencies * Windows * libc = "^0.2" * MacOS * libc = "^0.2" * mach2 = "^0.4.1" * core-foundation = "~0.9" * core-foundation-sys = "~0.8" * io-kit-sys = "^0.4.0" ## Security This library design follows a strict security mantra: *"Never trust the input"*. SMBIOS has been around for decades and has undergone many versions and revisions. Many OEM vendors have interpreted and implemented the specifications over the years. Known cases of incorrect firmware implementations exist. This presents a veritable labrynth of logic for both the known and the unknown. Rather than creating such a complex state machine, we take advantage of Rust's [Option<>](https://doc.rust-lang.org/std/option/) trait and assert that the act of retrieval for any and all information may fail. The burden of proof thus shifts from the library to the library consumer who is required to implement the failing condition arm. ## Examples ### Retrieve a Field of a Single Instance Structure Some structures are required and are a single instance. (e.g. [SMBiosSystemInformation](src/structs/types/system_information.rs)) ```rust #[test] /// Retrieves the System UUID from a device. /// UUID is found in the System Information (type 1) structure fn retrieve_system_uuid() { match table_load_from_device() { Ok(data) => match data.find_map(|sys_info: SMBiosSystemInformation| sys_info.uuid()) { Some(uuid) => println!("System Information UUID == {:?}", uuid), None => println!("No System Information (Type 1) structure found with a UUID field"), }, Err(err) => println!("failure: {:?}", err), } } ``` Output: ``` running 1 test System Information UUID == Uuid(4ee6523f-d56a-f3ea-8e2a-891cf96286ea) test retrieve_system_uuid ... ok ``` ### Retrieve All Instances of a Structure - collect() Some structures are allowed to have more than one instance. (e.g. [SMBiosMemoryDevice](src/structs/types/memory_device.rs)) ```rust #[test] /// Prints information for all memory devices within a device. fn print_all_memory_devices() { match table_load_from_device() { Ok(data) => { for memory_device in data.collect::() { println!("{:#?}", memory_device); } } Err(err) => println!("failure: {:?}", err), } } ``` Output: ``` running 1 test smbioslib::structs::types::memory_device::SMBiosMemoryDevice { header: smbioslib::core::header::Header { struct_type: 17, length: 40, handle: smbioslib::structs::structure::Handle { handle: 8, }, }, physical_memory_array_handle: Some( smbioslib::structs::structure::Handle { handle: 1, }, ), [...elided...] ``` ### Retrieve a Structure Given a Handle - find_by_handle() Some structures point to other structures via handles. (e.g. [SMBiosMemoryDevice](src/structs/types/memory_device.rs) points to [SMBiosPhysicalMemoryArray](src/structs/types/physical_memory_array.rs)) ```rust /// Finds an associated struct by handle #[test] fn struct_struct_association() { match table_load_from_device() { Ok(data) => match data.first::() { Some(first_memory_device) => { let handle = first_memory_device.physical_memory_array_handle().unwrap(); match data.find_by_handle(&handle) { Some(undefined_struct) => { let physical_memory_array = undefined_struct.defined_struct(); println!("{:#?}", physical_memory_array) } None => println!("No Physical Memory Array (Type 16) structure found"), } } None => println!("No Memory Device (Type 17) structure found"), }, Err(err) => println!("failure: {:?}", err), } } ``` Output: ``` running 1 test PhysicalMemoryArray( smbioslib::structs::types::physical_memory_array::SMBiosPhysicalMemoryArray { header: smbioslib::core::header::Header { struct_type: 16, length: 23, handle: smbioslib::structs::structure::Handle { handle: 1, }, }, location: Some( smbioslib::structs::types::physical_memory_array::MemoryArrayLocationData { raw: 3, value: SystemBoardOrMotherboard, }, ), [...elided...] ``` smbios-lib-0.9.2/src/core/entry_point.rs000064400000000000000000000606521046102023000163440ustar 00000000000000use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::{ convert::TryFrom, convert::TryInto, fmt, fs::{read, File}, io::{prelude::*, Error, ErrorKind, SeekFrom}, num::Wrapping, ops::RangeBounds, path::Path, }; /// # SMBIOS 2.1 (32 bit) Entry Point structure /// /// On non-UEFI systems, the 32-bit SMBIOS Entry Point structure, can be located by application software /// by searching for the anchor-string on paragraph (16-byte) boundaries within the physical memory address /// range 000F0000h to 000FFFFFh. This entry point encapsulates an intermediate anchor string that is used /// by some existing DMI browsers. /// /// On UEFI-based systems, the SMBIOS Entry Point structure can be located by looking in the EFI /// Configuration Table for the SMBIOS GUID (SMBIOS_TABLE_GUID, {EB9D2D31-2D88-11D3-9A16- /// 0090273FC14D}) and using the associated pointer. See section 4.6 of the UEFI Specification for details. /// See section 2.3 of the UEFI Specification for how to report the containing memory type. pub struct SMBiosEntryPoint32 { raw: Vec, } impl<'a> SMBiosEntryPoint32 { /// Minimum acceptable size of this structure /// /// TODO: Review DMTF SMBIOS document history and see /// if structure sizes smaller than 0x1F existed. If /// so then change this structure design to return Option<> /// values and adjust this size accordingly. pub const MINIMUM_SIZE: usize = 0x1F; /// Anchor String "_SM_" (offset 0) pub const SM_ANCHOR: [u8; 4] = [b'_', b'S', b'M', b'_']; /// Anchor String "_DMI_" (offset 0x10) pub const DMI_ANCHOR: [u8; 5] = [b'_', b'D', b'M', b'I', b'_']; /// Entry Point Structure Checksum Offset pub const ENTRY_POINT_STRUCTURE_CHECKSUM_OFFSET: usize = 0x04; /// Entry Point Length Offset pub const ENTRY_POINT_LENGTH_OFFSET: usize = 0x05; /// SMBIOS Major Version Offset pub const MAJOR_VERSION_OFFSET: usize = 0x06; /// SMBIOS Minor Version Offset pub const MINOR_VERSION_OFFSET: usize = 0x07; /// Maximum Structure Size Offset pub const MAXIMUM_STRUCTURE_SIZE_OFFSET: usize = 0x08; /// Entry Point Revision Offset pub const ENTRY_POINT_REVISION_OFFSET: usize = 0x0A; /// Formatted Area Offset pub const FORMATTED_AREA_OFFSET: usize = 0x0B; /// Intermediate Anchor String Offset /// /// NOTE: This field is paragraph-aligned, to allow legacy DMI browsers to /// find this entry point within the SMBIOS Entry Point Structure. pub const INTERMEDIATE_ANCHOR_OFFSET: usize = 0x10; /// Intermediate Checksum Offset pub const INTERMEDIATE_CHECKSUM_OFFSET: usize = 0x15; /// Structure Table Length Offset pub const STRUCTURE_TABLE_LENGTH_OFFSET: usize = 0x16; /// Structure Table Address Offset pub const STRUCTURE_TABLE_ADDRESS_OFFSET: usize = 0x18; /// Number of SMBIOS Structures Offset pub const NUMBER_OF_SMBIOS_STRUCTURES_OFFSET: usize = 0x1C; /// SMBIOS BCD Revision Offset pub const BCD_REVISION_OFFSET: usize = 0x1E; /// Entry Point Structure Checksum /// /// Checksum of the Entry Point Structure (EPS) /// /// This value, when added to all other bytes in the EPS, results in /// the value 00h (using 8-bit addition calculations). Values in the /// EPS are summed starting at offset 00h, for `entry_point_length` /// bytes. pub fn entry_point_structure_checksum(&self) -> u8 { self.raw[Self::ENTRY_POINT_STRUCTURE_CHECKSUM_OFFSET] } /// Entry Point Length /// /// Length of the Entry Point Structure, starting with the Anchor String /// field, in bytes, currently 1Fh /// /// NOTE: This value was incorrectly stated in version 2.1 of this specification /// as 1Eh. Because of this, there might be version 2.1 /// implementations that use either the 1Eh or the 1Fh value, but /// version 2.2 or later implementations must use the 1Fh value. pub fn entry_point_length(&self) -> u8 { self.raw[Self::ENTRY_POINT_LENGTH_OFFSET] } /// SMBIOS Major Version /// /// Major version of this specification implemented in the table /// structures (for example, the value is 0Ah (10) for revision 10.22 and /// 02h for revision 2.1) pub fn major_version(&self) -> u8 { self.raw[Self::MAJOR_VERSION_OFFSET] } /// SMBIOS Minor Version /// /// Minor version of this specification implemented in the table /// structures (for example, the value is 16h (22) for revision 10.22 and /// 01h for revision 2.1) pub fn minor_version(&self) -> u8 { self.raw[Self::MINOR_VERSION_OFFSET] } /// Maximum Structure Size /// /// Size of the largest SMBIOS structure, in bytes, and encompasses /// the structure’s formatted area and text strings pub fn maximum_structure_size(&self) -> u16 { u16::from_le_bytes( self.raw[Self::MAXIMUM_STRUCTURE_SIZE_OFFSET..Self::MAXIMUM_STRUCTURE_SIZE_OFFSET + 2] .try_into() .expect("u16 is 2 bytes"), ) } /// Entry Point Revision /// /// EPS revision implemented in this structure and identifies the /// formatting of offsets 0Bh to 0Fh as follows: /// - 00h Entry Point is based on SMBIOS 2.1 definition; formatted area is reserved and set to all 00h. /// - 01h-FFh Reserved for assignment by this specification pub fn entry_point_revision(&self) -> u8 { self.raw[Self::ENTRY_POINT_REVISION_OFFSET] } /// Formatted Area /// /// Value present in the `entry_point_revision` field defines the /// interpretation to be placed upon these 5 bytes pub fn formatted_area(&self) -> [u8; 5] { self.raw[Self::FORMATTED_AREA_OFFSET..Self::FORMATTED_AREA_OFFSET + 5] .try_into() .expect("5 bytes") } /// Intermediate Anchor String /// /// _DMI_, specified as five ASCII characters (5F 44 4D 49 5F). pub fn intermediate_anchor(&self) -> [u8; 5] { self.raw[Self::INTERMEDIATE_ANCHOR_OFFSET..Self::INTERMEDIATE_ANCHOR_OFFSET + 5] .try_into() .expect("5 bytes") } /// Intermediate Checksum /// /// Checksum of Intermediate Entry Point Structure (IEPS). /// /// This value, when added to all other bytes in the IEPS, results in /// the value 00h (using 8-bit addition calculations). Values in the /// IEPS are summed starting at offset 10h, for 0Fh bytes. pub fn intermediate_checksum(&self) -> u8 { self.raw[Self::INTERMEDIATE_CHECKSUM_OFFSET] } /// Structure Table Length /// /// Total length of SMBIOS Structure Table, pointed to by the /// `structure_table_address`, in bytes pub fn structure_table_length(&self) -> u16 { u16::from_le_bytes( self.raw[Self::STRUCTURE_TABLE_LENGTH_OFFSET..Self::STRUCTURE_TABLE_LENGTH_OFFSET + 2] .try_into() .expect("u16 is 2 bytes"), ) } /// Structure Table Address /// /// 32-bit physical starting address of the read-only SMBIOS /// Structure Table, which can start at any 32-bit address /// This area contains all of the SMBIOS structures fully packed /// together. These structures can then be parsed to produce exactly /// the same format as that returned from a Get SMBIOS Structure /// function call. pub fn structure_table_address(&self) -> u32 { u32::from_le_bytes( self.raw [Self::STRUCTURE_TABLE_ADDRESS_OFFSET..Self::STRUCTURE_TABLE_ADDRESS_OFFSET + 4] .try_into() .expect("u32 is 4 bytes"), ) } /// Number of SMBIOS Structures /// /// Total number of structures present in the SMBIOS Structure Table /// This is the value returned as NumStructures from the Get /// SMBIOS Information function. pub fn number_of_smbios_structures(&self) -> u16 { u16::from_le_bytes( self.raw[Self::NUMBER_OF_SMBIOS_STRUCTURES_OFFSET ..Self::NUMBER_OF_SMBIOS_STRUCTURES_OFFSET + 2] .try_into() .expect("u16 is 2 bytes"), ) } /// SMBIOS BCD Revision /// /// Indicates compliance with a revision of this specification /// It is a BCD value where the upper nibble indicates the major /// version and the lower nibble the minor version. For revision 2.1, /// the returned value is 21h. If the value is 00h, only the Major and /// Minor Versions in offsets 6 and 7 of the Entry Point Structure /// provide the version information. pub fn bcd_revision(&self) -> u8 { self.raw[Self::BCD_REVISION_OFFSET] } /// Load this structure from a file pub fn try_load_from_file(filename: &Path) -> Result { read(filename)?.try_into() } /// Load this structure by scanning a file within the given offsets, /// looking for the [SMBiosEntryPoint32::SM_ANCHOR] string. pub fn try_scan_from_file>( file: &mut File, range: T, ) -> Result where T: RangeBounds, { let mut anchor = [0; 4]; for offset in range.step_by(0x10) { file.seek(SeekFrom::Start(offset))?; file.read_exact(&mut anchor)?; if anchor == Self::SM_ANCHOR { let mut length = [0; 2]; file.read_exact(&mut length)?; let struct_length = length[1] as usize; let mut entry_point_buffer = Vec::with_capacity(struct_length); entry_point_buffer.resize(struct_length, 0); file.seek(SeekFrom::Start(offset))?; file.read_exact(&mut entry_point_buffer)?; let entry_point: Self = entry_point_buffer.try_into()?; return Ok(entry_point); } } Err(Error::new(ErrorKind::UnexpectedEof, "Not found")) } } impl<'a> TryFrom> for SMBiosEntryPoint32 { type Error = Error; fn try_from(raw: Vec) -> Result { if raw.len() < Self::MINIMUM_SIZE { return Err(Error::new( ErrorKind::InvalidData, "Slice is smaller than SMBiosEntryPoint32::MINIMUM_SIZE", )); } if !raw .iter() .zip(Self::SM_ANCHOR.iter()) .all(|pair| pair.0 == pair.1) { return Err(Error::new(ErrorKind::InvalidData, "_SM_ anchor not found")); } // Verify the EPS checksum // The checksum is calculated for a length of `entry_point_length` let entry_point_length = raw[Self::ENTRY_POINT_LENGTH_OFFSET] as usize; match raw.get(0..entry_point_length) { Some(checked_bytes) => { if !verify_checksum(checked_bytes) { return Err(Error::new( ErrorKind::InvalidData,"Entry Point Structure checksum verification failed")); } } None => return Err(Error::new( ErrorKind::InvalidData,"The Entry Point Length field specified a value which exceeded the bounds of the Entry Point Structure")), } let intermediate_anchor: [u8; 5] = raw [Self::INTERMEDIATE_ANCHOR_OFFSET..Self::INTERMEDIATE_ANCHOR_OFFSET + 5] .try_into() .expect("5 bytes"); if !intermediate_anchor .iter() .zip(Self::DMI_ANCHOR.iter()) .all(|pair| pair.0 == pair.1) { return Err(Error::new(ErrorKind::InvalidData, "_DMI_ anchor not found")); } // Verify the IEPS checksum // The checksum is calculated for a length of 0x0F let intermediate_entry_point_structure: [u8; 0x0F] = raw [Self::INTERMEDIATE_ANCHOR_OFFSET..] .try_into() .expect("0x0F bytes"); if !verify_checksum(&intermediate_entry_point_structure) { return Err(Error::new( ErrorKind::InvalidData, "Intermediate entry point structure checksum verification failed", )); } Ok(SMBiosEntryPoint32 { raw }) } } impl fmt::Debug for SMBiosEntryPoint32 { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field( "entry_point_structure_checksum", &self.entry_point_structure_checksum(), ) .field("entry_point_length", &self.entry_point_length()) .field("major_version", &self.major_version()) .field("minor_version", &self.minor_version()) .field("maximum_structure_size", &self.maximum_structure_size()) .field("entry_point_revision", &self.entry_point_revision()) .field("formatted_area", &self.formatted_area()) .field("intermediate_anchor", &self.intermediate_anchor()) .field("intermediate_checksum", &self.intermediate_checksum()) .field("structure_table_length", &self.structure_table_length()) .field("structure_table_address", &self.structure_table_address()) .field( "number_of_smbios_structures", &self.number_of_smbios_structures(), ) .field("bcd_revision", &self.bcd_revision()) .finish() } } impl Serialize for SMBiosEntryPoint32 { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosEntryPoint32", 13)?; state.serialize_field( "entry_point_structure_checksum", &self.entry_point_structure_checksum(), )?; state.serialize_field("entry_point_length", &self.entry_point_length())?; state.serialize_field("major_version", &self.major_version())?; state.serialize_field("minor_version", &self.minor_version())?; state.serialize_field("maximum_structure_size", &self.maximum_structure_size())?; state.serialize_field("entry_point_revision", &self.entry_point_revision())?; state.serialize_field("formatted_area", &self.formatted_area())?; state.serialize_field("intermediate_anchor", &self.intermediate_anchor())?; state.serialize_field("intermediate_checksum", &self.intermediate_checksum())?; state.serialize_field("structure_table_length", &self.structure_table_length())?; state.serialize_field("structure_table_address", &self.structure_table_address())?; state.serialize_field( "number_of_smbios_structures", &self.number_of_smbios_structures(), )?; state.serialize_field("bcd_revision", &self.bcd_revision())?; state.end() } } /// # SMBIOS 3.0 (64 bit) Entry Point structure /// /// On non-UEFI systems, the 64-bit SMBIOS Entry Point structure can be located by application software by /// searching for the anchor-string on paragraph (16-byte) boundaries within the physical memory address /// range 000F0000h to 000FFFFFh. /// /// On UEFI-based systems, the SMBIOS Entry Point structure can be located by looking in the EFI /// Configuration Table for the SMBIOS 3.x GUID (SMBIOS3_TABLE_GUID, {F2FD1544-9794-4A2C-992E836 E5BBCF20E394}) and using the associated pointer. See section 4.6 of the UEFI Specification for details. /// See section 2.3 of the UEFI Specification for how to report the containing memory type. pub struct SMBiosEntryPoint64 { raw: Vec, } impl<'a> SMBiosEntryPoint64 { /// Minimum acceptable size of this structure /// /// TODO: Review DMTF SMBIOS document history and see /// if structure sizes smaller than 0x18 existed. If /// so then change this structure design to return Option<> /// values and adjust this size accordingly. pub const MINIMUM_SIZE: usize = 0x18; /// Anchor String "_SM3_" (offset 0) pub const SM3_ANCHOR: [u8; 5] = [b'_', b'S', b'M', b'3', b'_']; /// Entry Point Structure Checksum Offset pub const ENTRY_POINT_STRUCTURE_CHECKSUM_OFFSET: usize = 0x05; /// Entry Point Length Offset pub const ENTRY_POINT_LENGTH_OFFSET: usize = 0x06; /// SMBIOS Major Version Offset pub const MAJOR_VERSION_OFFSET: usize = 0x07; /// SMBIOS Minor Version Offset pub const MINOR_VERSION_OFFSET: usize = 0x08; /// SMBIOS Docrev pub const DOCREV_OFFSET: usize = 0x09; /// Entry Point Revision Offset pub const ENTRY_POINT_REVISION_OFFSET: usize = 0x0A; /// Structure Table Maximum Size Offset pub const STRUCTURE_TABLE_MAXIMUM_SIZE_OFFSET: usize = 0x0C; /// Structure Table Address Offset pub const STRUCTURE_TABLE_ADDRESS_OFFSET: usize = 0x10; /// Entry Point Structure Checksum /// /// Checksum of the Entry Point Structure (EPS) /// /// This value, when added to all other bytes in the EPS, results in /// the value 00h (using 8-bit addition calculations). Values in the /// EPS are summed starting at offset 00h, for `entry_point_length` /// bytes. pub fn entry_point_structure_checksum(&self) -> u8 { self.raw[Self::ENTRY_POINT_STRUCTURE_CHECKSUM_OFFSET] } /// Entry Point Length /// /// Length of the Entry Point Structure, starting with the Anchor String /// field, in bytes, currently 18h pub fn entry_point_length(&self) -> u8 { self.raw[Self::ENTRY_POINT_LENGTH_OFFSET] } /// SMBIOS Major Version /// /// Major version of this specification implemented in the table /// structures (for example, the value is 0Ah (10) for revision 10.22 and /// 02h for revision 2.1) pub fn major_version(&self) -> u8 { self.raw[Self::MAJOR_VERSION_OFFSET] } /// SMBIOS Minor Version /// /// Minor version of this specification implemented in the table /// structures (for example, the value is 16h (22) for revision 10.22 and /// 01h for revision 2.1) pub fn minor_version(&self) -> u8 { self.raw[Self::MINOR_VERSION_OFFSET] } /// SMBIOS Docrev /// /// Identifies the docrev of this specification implemented in the table /// structures (for example, the value is 00h for revision 10.22.0 and /// 01h for revision 2.7.1). pub fn docrev(&self) -> u8 { self.raw[Self::DOCREV_OFFSET] } /// Entry Point Revision /// /// EPS revision implemented in this structure and identifies the /// formatting of offsets 0Bh and beyond as follows: /// - 00h Reserved for assignment by this specification /// - 01h Entry Point is based on SMBIOS 3.0 definition; /// - 02h-FFh Reserved for assignment by this specification; offsets 0Ch-17h are defined per revision 01h pub fn entry_point_revision(&self) -> u8 { self.raw[Self::ENTRY_POINT_REVISION_OFFSET] } /// Structure Table Maximum Size /// /// Maximum size of SMBIOS Structure Table, pointed to by the /// Structure Table Address, in bytes. The actual size is guaranteed /// to be less or equal to the maximum size. pub fn structure_table_maximum_size(&self) -> u32 { u32::from_le_bytes( self.raw[Self::STRUCTURE_TABLE_MAXIMUM_SIZE_OFFSET ..Self::STRUCTURE_TABLE_MAXIMUM_SIZE_OFFSET + 4] .try_into() .expect("u32 is 4 bytes"), ) } /// Structure Table Address /// /// The 64-bit physical starting address of the read-only SMBIOS /// Structure Table, which can start at any 64-bit address. This area /// contains all of the SMBIOS structures fully packed together pub fn structure_table_address(&self) -> u64 { u64::from_le_bytes( self.raw [Self::STRUCTURE_TABLE_ADDRESS_OFFSET..Self::STRUCTURE_TABLE_ADDRESS_OFFSET + 8] .try_into() .expect("u64 is 8 bytes"), ) } /// Load this structure from a file pub fn try_load_from_file(filename: &Path) -> Result { read(filename)?.try_into() } /// Load this structure by scanning a file within the given offsets, /// looking for the [SMBiosEntryPoint64::SM3_ANCHOR] string. pub fn try_scan_from_file>( file: &mut File, range: T, ) -> Result where T: RangeBounds, { let mut anchor = [0; 5]; for offset in range.step_by(0x10) { file.seek(SeekFrom::Start(offset))?; file.read_exact(&mut anchor)?; if anchor == Self::SM3_ANCHOR { let mut length = [0; 2]; file.read_exact(&mut length)?; let struct_length = length[1] as usize; let mut entry_point_buffer = Vec::with_capacity(struct_length); entry_point_buffer.resize(struct_length, 0); file.seek(SeekFrom::Start(offset))?; file.read_exact(&mut entry_point_buffer)?; let entry_point: Self = entry_point_buffer.try_into()?; return Ok(entry_point); } } Err(Error::new(ErrorKind::UnexpectedEof, "Not found")) } } impl fmt::Debug for SMBiosEntryPoint64 { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field( "entry_point_structure_checksum", &self.entry_point_structure_checksum(), ) .field("entry_point_length", &self.entry_point_length()) .field("major_version", &self.major_version()) .field("minor_version", &self.minor_version()) .field("docrev", &self.docrev()) .field( "structure_table_maximum_size", &self.structure_table_maximum_size(), ) .field("structure_table_address", &self.structure_table_address()) .finish() } } impl Serialize for SMBiosEntryPoint64 { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosEntryPoint64", 7)?; state.serialize_field( "entry_point_structure_checksum", &self.entry_point_structure_checksum(), )?; state.serialize_field("entry_point_length", &self.entry_point_length())?; state.serialize_field("major_version", &self.major_version())?; state.serialize_field("minor_version", &self.minor_version())?; state.serialize_field("docrev", &self.docrev())?; state.serialize_field( "structure_table_maximum_size", &self.structure_table_maximum_size(), )?; state.serialize_field("structure_table_address", &self.structure_table_address())?; state.end() } } impl<'a> TryFrom> for SMBiosEntryPoint64 { type Error = Error; fn try_from(raw: Vec) -> Result { if raw.len() < Self::MINIMUM_SIZE { return Err(Error::new( ErrorKind::InvalidData, "Slice is smaller than SMBiosEntryPoint64::MINIMUM_SIZE", )); } if !raw .iter() .zip(Self::SM3_ANCHOR.iter()) .all(|pair| pair.0 == pair.1) { return Err(Error::new( ErrorKind::InvalidData, "Expected _SM3_ identifier not found", )); } // Verify the checksum // The checksum is calculated for a length of `entry_point_length` let entry_point_length = raw[Self::ENTRY_POINT_LENGTH_OFFSET] as usize; match raw.get(0..entry_point_length) { Some(checked_bytes) => { if !verify_checksum(checked_bytes) { return Err(Error::new(ErrorKind::InvalidData,"Entry Point Structure checksum verification failed")); } } None => return Err(Error::new(ErrorKind::InvalidData,"The Entry Point Length field specified a value which exceeded the bounds of the Entry Point Structure")), } Ok(SMBiosEntryPoint64 { raw }) } } /// Verifies EPS and IEPS Checksums /// /// The EPS and IEPS contain a checksum value. /// /// The checksum value, when added to all other bytes in the EPS, results in /// the value 00h (using 8-bit addition [Wrapping] calculations). /// Values in the EPS are summed starting at offset 00h, for 'entry_point_length' /// bytes. fn verify_checksum(data: &[u8]) -> bool { let mut sum = Wrapping(0u8); data.iter().for_each(|b| sum += Wrapping(*b)); sum == Wrapping(0) } smbios-lib-0.9.2/src/core/header.rs000064400000000000000000000102061046102023000152100ustar 00000000000000use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::{convert::TryInto, fmt, ops::Deref, str::FromStr}; /// # Structure Handle /// /// Each SMBIOS structure has a handle or instance value associated with it. /// Some structures will reference other structures by using this value. /// /// Dereference a handle (*handle) to access its u16 value. #[derive(Serialize, PartialEq, Eq)] pub struct Handle(pub u16); impl Handle { /// Handle Size (2 bytes) pub const SIZE: usize = 2usize; } impl fmt::Debug for Handle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", &self.0) } } impl fmt::Display for Handle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", &self.0) } } impl Deref for Handle { type Target = u16; fn deref(&self) -> &Self::Target { &self.0 } } impl FromStr for Handle { type Err = std::num::ParseIntError; fn from_str(s: &str) -> Result { Ok(Handle(if s.starts_with("0x") && s.len() > 2 { u16::from_str_radix(&s[2..], 16)? } else { u16::from_str(s)? })) } } /// # SMBIOS Structure Type /// /// Each SMBIOS structure has a type number associated with it. /// /// Dereference a structure type (*struct_type) to access its u8 value. #[derive(Serialize)] pub struct SMBiosType(pub u8); impl Deref for SMBiosType { type Target = u8; fn deref(&self) -> &Self::Target { &self.0 } } impl fmt::Debug for SMBiosType { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("type", &self.0) .finish() } } /// # SMBIOS Header /// /// The header part/section of a structure pub struct Header([u8; 4]); impl fmt::Debug for Header { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::
()) .field("struct_type", &self.struct_type()) .field("length", &self.length()) .field("handle", &self.handle()) .finish() } } impl Serialize for Header { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("Header", 3)?; state.serialize_field("struct_type", &self.struct_type())?; state.serialize_field("length", &self.length())?; state.serialize_field("handle", &self.handle())?; state.end() } } impl Header { /// Total size of a Header (4) /// /// A header has a byte for the _struct_type_ at offset 0, /// a byte for the _length_ at offset 1, /// and a word for the _handle_ at offset 2 for a total of /// 4 bytes. pub const SIZE: usize = 4; /// StructType offset (offset 0 and 1 bytes) pub const STRUCT_TYPE_OFFSET: usize = 0; /// Length offset (offset 1 and 1 bytes) pub const LENGTH_OFFSET: usize = 1; /// Handle offset (offset 2 and 2 bytes) pub const HANDLE_OFFSET: usize = 2; /// Creates a new [Header] struct pub fn new(data: [u8; 4]) -> Self { Header(data) } /// The type of SMBIOS structure pub fn struct_type(&self) -> u8 { self.0[Self::STRUCT_TYPE_OFFSET] // struct_type is 1 byte at offset 0 } /// The length of the structure not including the strings part/section pub fn length(&self) -> u8 { self.0[Self::LENGTH_OFFSET] // length is 1 byte at offset 1 } /// The handle of this structure instance pub fn handle(&self) -> Handle { // handle is 2 bytes at offset 2 Handle(u16::from_le_bytes( self.0[Self::HANDLE_OFFSET..Self::HANDLE_OFFSET + 2] .try_into() .expect("u16 is 2 bytes"), )) } /// Byte iterator of the header pub fn iter(&self) -> std::slice::Iter<'_, u8> { self.0.iter() } } impl From<[u8; 4]> for Header { fn from(data: [u8; 4]) -> Self { Header(data) } } impl Deref for Header { type Target = [u8; 4]; fn deref(&self) -> &Self::Target { &self.0 } } smbios-lib-0.9.2/src/core/mod.rs000064400000000000000000000003431046102023000145400ustar 00000000000000mod entry_point; mod header; mod smbios_data; /// SMBIOS String module pub mod strings; mod undefined_struct; pub use entry_point::*; pub use header::*; pub use smbios_data::*; pub use strings::*; pub use undefined_struct::*; smbios-lib-0.9.2/src/core/smbios_data.rs000064400000000000000000000153521046102023000162540ustar 00000000000000use super::header::Handle; use super::undefined_struct::{UndefinedStruct, UndefinedStructTable}; use crate::structs::{DefinedStructTable, SMBiosStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::io::Error; use std::{cmp::Ordering, slice::Iter}; use std::{fmt, fs::read}; /// # SMBIOS Data /// /// Contains an optional SMBIOS version and a collection of SMBIOS structures. pub struct SMBiosData { table: UndefinedStructTable, /// Version of the contained SMBIOS structures. pub version: Option, } impl<'a> SMBiosData { /// Creates an SMBIOS table parser which can be iterated /// /// `table` is iterable table data. /// `version` is optional and represents the DMTF SMBIOS Standard version of the bytes in `data`. pub fn new(table: UndefinedStructTable, version: Option) -> Self { Self { table, version } } /// Creates an SMBIOS table parser which can be iterated /// /// `data` is a block of bytes representing the raw table data. /// `version` is optional and represents the DMTF SMBIOS Standard version of the bytes in `data`. pub fn from_vec_and_version(data: Vec, version: Option) -> Self { Self { table: UndefinedStructTable::from(data), version, } } /// Loads raw SMBios table data from a file pub fn try_load_from_file( filename: &str, version: Option, ) -> Result { let data = read(filename)?; let result = Self { table: UndefinedStructTable::from(data), version, }; Ok(result) } /// Iterator of the contained [UndefinedStruct] items pub fn iter(&self) -> Iter<'_, UndefinedStruct> { self.table.iter() } /// An iterator over the defined type instances within the table. pub fn defined_struct_iter(&'a self) -> impl Iterator + 'a where T: SMBiosStruct<'a>, { self.table.defined_struct_iter() } /// Tests if every element of the defined struct iterator matches a predicate. pub fn all(&'a self, f: F) -> bool where T: SMBiosStruct<'a>, F: FnMut(T) -> bool, { self.table.all(f) } /// Tests if any element of the defined struct iterator matches a predicate. pub fn any(&'a self, f: F) -> bool where T: SMBiosStruct<'a>, F: FnMut(T) -> bool, { self.table.any(f) } /// Finds the first occurance of the structure pub fn first(&'a self) -> Option where T: SMBiosStruct<'a>, { self.table.first() } /// Finds the first occurance of the structure that satisfies a predicate. pub fn find(&'a self, predicate: P) -> Option where T: SMBiosStruct<'a>, P: FnMut(&T) -> bool, { self.table.find(predicate) } /// Applies function to the defined struct elements and returns the first non-none result. pub fn find_map(&'a self, f: F) -> Option where A: SMBiosStruct<'a>, F: FnMut(A) -> Option, { self.table.find_map(f) } /// Creates an iterator of the defined structure which uses a closure to determine if an element should be yielded. pub fn filter(&'a self, predicate: P) -> impl Iterator + 'a where T: SMBiosStruct<'a>, P: FnMut(&T) -> bool, { self.table.filter(predicate) } /// Takes a closure and creates an iterator which calls that closure on each defined struct. pub fn map(&'a self, f: F) -> impl Iterator + 'a where A: SMBiosStruct<'a>, F: FnMut(A) -> B, { self.table.map(f) } /// Creates an iterator that both filters and maps from the defined struct iterator. pub fn filter_map(&'a self, f: F) -> impl Iterator + 'a where A: SMBiosStruct<'a>, F: FnMut(A) -> Option, { self.table.filter_map(f) } /// Finds the structure matching the given handle pub fn find_by_handle(&'a self, handle: &Handle) -> Option<&UndefinedStruct> { self.table.find_by_handle(handle) } /// Finds all occurances of the structure pub fn collect(&'a self) -> Vec where T: SMBiosStruct<'a>, { self.table.collect() } } impl IntoIterator for SMBiosData { type Item = UndefinedStruct; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.table.into_iter() } } impl fmt::Debug for SMBiosData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { // Convert to defined structures to see the structure fields let defined_table: DefinedStructTable<'_> = self.table.iter().collect(); fmt.debug_struct(std::any::type_name::()) .field("version", &self.version) .field("table", &defined_table) .finish() } } impl Serialize for SMBiosData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { // Convert to defined structures to see the structure fields let defined_table: DefinedStructTable<'_> = self.table.iter().collect(); let mut state = serializer.serialize_struct("SMBiosData", 2)?; state.serialize_field("version", &self.version)?; state.serialize_field("table", &defined_table)?; state.end() } } /// # Version of SMBIOS Structure #[derive(Debug, Eq, PartialEq, Serialize, Clone, Copy)] pub struct SMBiosVersion { /// SMBIOS major version pub major: u8, /// SMBIOS minor version pub minor: u8, /// SMBIOS version revision pub revision: u8, } impl SMBiosVersion { /// Creates a new [SMBiosVersion] struct pub fn new(major: u8, minor: u8, revision: u8) -> SMBiosVersion { SMBiosVersion { major, minor, revision, } } } impl Ord for SMBiosVersion { fn cmp(&self, other: &Self) -> Ordering { if self.major < other.major { Ordering::Less } else if self.major > other.major { Ordering::Greater } else if self.minor < other.minor { Ordering::Less } else if self.minor > other.minor { Ordering::Greater } else if self.revision < other.revision { Ordering::Less } else if self.revision > other.revision { Ordering::Greater } else { Ordering::Equal } } } impl PartialOrd for SMBiosVersion { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } smbios-lib-0.9.2/src/core/strings.rs000064400000000000000000000256301046102023000154600ustar 00000000000000use serde::{ser::SerializeSeq, Serialize, Serializer}; use std::error; use std::{fmt, string::FromUtf8Error}; /// # SMBIOS String-Set /// /// The string-set part/section of an SMBIOS structure pub struct SMBiosStringSet { strings: Vec>, current_string_index: usize, } impl SMBiosStringSet { /// Creates a new string-set section of a structure pub fn new(string_area: Vec) -> SMBiosStringSet { SMBiosStringSet { strings: { if string_area == &[] { vec![] } else { string_area .split(|num| *num == 0) .into_iter() .map(|string_slice| string_slice.to_vec()) .collect() } }, current_string_index: 0, } } fn reset(&mut self) { self.current_string_index = 0; } /// Returns a UTF-8 [String] at the given 1 based `index` /// /// If the index is 0 an empty string "" is returned. /// If SMBiosStringError::InvalidStringNumber is returned, either the field value is corrupt or the string-set is corrupt. /// If SMBiosStringError::Utf8 is returned, the string is corrupt. pub fn get_string(&self, index: u8) -> SMBiosString { let index_usize = index as usize; // As of 3.5.0 DMTF has decided to make UTF-8 the standard for how to interpret strings. // // section 6.1.3: // "Strings must be encoded as UTF-8 with no byte order mark (BOM). For compatibility // with older SMBIOS parsers, US-ASCII characters should be used. // // When the formatted portion of an SMBIOS structure references a string, it does so by specifying // a non-zero string number within the structure's string-set. // // If a string field references no string, a null (0) is placed in that string field." // Referential transparency: // In rust we can return the empty string ("") when index is 0. This is idempotent because // the structure's string-set, by design, is incapable of producing an empty string. SMBiosString { value: match index_usize == 0 { true => Ok(String::new()), false => match index_usize <= self.strings.len() { true => String::from_utf8(self.strings[index_usize - 1].clone()) .map_err(|err| err.into()), false => Err(SMBiosStringError::InvalidStringNumber(index)), }, }, } } /// Iterates the raw bytes of the strings. The terminating 0 is not included in each string. pub fn iter(&self) -> std::slice::Iter<'_, Vec> { self.strings.iter() } } impl Iterator for SMBiosStringSet { type Item = SMBiosString; fn next(&mut self) -> Option { if self.current_string_index == self.strings.len() { self.reset(); return None; } let result = String::from_utf8(self.strings[self.current_string_index].clone()) .map_err(|err| err.into()); self.current_string_index = self.current_string_index + 1; Some(SMBiosString::from(result)) } } impl IntoIterator for &SMBiosStringSet { type Item = SMBiosString; type IntoIter = SMBiosStringSet; fn into_iter(self) -> Self::IntoIter { SMBiosStringSet { strings: self.strings.clone(), current_string_index: 0, } } } impl fmt::Debug for SMBiosStringSet { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().entries(self.into_iter()).finish() } } impl Serialize for SMBiosStringSet { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let strings: Vec = self.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(strings.len()))?; for e in strings { match e.value { Ok(val) => seq.serialize_element(&val)?, Err(err) => seq.serialize_element(format!("{}", err).as_str())?, } } seq.end() } } /// # SMBiosStringError /// /// An SMBIOS String retrival error #[derive(Serialize, Debug)] pub enum SMBiosStringError { /// The structure's field is out of bounds of the formatted portion of the SMBIOS structure FieldOutOfBounds, /// The given string number was outside the range of the SMBIOS structure's string-set InvalidStringNumber(u8), /// UTF8 parsing error #[serde(serialize_with = "ser_from_utf8_error")] Utf8(FromUtf8Error), } fn ser_from_utf8_error(data: &FromUtf8Error, serializer: S) -> Result where S: Serializer, { serializer.serialize_str(format!("{}", data).as_str()) } impl fmt::Display for SMBiosStringError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { SMBiosStringError::FieldOutOfBounds => { write!( f, "The structure's field is out of bounds of the formatted portion of the SMBIOS structure" ) } SMBiosStringError::InvalidStringNumber(_) => { write!( f, "The given string number was outside the range of the SMBIOS structure's string-set" ) } // The wrapped error contains additional information and is available // via the source() method. SMBiosStringError::Utf8(..) => { write!(f, "UTF8 parsing error") } } } } impl error::Error for SMBiosStringError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match *self { // The cause is the underlying implementation error type. Is implicitly // cast to the trait object `&error::Error`. This works because the // underlying type already implements the `Error` trait. SMBiosStringError::Utf8(ref e) => Some(e), _ => None, } } } // Implement the conversion from `FromUtf8Error` to `SMBiosStringError`. // This will be automatically called by `?` if a `FromUtf8Error` // needs to be converted into a `SMBiosStringError`. impl From for SMBiosStringError { fn from(err: FromUtf8Error) -> SMBiosStringError { SMBiosStringError::Utf8(err) } } impl From> for SMBiosString { fn from(data: Result) -> Self { SMBiosString { value: data } } } /// # SMBiosString /// /// Contains the retrival result for an SMBIOS string field. pub struct SMBiosString { value: Result, } impl SMBiosString { /// Produces a UTF-8 which includes invalid UTF-8 characters; otherwise, returns /// Option::None for all other conditions. pub fn to_utf8_lossy(&self) -> Option { match &self.value { Ok(val) => Some(val.to_string()), Err(err) => match err { SMBiosStringError::Utf8(utf8) => { Some(String::from_utf8_lossy(utf8.as_bytes()).to_string()) } _ => None, }, } } /// Returns `true` if the result is [Ok]. pub const fn is_ok(&self) -> bool { self.value.is_ok() } /// Returns `true` if the result is [Err]. pub const fn is_err(&self) -> bool { self.value.is_err() } /// Converts to `Option` consuming self, and discarding the error, if any. pub fn ok(self) -> Option { self.value.ok() } /// Converts to `Option` consuming self, and discarding the success value, if any. pub fn err(self) -> Option { self.value.err() } /// Produces a new `Result`, containing a reference into the original, leaving the original in place. pub const fn as_ref(&self) -> Result<&String, &SMBiosStringError> { self.value.as_ref() } /// Converts to Result<&mut String, &mut SMBiosStringError>. pub fn as_mut(&mut self) -> Result<&mut String, &mut SMBiosStringError> { self.value.as_mut() } } impl fmt::Display for SMBiosString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { Ok(val) => write!(f, "{}", val), Err(err) => write!(f, "{}", err), } } } impl fmt::Debug for SMBiosString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { Ok(val) => write!(f, "{}", val), Err(err) => write!(f, "{}", err), } } } impl Serialize for SMBiosString { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_str(format!("{}", &self).as_str()) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_string_parsing() { let string_set_bytes = vec![ // "en|US|iso8859-1" 0x65, 0x6E, 0x7C, 0x55, 0x53, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31, 0x00, // "Heart=💖" b'H', b'e', b'a', b'r', b't', b'=', 240, 159, 146, 150, 0x00, // "Error=" b'E', b'r', b'r', b'o', b'r', b'=', 1, 159, 146, 150, 0x00, // "ja|JP|unicode" 0x6A, 0x61, 0x7C, 0x4A, 0x50, 0x7C, 0x75, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, ]; let string_set = SMBiosStringSet::new(string_set_bytes); let mut string_iterator = string_set.into_iter(); let first_string = string_iterator.next().unwrap().value.unwrap(); assert_eq!(first_string, "en|US|iso8859-1".to_string()); let second_string = string_iterator.next().unwrap().value.unwrap(); assert_eq!(second_string, "Heart=💖".to_string()); // Err(FromUtf8Error { bytes: [69, 114, 114, 111, 114, 61, 1, 159, 146, 150], error: Utf8Error { valid_up_to: 7, error_len: Some(1) } }) match string_iterator.next().unwrap().value { Ok(_) => panic!("This should have been a UTF8 error"), Err(err) => match err { SMBiosStringError::FieldOutOfBounds => panic!("This should have been inbounds"), SMBiosStringError::InvalidStringNumber(_) => { panic!("This should have been a valid string number") } SMBiosStringError::Utf8(utf8) => { assert_eq!(7, utf8.utf8_error().valid_up_to()); assert_eq!( "Error=\u{1}���", String::from_utf8_lossy(utf8.as_bytes()).to_string() ); } }, } let fourth_string = string_iterator.next().unwrap().value.unwrap(); assert_eq!(fourth_string, "ja|JP|unicode".to_string()); } } smbios-lib-0.9.2/src/core/undefined_struct.rs000064400000000000000000000341111046102023000173260ustar 00000000000000use super::header::{Handle, Header}; use super::strings::*; use crate::structs::{DefinedStruct, SMBiosEndOfTable, SMBiosStruct}; use serde::{Serialize, Serializer}; use std::fmt; use std::{ convert::TryInto, fs::File, io::{prelude::*, Error, ErrorKind, SeekFrom}, slice::Iter, }; /// # Embodies the three basic parts of an SMBIOS structure /// /// Every SMBIOS structure contains three distinct sections: /// - A header /// - A formatted structure of fields (offsets and widths) /// - String data /// /// A consumer of BIOS data ultimately wants to work with a [DefinedStruct]. /// [UndefinedStruct] provides a set of fields and functions that enables /// downcasting to a [DefinedStruct]. Further, the OEM is allowed to define /// their own structures and in such cases working with UndefinedStruct is /// necessary. Therefore, [UndefinedStruct] is public for the case of OEM, /// as well as when working with structures that are defined in an SMBIOS /// standard newer than the one this library currently supports. #[derive(Serialize)] pub struct UndefinedStruct { /// The [Header] of the structure pub header: Header, /// The raw data for the header and fields /// /// `fields` is used by the `get_field_*()` functions. `fields` does not /// include _strings_; therefore, preventing accidentally retrieving /// data from the _strings_ area. This avoids a need to check /// `header.length()` during field retrieval. /// /// Note: A better design is for this to only hold the fields, however, /// that will shift field offsets given in code by 4 (the header size). /// The SMBIOS specification gives offsets relative to the start of the /// header, and therefore maintaining this library code is easier to /// keep the header. /// /// An alternative would be to make the `get_field_*()` functions adjust /// for the header offset though this adds a small cost to every field /// retrieval in comparison to just keeping an extra 4 bytes for every /// structure. pub fields: Vec, /// The strings of the structure #[serde(serialize_with = "ser_strings")] pub strings: SMBiosStringSet, } fn ser_strings(data: &SMBiosStringSet, serializer: S) -> Result where S: Serializer, { serializer.serialize_str(format!("{:?}", data).as_str()) } impl<'a> UndefinedStruct { /// Creates a structure instance of the given byte array slice pub fn new(raw: &Vec) -> Self { match raw.get(Header::LENGTH_OFFSET) { Some(&header_length) => UndefinedStruct { header: Header::new(raw[..Header::SIZE].try_into().expect("4 bytes")), fields: raw.get(..(header_length as usize)).unwrap_or(&[]).to_vec(), strings: { SMBiosStringSet::new( raw.get((header_length as usize)..raw.len() - 2) .unwrap_or(&[]) .to_vec(), ) }, }, None => UndefinedStruct { ..Default::default() }, } } /// Retrieve a byte at the given offset from the structure's data section pub fn get_field_byte(&self, offset: usize) -> Option { match self.fields.get(offset..offset + 1) { Some(val) => Some(val[0]), None => None, } } /// Retrieve a WORD at the given offset from the structure's data section pub fn get_field_word(&self, offset: usize) -> Option { match self.fields.get(offset..offset + 2) { Some(val) => Some(u16::from_le_bytes(val.try_into().expect("u16 is 2 bytes"))), None => None, } } /// Retrieve a [Handle] at the given offset from the structure's data section pub fn get_field_handle(&self, offset: usize) -> Option { match self.fields.get(offset..offset + Handle::SIZE) { Some(val) => Some(Handle(u16::from_le_bytes( val.try_into().expect("u16 is 2 bytes"), ))), None => None, } } /// Retrieve a DWORD at the given offset from the structure's data section pub fn get_field_dword(&self, offset: usize) -> Option { match self.fields.get(offset..offset + 4) { Some(val) => Some(u32::from_le_bytes(val.try_into().expect("u32 is 4 bytes"))), None => None, } } /// Retrieve a QWORD at the given offset from the structure's data section pub fn get_field_qword(&self, offset: usize) -> Option { match self.fields.get(offset..offset + 8) { Some(val) => Some(u64::from_le_bytes(val.try_into().expect("u64 is 8 bytes"))), None => None, } } /// Retrieve a String of the given offset /// /// Retrieval of strings is a two part operation. The given offset /// contains a byte whose value is a 1 based index into the strings section. /// The string is thus retrieved from the strings section based on the /// byte value at the given offset. pub fn get_field_string(&self, offset: usize) -> SMBiosString { match self.get_field_byte(offset) { Some(val) => self.strings.get_string(val), None => Err(SMBiosStringError::FieldOutOfBounds).into(), } } // todo: learn how to pass an index range (SliceIndex?) rather than start/end indices. // This would better conform to the Rust design look and feel. /// Retrieve a block of bytes from the structure's data section pub fn get_field_data(&self, start_index: usize, end_index: usize) -> Option<&[u8]> { return self.fields.get(start_index..end_index); } /// Cast to a given structure /// /// When this library does not contain a [DefinedStruct] variant /// matching the SMBiosStruct::STRUCT_TYPE, this function affords a cast to the /// given type. Such would be the case with OEM structure type T /// (which implements the [SMBiosStruct] trait). /// /// TODO: This should panic (not be Option) when the STRUCT_TYPE does not match because /// this would be a logic error in code, not a runtime error. /// /// Make this a "try_into" pub fn as_type>(&'a self) -> Option { if T::STRUCT_TYPE == self.header.struct_type() { Some(T::new(self)) } else { None } } /// Down casts the current structure to its specific defined BIOS structure type pub fn defined_struct(&self) -> DefinedStruct<'_> { self.into() } } impl fmt::Debug for UndefinedStruct { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let fields = &self.fields[Header::SIZE..]; fmt.debug_struct(std::any::type_name::()) .field("header", &self.header) .field("fields", &fields) .field("strings", &self.strings) .finish() } } impl Default for UndefinedStruct { fn default() -> Self { let v: [u8; 4] = [0; 4]; UndefinedStruct { header: Header::new(v), fields: (&[]).to_vec(), strings: { SMBiosStringSet::new((&[]).to_vec()) }, } } } /// # Undefined Struct Table /// /// A collection of [UndefinedStruct] items. #[derive(Debug, Serialize)] pub struct UndefinedStructTable(Vec); impl<'a> UndefinedStructTable { fn new() -> UndefinedStructTable { UndefinedStructTable(Vec::new()) } fn add(&mut self, elem: UndefinedStruct) { self.0.push(elem); } /// Iterator of the contained [UndefinedStruct] items. pub fn iter(&self) -> Iter<'_, UndefinedStruct> { self.0.iter() } /// An iterator over the defined type instances within the table. pub fn defined_struct_iter(&'a self) -> impl Iterator + 'a where T: SMBiosStruct<'a>, { self.iter() .take_while(|undefined_struct| { undefined_struct.header.struct_type() != SMBiosEndOfTable::STRUCT_TYPE }) .filter_map(|undefined_struct| { if undefined_struct.header.struct_type() == T::STRUCT_TYPE { Some(T::new(undefined_struct)) } else { None } }) } /// Tests if every element of the defined struct iterator matches a predicate. pub fn all(&'a self, f: F) -> bool where T: SMBiosStruct<'a>, F: FnMut(T) -> bool, { self.defined_struct_iter().all(f) } /// Tests if any element of the defined struct iterator matches a predicate. pub fn any(&'a self, f: F) -> bool where T: SMBiosStruct<'a>, F: FnMut(T) -> bool, { self.defined_struct_iter().any(f) } /// Finds the first occurance of the structure pub fn first(&'a self) -> Option where T: SMBiosStruct<'a>, { self.defined_struct_iter().next() } /// Finds the first occurance of the structure that satisfies a predicate. pub fn find(&'a self, predicate: P) -> Option where T: SMBiosStruct<'a>, P: FnMut(&T) -> bool, { self.defined_struct_iter().find(predicate) } /// Applies function to the defined struct elements and returns the first non-none result. pub fn find_map(&'a self, f: F) -> Option where A: SMBiosStruct<'a>, F: FnMut(A) -> Option, { self.defined_struct_iter().find_map(f) } /// Creates an iterator of the defined structure which uses a closure to determine if an element should be yielded. pub fn filter(&'a self, predicate: P) -> impl Iterator + 'a where T: SMBiosStruct<'a>, P: FnMut(&T) -> bool, { self.defined_struct_iter().filter(predicate) } /// Maps the defined struct to another type given by the closure. pub fn map(&'a self, f: F) -> impl Iterator + 'a where A: SMBiosStruct<'a>, F: FnMut(A) -> B, { self.defined_struct_iter().map(f) } /// Creates an iterator that both filters and maps from the defined struct iterator. pub fn filter_map(&'a self, f: F) -> impl Iterator + 'a where A: SMBiosStruct<'a>, F: FnMut(A) -> Option, { self.defined_struct_iter().filter_map(f) } /// Finds the structure matching the given handle /// /// To downcast to the defined struct, call .defined_struct() on the result. pub fn find_by_handle(&'a self, handle: &Handle) -> Option<&'a UndefinedStruct> { self.iter() .find(|smbios_struct| smbios_struct.header.handle() == *handle) .and_then(|undefined_struct| Some(undefined_struct)) } /// Returns all occurances of the structure pub fn collect(&'a self) -> Vec where T: SMBiosStruct<'a>, { self.defined_struct_iter().collect() } /// Load an [UndefinedStructTable] by seeking and reading the file offsets. pub fn try_load_from_file_offset( file: &mut File, table_offset: u64, table_len: usize, ) -> Result { if table_len < Header::SIZE + 2 { return Err(Error::new( ErrorKind::InvalidData, format!("The table has an invalid size: {}", table_len), )); } file.seek(SeekFrom::Start(table_offset))?; let mut table = Vec::with_capacity(table_len); table.resize(table_len, 0); file.read_exact(&mut table)?; Ok(table.into()) } } impl From> for UndefinedStructTable { fn from(data: Vec) -> Self { const DOUBLE_ZERO_SIZE: usize = 2usize; const MIN_STRUCT_SIZE: usize = Header::SIZE + DOUBLE_ZERO_SIZE; let mut result = Self::new(); let mut current_index = 0usize; loop { // Is the next structure long enough? match data.get(current_index..current_index + MIN_STRUCT_SIZE) { Some(min_struct) => { // Read the structure's self-reported length in its header let struct_len = min_struct[Header::LENGTH_OFFSET] as usize; // Bad reported length if struct_len < Header::SIZE { break; } // Beyond the structure length are the structure's strings // Find the /0/0 which marks the end of this structure and the // beginning of the next. match data.get(current_index + struct_len..) { Some(strings_etc) => { match strings_etc .windows(DOUBLE_ZERO_SIZE) .position(|x| x[0] == x[1] && x[1] == 0) { Some(double_zero_position) => { // The next structure will start at this index let next_index = current_index + struct_len + double_zero_position + DOUBLE_ZERO_SIZE; // Copy the current structure to the collection result.add(UndefinedStruct::new( &data[current_index..next_index].to_vec(), )); current_index = next_index; } None => break, } } None => break, }; } None => break, } } result } } impl IntoIterator for UndefinedStructTable { type Item = UndefinedStruct; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } smbios-lib-0.9.2/src/file_io.rs000064400000000000000000000045561046102023000144510ustar 00000000000000//! Loads files containing raw bios binary data. //! //! When testing this library it is useful to read stored //! raw data and then load it into the structures. use crate::core::SMBiosData; use crate::windows::WinSMBiosData; use std::io::{BufWriter, Error, Write}; use std::{ fs::{read, read_dir, File}, path::Path, }; /// Loads raw smbios data from a file and returns [SMBiosData] or [std::io::Error] on error. /// /// Currently supports reading raw files containing only SMBIOS table data or /// Windows raw files containing the windows header and SMBIOS table data. pub fn load_smbios_data_from_file(file_path: &Path) -> Result { let data = read(file_path)?; if WinSMBiosData::is_valid_win_smbios_data(&data) { let win_smbios = WinSMBiosData::new(data) .expect("Structure shouldn't be invalid it was already checked."); Ok(win_smbios.smbios_data) } else { Ok(SMBiosData::from_vec_and_version(data, None)) } } /// Loads raw smbios data files from a given _folder_ and returns [Vec] pub fn load_raw_files(folder: &Path) -> Vec { assert!(folder.is_dir()); let mut result = Vec::new(); let entries = read_dir(folder) .expect("valid files") .map(|res| res.map(|e| e.path())) .collect::, Error>>() .expect("msg"); for elem in entries { let smbios_table_data = load_smbios_data_from_file(&elem); match smbios_table_data { Ok(data) => result.push(data), Err(_) => {} } } result } /// dumps raw data into a file pub fn dump_raw(data: Vec, out_path: &Path) -> Result<(), Error> { let f = File::create(&out_path)?; let mut f = BufWriter::new(f); f.write_all(&data)?; Ok(()) } #[cfg(test)] mod tests { use super::*; use std::path::PathBuf; #[test] fn test_load_smbios_table_data() { let mut path = PathBuf::new(); path.push("."); path.push("tests"); path.push("jeffgerlap_3_2_0"); path.set_extension("dat"); match load_smbios_data_from_file(&path.as_path()) { Ok(table_data) => { for parts in table_data.into_iter() { println!("{:?}", parts.defined_struct()); } } _ => panic!("Expected data!"), } } } smbios-lib-0.9.2/src/lib.rs000064400000000000000000000014451046102023000136030ustar 00000000000000//! SMBIOS Library //! //! Implements the DMTF [System Management BIOS (SMBIOS) Reference Specification 3.5.0](https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.5.0.pdf). //! //! This library focuses on the tasks involved with reading and interpreting //! BIOS data. #![warn(missing_docs)] #![deny(rust_2018_idioms)] mod core; mod file_io; mod macos; mod structs; mod unix; mod windows; pub use structs::*; pub use crate::core::*; pub use file_io::*; #[cfg(target_family = "windows")] pub use windows::{load_windows_smbios_data, raw_smbios_from_device, table_load_from_device}; pub use windows::WinSMBiosData; #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] pub use unix::*; #[cfg(any(target_os = "macos", target_os = "ios"))] pub use macos::*; smbios-lib-0.9.2/src/macos/mod.rs000064400000000000000000000003101046102023000147040ustar 00000000000000#[cfg(any(target_os = "macos", target_os = "ios"))] mod platform; #[cfg(any(target_os = "macos", target_os = "ios"))] pub use platform::*; pub use std::convert::TryInto; pub use std::{fmt, fs, io}; smbios-lib-0.9.2/src/macos/platform.rs000064400000000000000000000074211046102023000157630ustar 00000000000000use crate::*; use core_foundation::{ base::{kCFAllocatorDefault, mach_port_t, CFRelease, TCFTypeRef}, data::{CFDataGetBytePtr, CFDataGetLength, CFDataRef}, }; use io_kit_sys::{ types::{io_service_t, IOOptionBits}, IOMasterPort, IOObjectRelease, IORegistryEntryCreateCFProperty, IOServiceGetMatchingService, IOServiceMatching, CFSTR, }; use mach2::*; use std::{convert::TryFrom, ffi::CString, io::Error, io::ErrorKind}; struct AppleSMBiosService { pub service_handle: io_service_t, } impl AppleSMBiosService { fn try_init() -> Result { unsafe { let service_name = CString::new("AppleSMBIOS").expect("CString::new failed"); let mut master_port: mach_port_t = port::MACH_PORT_NULL; IOMasterPort(port::MACH_PORT_NULL, &mut master_port); let service: io_service_t = IOServiceGetMatchingService(master_port, IOServiceMatching(service_name.as_ptr())); if service == port::MACH_PORT_NULL { return Err(Error::new( ErrorKind::NotFound, "AppleSMBIOS service is unreachable", )); } Ok(AppleSMBiosService { service_handle: service, }) } } } impl Drop for AppleSMBiosService { fn drop(&mut self) { unsafe { IOObjectRelease(self.service_handle); } } } fn try_load_macos_entry_point() -> Result { let service = AppleSMBiosService::try_init()?; unsafe { let smbios_entry_point_name = CString::new("SMBIOS-EPS").expect("CString::new failed"); let option_bits: IOOptionBits = 0; let data_ref = IORegistryEntryCreateCFProperty( service.service_handle, CFSTR(smbios_entry_point_name.as_ptr()), kCFAllocatorDefault, option_bits, ) as CFDataRef; if data_ref.is_null() { return Err(Error::new( ErrorKind::NotFound, "SMBIOS-EPS entry point is unreachable", )); } let data_ptr = CFDataGetBytePtr(data_ref); let data_length = CFDataGetLength(data_ref); let entry_point = std::slice::from_raw_parts(data_ptr, data_length as usize).to_vec(); CFRelease(data_ref.as_void_ptr()); SMBiosEntryPoint32::try_from(entry_point) } } fn try_load_macos_table() -> Result, Error> { let service = AppleSMBiosService::try_init()?; unsafe { let smbios_table_name = CString::new("SMBIOS").expect("CString::new failed"); let option_bits: IOOptionBits = 0; let data_ref = IORegistryEntryCreateCFProperty( service.service_handle, CFSTR(smbios_table_name.as_ptr()), kCFAllocatorDefault, option_bits, ) as CFDataRef; if data_ref.is_null() { return Err(Error::new(ErrorKind::NotFound, "SMBIOS is unreachable")); } let data_ptr = CFDataGetBytePtr(data_ref); let data_length = CFDataGetLength(data_ref); let table = std::slice::from_raw_parts(data_ptr, data_length as usize).to_vec(); CFRelease(data_ref.as_void_ptr()); Ok(table) } } /// Loads SMBIOS table data ([SMBiosData]) from the device pub fn table_load_from_device() -> Result { let entry_point = try_load_macos_entry_point()?; let version = SMBiosVersion { major: entry_point.major_version(), minor: entry_point.minor_version(), revision: 0, }; let table = try_load_macos_table()?; Ok(SMBiosData::from_vec_and_version(table, Some(version))) } /// Returns smbios raw data pub fn raw_smbios_from_device() -> Result, Error> { Ok(try_load_macos_table()?) } smbios-lib-0.9.2/src/main.rs000064400000000000000000000247041046102023000137640ustar 00000000000000use std::{error::Error, fmt::Display, path::Path}; use smbioslib::*; #[derive(Debug)] enum BiosParseError { BiosVendorNotFound, BiosVersionNotFound, BiosReleaseDateNotFound, BiosRevisionNotFound, FirmewareRevisionNotFound, SystemManufacturerNotFound, SystemProductNameNotFound, SystemVersionNotFound, SystemSerialNumberNotFound, SystemUuidNotFound, SystemSkuNumberNotFound, SystemFamilyNotFound, BaseboardManufacturerNotFound, BaseboardProductNameNotFound, BaseboardVersionNotFound, BaseboardSerialNumberNotFound, BaseboardAssetTagNotFound, ChassisManufacturerNotFound, ChassisTypeNotFound, ChassisVersionNotFound, ChassisSerialNumberNotFound, ChassisAssetTagNotFound, ProcessorFamilyNotFound, ProcessorManufacturerNotFound, ProcessorVersionNotFound, ProcessorFrequencyNotFound, InvalidKeywordOnCommandLine, } impl Error for BiosParseError { fn source(&self) -> Option<&(dyn Error + 'static)> { None } } impl Display for BiosParseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Here we can match and turn each arm into a human readable statement. // We have other variants to add so we will wait before doing so. write!(f, "{:?}", &self) } } fn string_keyword(keyword: String, data: &SMBiosData) -> Result { match keyword.to_lowercase().as_str() { "bios-vendor" => data .find_map(|bios_info: SMBiosInformation| bios_info.vendor().to_utf8_lossy()) .ok_or(BiosParseError::BiosVendorNotFound), "bios-version" => data .find_map(|bios_info: SMBiosInformation| bios_info.version().to_utf8_lossy()) .ok_or(BiosParseError::BiosVersionNotFound), "bios-release-date" => data .find_map(|bios_info: SMBiosInformation| bios_info.release_date().to_utf8_lossy()) .ok_or(BiosParseError::BiosReleaseDateNotFound), "bios-revision" => data .find_map(|bios_info: SMBiosInformation| { match ( bios_info.system_bios_major_release(), bios_info.system_bios_minor_release(), ) { (Some(major), Some(minor)) => Some(format!("{}.{}", major, minor)), _ => None, } }) .ok_or(BiosParseError::BiosRevisionNotFound), "firmware-revision" => data .find_map(|bios_info: SMBiosInformation| { match ( bios_info.e_c_firmware_major_release(), bios_info.e_c_firmware_minor_release(), ) { (Some(major), Some(minor)) => Some(format!("{}.{}", major, minor)), _ => None, } }) .ok_or(BiosParseError::FirmewareRevisionNotFound), "system-manufacturer" => data .find_map(|system_info: SMBiosSystemInformation| { system_info.manufacturer().to_utf8_lossy() }) .ok_or(BiosParseError::SystemManufacturerNotFound), "system-product-name" => data .find_map(|system_info: SMBiosSystemInformation| { system_info.product_name().to_utf8_lossy() }) .ok_or(BiosParseError::SystemProductNameNotFound), "system-version" => data .find_map(|system_info: SMBiosSystemInformation| system_info.version().to_utf8_lossy()) .ok_or(BiosParseError::SystemVersionNotFound), "system-serial-number" => data .find_map(|system_info: SMBiosSystemInformation| { system_info.serial_number().to_utf8_lossy() }) .ok_or(BiosParseError::SystemSerialNumberNotFound), "system-uuid" => { match data.find_map(|system_info: SMBiosSystemInformation| system_info.uuid()) { // SystemUuidData is an enum that can be broken down further if desired Some(uuid) => Ok(format!("{}", uuid)), None => Err(BiosParseError::SystemUuidNotFound), } } "system-sku-number" => data .find_map(|system_info: SMBiosSystemInformation| { system_info.sku_number().to_utf8_lossy() }) .ok_or(BiosParseError::SystemSkuNumberNotFound), "system-family" => data .find_map(|system_info: SMBiosSystemInformation| system_info.family().to_utf8_lossy()) .ok_or(BiosParseError::SystemFamilyNotFound), "baseboard-manufacturer" => data .find_map(|baseboard_info: SMBiosBaseboardInformation| { baseboard_info.manufacturer().to_utf8_lossy() }) .ok_or(BiosParseError::BaseboardManufacturerNotFound), "baseboard-product-name" => data .find_map(|baseboard_info: SMBiosBaseboardInformation| { baseboard_info.product().to_utf8_lossy() }) .ok_or(BiosParseError::BaseboardProductNameNotFound), "baseboard-version" => data .find_map(|baseboard_info: SMBiosBaseboardInformation| { baseboard_info.version().to_utf8_lossy() }) .ok_or(BiosParseError::BaseboardVersionNotFound), "baseboard-serial-number" => data .find_map(|baseboard_info: SMBiosBaseboardInformation| { baseboard_info.serial_number().to_utf8_lossy() }) .ok_or(BiosParseError::BaseboardSerialNumberNotFound), "baseboard-asset-tag" => data .find_map(|baseboard_info: SMBiosBaseboardInformation| { baseboard_info.asset_tag().to_utf8_lossy() }) .ok_or(BiosParseError::BaseboardAssetTagNotFound), "chassis-manufacturer" => data .find_map(|chassis_info: SMBiosSystemChassisInformation| { chassis_info.manufacturer().to_utf8_lossy() }) .ok_or(BiosParseError::ChassisManufacturerNotFound), "chassis-type" => match data .find_map(|chassis_info: SMBiosSystemChassisInformation| chassis_info.chassis_type()) { Some(chassis_type) => Ok(format!("{}", chassis_type)), None => Err(BiosParseError::ChassisTypeNotFound), }, "chassis-version" => data .find_map(|chassis_info: SMBiosSystemChassisInformation| { chassis_info.version().to_utf8_lossy() }) .ok_or(BiosParseError::ChassisVersionNotFound), "chassis-serial-number" => data .find_map(|chassis_info: SMBiosSystemChassisInformation| { chassis_info.serial_number().to_utf8_lossy() }) .ok_or(BiosParseError::ChassisSerialNumberNotFound), "chassis-asset-tag" => data .find_map(|chassis_info: SMBiosSystemChassisInformation| { chassis_info.asset_tag_number().to_utf8_lossy() }) .ok_or(BiosParseError::ChassisAssetTagNotFound), "processor-family" => match data.first::() { Some(processor_info) => match processor_info.processor_family() { Some(family) => match family.value { ProcessorFamily::SeeProcessorFamily2 => { match processor_info.processor_family_2() { Some(family) => Ok(format!("{}", family)), None => Err(BiosParseError::ProcessorFamilyNotFound), } } _ => Ok(format!("{}", family)), }, None => Err(BiosParseError::ProcessorFamilyNotFound), }, None => Err(BiosParseError::ProcessorFamilyNotFound), }, "processor-manufacturer" => data .find_map(|processor_info: SMBiosProcessorInformation| { processor_info.processor_manufacturer().to_utf8_lossy() }) .ok_or(BiosParseError::ProcessorManufacturerNotFound), "processor-version" => data .find_map(|processor_info: SMBiosProcessorInformation| { processor_info.processor_version().to_utf8_lossy() }) .ok_or(BiosParseError::ProcessorVersionNotFound), "processor-frequency" => match data .find_map(|processor_info: SMBiosProcessorInformation| processor_info.current_speed()) { Some(current_speed) => Ok(format!("{:?}", current_speed)), None => Err(BiosParseError::ProcessorFrequencyNotFound), }, _ => Err(BiosParseError::InvalidKeywordOnCommandLine), } } fn main() -> Result<(), Box> { let file_option = "f"; let output_option = "o"; let string_option = "s"; let json_option = "j"; let args: Vec = std::env::args().collect(); let mut opts = getopts::Options::new(); opts.optopt(file_option, "", "read smbios table from file", "FILE"); opts.optopt(output_option, "", "dump smbios table to a file", "FILE"); opts.optopt( string_option, "", "Only display the value of the DMI string identified by KEYWORD.", "KEYWORD", ); opts.optflag(json_option, "", "output in json format"); let matches = opts.parse(&args[1..])?; if !matches.opt_present(file_option) && !matches.opt_present(output_option) && !matches.opt_present(string_option) && !matches.opt_present(json_option) { println!("table_data: {:#?}", table_load_from_device()?); return Ok(()); } match matches.opt_str(file_option) { Some(filename) => { let file_path = Path::new(&filename); println!("{:#?}", load_smbios_data_from_file(&file_path)?); } None => (), } match matches.opt_str(output_option) { Some(filename) => { let out_path = Path::new(&filename); dump_raw(raw_smbios_from_device()?, &out_path)?; } None => (), } match matches.opt_str(string_option) { Some(keyword) => { let smbios_data = table_load_from_device()?; let output = string_keyword(keyword, &smbios_data)?; println!("{}", output); } None => (), } if matches.opt_present(json_option) { let smbios_data = table_load_from_device()?; if let Ok(output) = serde_json::to_string(&smbios_data) { println!("{}", output) } } Ok(()) } smbios-lib-0.9.2/src/structs/defined_struct.rs000064400000000000000000000363771046102023000175620ustar 00000000000000//! [DefinedStruct] and [DefinedStructTable] perform downcast operations //! via into() and into_iter() trait functions for [UndefinedStruct]. use serde::Serialize; use std::iter::FromIterator; use crate::core::UndefinedStruct; use super::*; /// # SMBIOS Standard Defined Structure /// /// Represents one of the SMBIOS defined structures or, in the case /// of an OEM defined structure, as a generically defined Unknown variant #[derive(Serialize, Debug)] pub enum DefinedStruct<'a> { /// BIOS Information (Type 0) Information(SMBiosInformation<'a>), /// System Information (Type 1) SystemInformation(SMBiosSystemInformation<'a>), /// Baseboard (or Module) Information (Type 2) BaseBoardInformation(SMBiosBaseboardInformation<'a>), /// System Enclosure or Chassis (Type 3) SystemChassisInformation(SMBiosSystemChassisInformation<'a>), /// Processor Information (Type 4) ProcessorInformation(SMBiosProcessorInformation<'a>), /// Memory Controller Information (Type 5, Obsolete) MemoryControllerInformation(SMBiosMemoryControllerInformation<'a>), /// Memory Module Information (Type 6, Obsolete) MemoryModuleInformation(SMBiosMemoryModuleInformation<'a>), /// Cache Informaiton (Type 7) CacheInformation(SMBiosCacheInformation<'a>), /// Port Connector Information (Type 8) PortConnectorInformation(SMBiosPortConnectorInformation<'a>), /// System Slot Information (Type 9) SystemSlot(SMBiosSystemSlot<'a>), /// On Board Devices Information (Type 10, Obsolete) OnBoardDeviceInformation(SMBiosOnBoardDeviceInformation<'a>), /// OEM Strings (Type 11) OemStrings(SMBiosOemStrings<'a>), /// System Configuration Options (Type 12) SystemConfigurationOptions(SMBiosSystemConfigurationOptions<'a>), /// BIOS Language Information (Type 13) LanguageInformation(SMBiosBiosLanguageInformation<'a>), /// Group Associations (Type 14) GroupAssociations(SMBiosGroupAssociations<'a>), /// System Event Log (Type 15) EventLog(SMBiosSystemEventLog<'a>), /// Physical Memory Array (Type 16) PhysicalMemoryArray(SMBiosPhysicalMemoryArray<'a>), /// Memory Device (Type 17) MemoryDevice(SMBiosMemoryDevice<'a>), /// 32-Bit Memory Error Information (Type 18) MemoryErrorInformation32Bit(SMBiosMemoryErrorInformation32<'a>), /// Memory Array Mapped Address (Type 19) MemoryArrayMappedAddress(SMBiosMemoryArrayMappedAddress<'a>), /// Memory Device Mapped Address (Type 20) MemoryDeviceMappedAddress(SMBiosMemoryDeviceMappedAddress<'a>), /// Built-in Pointing Device (Type 21) BuiltInPointingDevice(SMBiosBuiltInPointingDevice<'a>), /// Portable Battery (Type 22) PortableBattery(SMBiosPortableBattery<'a>), /// System Reset (Type 23) SystemReset(SMBiosSystemReset<'a>), /// Hardware Security (Type 24) HardwareSecurity(SMBiosHardwareSecurity<'a>), /// System Power Controls (Type 25) SystemPowerControls(SMBiosSystemPowerControls<'a>), /// Voltage Probe (Type 26) VoltageProbe(SMBiosVoltageProbe<'a>), /// Cooling Device (Type 27) CoolingDevice(SMBiosCoolingDevice<'a>), /// Temperature Probe (Type 28) TemperatureProbe(SMBiosTemperatureProbe<'a>), /// Electrical Current Probe (Type 29) ElectricalCurrentProbe(SMBiosElectricalCurrentProbe<'a>), /// Out-of-Band Remote Access (Type 30) OutOfBandRemoteAccess(SMBiosOutOfBandRemoteAccess<'a>), /// Boot Integrity Services (BIS) (Type 31) BisEntryPoint(SMBiosBisEntryPoint<'a>), /// System Boot Information (Type 32) SystemBootInformation(SMBiosSystemBootInformation<'a>), /// 64-Bit Memory Error Information (Type 33) MemoryErrorInformation64Bit(SMBiosMemoryErrorInformation64<'a>), /// Management Device (Type 34) ManagementDevice(SMBiosManagementDevice<'a>), /// Management Device Component (Type 35) ManagementDeviceComponent(SMBiosManagementDeviceComponent<'a>), /// Management Device Threshold Data (Type 36) ManagementDeviceThresholdData(SMBiosManagementDeviceThresholdData<'a>), /// Memory Channel (Type 37) MemoryChannel(SMBiosMemoryChannel<'a>), /// IPMI Device Information (Type 38) IpmiDeviceInformation(SMBiosIpmiDeviceInformation<'a>), /// Power Supply (Type 39) SystemPowerSupply(SMBiosSystemPowerSupply<'a>), /// Additional Information (Type 40) AdditionalInformation(SMBiosAdditionalInformation<'a>), /// Onboard Devices Extended Information (Type 41) OnboardDevicesExtendedInformation(SMBiosOnboardDevicesExtendedInformation<'a>), /// Management Controller Host Interface (Type 42) ManagementControllerHostInterface(SMBiosManagementControllerHostInterface<'a>), /// TPM Device (Type 43) TpmDevice(SMBiosTpmDevice<'a>), /// Processor Additional Information (Type 44) ProcessorAdditionalInformation(SMBiosProcessorAdditionalInformation<'a>), /// Firmware Inventory Information (Type 45) FirmwareInventoryInformation(SMBiosFirmwareInventoryInformation<'a>), /// String Property (Type 46) StringProperty(SMBiosStringProperty<'a>), /// Inactive (Type 126) Inactive(SMBiosInactive<'a>), /// End-of-Table (Type 127) EndOfTable(SMBiosEndOfTable<'a>), /// OEM-Defined or Unknown Structure /// /// - A structure with a type value not yet defined, such as by a DMTF specification /// that supercedes the types known by this library /// - An OEM type with a value > 127. Undefined(SMBiosUnknown<'a>), } impl<'a> From<&'a UndefinedStruct> for DefinedStruct<'a> { fn from(undefined_struct: &'a UndefinedStruct) -> Self { match undefined_struct.header.struct_type() { SMBiosInformation::STRUCT_TYPE => { DefinedStruct::Information(SMBiosInformation::new(undefined_struct)) } SMBiosSystemInformation::STRUCT_TYPE => { DefinedStruct::SystemInformation(SMBiosSystemInformation::new(undefined_struct)) } SMBiosBaseboardInformation::STRUCT_TYPE => DefinedStruct::BaseBoardInformation( SMBiosBaseboardInformation::new(undefined_struct), ), SMBiosSystemChassisInformation::STRUCT_TYPE => DefinedStruct::SystemChassisInformation( SMBiosSystemChassisInformation::new(undefined_struct), ), SMBiosProcessorInformation::STRUCT_TYPE => DefinedStruct::ProcessorInformation( SMBiosProcessorInformation::new(undefined_struct), ), SMBiosMemoryControllerInformation::STRUCT_TYPE => { DefinedStruct::MemoryControllerInformation(SMBiosMemoryControllerInformation::new( undefined_struct, )) } SMBiosMemoryModuleInformation::STRUCT_TYPE => DefinedStruct::MemoryModuleInformation( SMBiosMemoryModuleInformation::new(undefined_struct), ), SMBiosCacheInformation::STRUCT_TYPE => { DefinedStruct::CacheInformation(SMBiosCacheInformation::new(undefined_struct)) } SMBiosPortConnectorInformation::STRUCT_TYPE => DefinedStruct::PortConnectorInformation( SMBiosPortConnectorInformation::new(undefined_struct), ), SMBiosSystemSlot::STRUCT_TYPE => { DefinedStruct::SystemSlot(SMBiosSystemSlot::new(undefined_struct)) } SMBiosOnBoardDeviceInformation::STRUCT_TYPE => DefinedStruct::OnBoardDeviceInformation( SMBiosOnBoardDeviceInformation::new(undefined_struct), ), SMBiosOemStrings::STRUCT_TYPE => { DefinedStruct::OemStrings(SMBiosOemStrings::new(undefined_struct)) } SMBiosSystemConfigurationOptions::STRUCT_TYPE => { DefinedStruct::SystemConfigurationOptions(SMBiosSystemConfigurationOptions::new( undefined_struct, )) } SMBiosBiosLanguageInformation::STRUCT_TYPE => DefinedStruct::LanguageInformation( SMBiosBiosLanguageInformation::new(undefined_struct), ), SMBiosGroupAssociations::STRUCT_TYPE => { DefinedStruct::GroupAssociations(SMBiosGroupAssociations::new(undefined_struct)) } SMBiosSystemEventLog::STRUCT_TYPE => { DefinedStruct::EventLog(SMBiosSystemEventLog::new(undefined_struct)) } SMBiosPhysicalMemoryArray::STRUCT_TYPE => { DefinedStruct::PhysicalMemoryArray(SMBiosPhysicalMemoryArray::new(undefined_struct)) } SMBiosMemoryDevice::STRUCT_TYPE => { DefinedStruct::MemoryDevice(SMBiosMemoryDevice::new(undefined_struct)) } SMBiosMemoryErrorInformation32::STRUCT_TYPE => { DefinedStruct::MemoryErrorInformation32Bit(SMBiosMemoryErrorInformation32::new( undefined_struct, )) } SMBiosMemoryArrayMappedAddress::STRUCT_TYPE => DefinedStruct::MemoryArrayMappedAddress( SMBiosMemoryArrayMappedAddress::new(undefined_struct), ), SMBiosMemoryDeviceMappedAddress::STRUCT_TYPE => { DefinedStruct::MemoryDeviceMappedAddress(SMBiosMemoryDeviceMappedAddress::new( undefined_struct, )) } SMBiosBuiltInPointingDevice::STRUCT_TYPE => DefinedStruct::BuiltInPointingDevice( SMBiosBuiltInPointingDevice::new(undefined_struct), ), SMBiosPortableBattery::STRUCT_TYPE => { DefinedStruct::PortableBattery(SMBiosPortableBattery::new(undefined_struct)) } SMBiosSystemReset::STRUCT_TYPE => { DefinedStruct::SystemReset(SMBiosSystemReset::new(undefined_struct)) } SMBiosHardwareSecurity::STRUCT_TYPE => { DefinedStruct::HardwareSecurity(SMBiosHardwareSecurity::new(undefined_struct)) } SMBiosSystemPowerControls::STRUCT_TYPE => { DefinedStruct::SystemPowerControls(SMBiosSystemPowerControls::new(undefined_struct)) } SMBiosVoltageProbe::STRUCT_TYPE => { DefinedStruct::VoltageProbe(SMBiosVoltageProbe::new(undefined_struct)) } SMBiosCoolingDevice::STRUCT_TYPE => { DefinedStruct::CoolingDevice(SMBiosCoolingDevice::new(undefined_struct)) } SMBiosTemperatureProbe::STRUCT_TYPE => { DefinedStruct::TemperatureProbe(SMBiosTemperatureProbe::new(undefined_struct)) } SMBiosElectricalCurrentProbe::STRUCT_TYPE => DefinedStruct::ElectricalCurrentProbe( SMBiosElectricalCurrentProbe::new(undefined_struct), ), SMBiosOutOfBandRemoteAccess::STRUCT_TYPE => DefinedStruct::OutOfBandRemoteAccess( SMBiosOutOfBandRemoteAccess::new(undefined_struct), ), SMBiosBisEntryPoint::STRUCT_TYPE => { DefinedStruct::BisEntryPoint(SMBiosBisEntryPoint::new(undefined_struct)) } SMBiosSystemBootInformation::STRUCT_TYPE => DefinedStruct::SystemBootInformation( SMBiosSystemBootInformation::new(undefined_struct), ), SMBiosMemoryErrorInformation64::STRUCT_TYPE => { DefinedStruct::MemoryErrorInformation64Bit(SMBiosMemoryErrorInformation64::new( undefined_struct, )) } SMBiosManagementDevice::STRUCT_TYPE => { DefinedStruct::ManagementDevice(SMBiosManagementDevice::new(undefined_struct)) } SMBiosManagementDeviceComponent::STRUCT_TYPE => { DefinedStruct::ManagementDeviceComponent(SMBiosManagementDeviceComponent::new( undefined_struct, )) } SMBiosManagementDeviceThresholdData::STRUCT_TYPE => { DefinedStruct::ManagementDeviceThresholdData( SMBiosManagementDeviceThresholdData::new(undefined_struct), ) } SMBiosMemoryChannel::STRUCT_TYPE => { DefinedStruct::MemoryChannel(SMBiosMemoryChannel::new(undefined_struct)) } SMBiosIpmiDeviceInformation::STRUCT_TYPE => DefinedStruct::IpmiDeviceInformation( SMBiosIpmiDeviceInformation::new(undefined_struct), ), SMBiosSystemPowerSupply::STRUCT_TYPE => { DefinedStruct::SystemPowerSupply(SMBiosSystemPowerSupply::new(undefined_struct)) } SMBiosAdditionalInformation::STRUCT_TYPE => DefinedStruct::AdditionalInformation( SMBiosAdditionalInformation::new(undefined_struct), ), SMBiosOnboardDevicesExtendedInformation::STRUCT_TYPE => { DefinedStruct::OnboardDevicesExtendedInformation( SMBiosOnboardDevicesExtendedInformation::new(undefined_struct), ) } SMBiosManagementControllerHostInterface::STRUCT_TYPE => { DefinedStruct::ManagementControllerHostInterface( SMBiosManagementControllerHostInterface::new(undefined_struct), ) } SMBiosTpmDevice::STRUCT_TYPE => { DefinedStruct::TpmDevice(SMBiosTpmDevice::new(undefined_struct)) } SMBiosProcessorAdditionalInformation::STRUCT_TYPE => { DefinedStruct::ProcessorAdditionalInformation( SMBiosProcessorAdditionalInformation::new(undefined_struct), ) } SMBiosFirmwareInventoryInformation::STRUCT_TYPE => { DefinedStruct::FirmwareInventoryInformation( SMBiosFirmwareInventoryInformation::new(undefined_struct), ) } SMBiosStringProperty::STRUCT_TYPE => { DefinedStruct::StringProperty(SMBiosStringProperty::new(undefined_struct)) } SMBiosInactive::STRUCT_TYPE => { DefinedStruct::Inactive(SMBiosInactive::new(undefined_struct)) } SMBiosEndOfTable::STRUCT_TYPE => { DefinedStruct::EndOfTable(SMBiosEndOfTable::new(undefined_struct)) } _ => DefinedStruct::Undefined(SMBiosUnknown::new(undefined_struct)), } } } /// # Defined Struct Table /// /// Contains a list of [DefinedStruct] items. #[derive(Serialize, Debug)] pub struct DefinedStructTable<'a>(Vec>); impl<'a> DefinedStructTable<'a> { fn new() -> DefinedStructTable<'a> { DefinedStructTable(Vec::new()) } fn add(&mut self, elem: DefinedStruct<'a>) { self.0.push(elem); } } impl<'a> IntoIterator for DefinedStructTable<'a> { type Item = DefinedStruct<'a>; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } impl<'a> FromIterator<&'a UndefinedStruct> for DefinedStructTable<'a> { fn from_iter>(iter: I) -> Self { let mut defined_struct_table = DefinedStructTable::new(); for undefined_struct in iter { defined_struct_table.add(undefined_struct.into()); } defined_struct_table } } smbios-lib-0.9.2/src/structs/mod.rs000064400000000000000000000001621046102023000153160ustar 00000000000000mod defined_struct; mod structure; mod types; pub use defined_struct::*; pub use structure::*; pub use types::*; smbios-lib-0.9.2/src/structs/structure.rs000064400000000000000000000010341046102023000165760ustar 00000000000000use crate::core::UndefinedStruct; /// # SMBIOS Structure /// /// A type implementing this trait provides a representation of an SMBIOS type. pub trait SMBiosStruct<'a> { /// The SMBIOS structure type /// /// Example: System Information (Type 1) this is set to 1. const STRUCT_TYPE: u8; /// Creates a new instance of the implementing SMBIOS type fn new(parts: &'a UndefinedStruct) -> Self; /// Contains the standard parts/sections of the implementing SMBIOS type. fn parts(&self) -> &'a UndefinedStruct; } smbios-lib-0.9.2/src/structs/types/additional_information.rs000064400000000000000000000262401046102023000224250ustar 00000000000000use crate::core::{strings::*, Handle, UndefinedStruct}; use crate::structs::SMBiosStruct; use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Additional Information Entry contained within [SMBiosAdditionalInformation] pub struct AdditionalInformationEntry<'a> { additional_information: &'a SMBiosAdditionalInformation<'a>, entry_offset: usize, } impl<'a> AdditionalInformationEntry<'a> { fn new( additional_information: &'a SMBiosAdditionalInformation<'a>, entry_offset: usize, ) -> Self { Self { additional_information, entry_offset, } } /// Length of this Additional Information Entry instance; a minimum of 6 pub fn entry_length(&self) -> Option { self.additional_information .parts() .get_field_byte(self.entry_offset) } /// Handle, or instance number, associated with the structure for which additional information is provided pub fn referenced_handle(&self) -> Option { self.additional_information .parts() .get_field_handle(self.entry_offset + 1) } /// Offset of the field within the structure referenced by the /// _Referenced Handle_ for which additional information is provided pub fn referenced_offset(&self) -> Option { self.additional_information .parts() .get_field_byte(self.entry_offset + 3) } /// Number of the optional string to be associated with the field referenced by the _Referenced Offset_ pub fn string(&self) -> SMBiosString { self.additional_information .parts() .get_field_string(self.entry_offset + 4) } /// Enumerated value or updated field content that has not yet been /// approved for publication in this specification and therefore could /// not be used in the field referenced by _Referenced Offset_ /// /// NOTE: This field is the same type and size as the field being referenced /// by this Additional Information Entry. pub fn value(&self) -> Option<&[u8]> { const VALUE_RELATIVE_OFFSET: usize = 5usize; let value_offset = self.entry_offset + VALUE_RELATIVE_OFFSET; match self.entry_length() { Some(entry_length) => { let value_size = entry_length as usize - VALUE_RELATIVE_OFFSET; self.additional_information .parts() .get_field_data(value_offset, value_offset + value_size) } None => None, } } } impl fmt::Debug for AdditionalInformationEntry<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("entry_length", &self.entry_length()) .field("referenced_handle", &self.referenced_handle()) .field("referenced_offset", &self.referenced_offset()) .field("string", &self.string()) .field("value", &self.value()) .finish() } } impl Serialize for AdditionalInformationEntry<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("AdditionalInformationEntry", 5)?; state.serialize_field("entry_length", &self.entry_length())?; state.serialize_field("referenced_handle", &self.referenced_handle())?; state.serialize_field("referenced_offset", &self.referenced_offset())?; state.serialize_field("string", &self.string())?; state.serialize_field("value", &self.value())?; state.end() } } /// # Iterates over the [AdditionalInformationEntry] entries contained within [SMBiosAdditionalInformation] pub struct AdditionalInformationEntryIterator<'a> { data: &'a SMBiosAdditionalInformation<'a>, current_index: usize, current_entry: u8, number_of_entries: u8, } impl<'a> AdditionalInformationEntryIterator<'a> { const ENTRIES_OFFSET: usize = 5usize; fn new(data: &'a SMBiosAdditionalInformation<'a>) -> Self { AdditionalInformationEntryIterator { data: data, current_index: Self::ENTRIES_OFFSET, current_entry: 0, number_of_entries: data.number_of_entries().unwrap_or(0), } } fn reset(&mut self) { self.current_index = Self::ENTRIES_OFFSET; self.current_entry = 0; } } impl<'a> IntoIterator for &'a AdditionalInformationEntryIterator<'a> { type Item = AdditionalInformationEntry<'a>; type IntoIter = AdditionalInformationEntryIterator<'a>; fn into_iter(self) -> Self::IntoIter { AdditionalInformationEntryIterator { data: self.data, current_index: AdditionalInformationEntryIterator::ENTRIES_OFFSET, current_entry: 0, number_of_entries: self.data.number_of_entries().unwrap_or(0), } } } impl<'a> Iterator for AdditionalInformationEntryIterator<'a> { type Item = AdditionalInformationEntry<'a>; fn next(&mut self) -> Option { if self.current_entry == self.number_of_entries { self.reset(); return None; } match self.data.parts().get_field_byte(self.current_index) { Some(entry_length) => { // Length of 0 would result in an endless loop because we would never advance to the next entry if entry_length == 0 { self.reset(); return None; } let next_index = self.current_index + entry_length as usize; match self .data .parts() .get_field_data(self.current_index, next_index) { Some(_entry_block) => { let result = AdditionalInformationEntry::new(self.data, self.current_index); self.current_index = next_index; self.current_entry += 1; Some(result) } None => { self.reset(); None } } } None => { self.reset(); None } } } } impl<'a> fmt::Debug for AdditionalInformationEntryIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().entries(self.into_iter()).finish() } } impl<'a> Serialize for AdditionalInformationEntryIterator<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let entries: Vec> = self.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(entries.len()))?; for e in entries { seq.serialize_element(&e)?; } seq.end() } } /// # Additional Information (Type 40) /// /// This structure is intended to provide additional information for handling unspecified enumerated values /// and interim field updates in another structure. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosAdditionalInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosAdditionalInformation<'a> { const STRUCT_TYPE: u8 = 40u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosAdditionalInformation<'a> { /// Number of [AdditionalInformationEntry] entries pub fn number_of_entries(&self) -> Option { self.parts.get_field_byte(0x04) } /// Iterates over the [AdditionalInformationEntry] entries pub fn entry_iterator(&'a self) -> AdditionalInformationEntryIterator<'a> { AdditionalInformationEntryIterator::new(self) } } impl fmt::Debug for SMBiosAdditionalInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("number_of_entries", &self.number_of_entries()) .field("entry_iterator", &self.entry_iterator()) .finish() } } impl Serialize for SMBiosAdditionalInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosAdditionalInformation", 3)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("number_of_entries", &self.number_of_entries())?; state.serialize_field("entry_iterator", &self.entry_iterator())?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_additional_information() { let additional_information_bytes = vec![ 0x28u8, 0x0B, 0x02, 0x01, // header (offsets 0-3) 0x01, // 1 additional entry (offset 4) 0x6, 0x04, 0x03, 0x22, 0x01, 0x67, // entry (offsets 5-0x0A) 0x58, 0x00, // entry string "X" (offsets 0x0B-0x0C) 0x00, ]; // end of structure (offset 0x0D) let parts = UndefinedStruct::new(&additional_information_bytes); let additional_information = SMBiosAdditionalInformation::new(&parts); assert_eq!(*additional_information.parts().header.handle(), 0x0102); assert_eq!(additional_information.parts().header.length(), 0x0B); assert_eq!( additional_information .number_of_entries() .expect("must be 1 entry"), 1 ); let mut iterator = additional_information.entry_iterator(); let first_entry = iterator.next().expect("must have a first entry"); assert_eq!( first_entry .entry_length() .expect("must be entry length of 6"), 6 ); assert_eq!(first_entry.string().to_string(), "X".to_string()); assert!(iterator.next().is_none()); let additional_information_bytes = vec![ 0x28u8, 0x11, 0x02, 0x01, // header (offsets 0-3) 0x02, // 2 additional entries (offset 4) 0x6, 0x04, 0x03, 0x22, 0x00, 0x67, // entry (offsets 5-0x0A) 0x6, 0x06, 0x05, 0x33, 0x00, 0x89, // entry (offsets 0x0B-0x10) 0x00, // null string (offsets 0x0B-0x0C) 0x00, ]; // end of structure (offset 0x0D) let parts = UndefinedStruct::new(&additional_information_bytes); let additional_information = SMBiosAdditionalInformation::new(&parts); let mut counter = 0; for _entry in additional_information.entry_iterator() { counter = counter + 1; } assert_eq!(counter, 2); assert_eq!( additional_information .number_of_entries() .expect("must be 2 entries"), counter ); println!("additional_information: {:?}", additional_information); } } smbios-lib-0.9.2/src/structs/types/baseboard_information.rs000064400000000000000000000412751046102023000222440ustar 00000000000000use crate::core::{strings::*, Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # Baseboard (or Module) Information (Type 2) /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosBaseboardInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosBaseboardInformation<'a> { const STRUCT_TYPE: u8 = 2u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosBaseboardInformation<'a> { ///Baseboard manufacturer pub fn manufacturer(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Baseboard product pub fn product(&self) -> SMBiosString { self.parts.get_field_string(0x05) } /// Baseboard version pub fn version(&self) -> SMBiosString { self.parts.get_field_string(0x06) } /// Baseboard serial number pub fn serial_number(&self) -> SMBiosString { self.parts.get_field_string(0x07) } /// Baseboard asset tag pub fn asset_tag(&self) -> SMBiosString { self.parts.get_field_string(0x08) } /// Collection of flags that identify features of this baseboard. pub fn feature_flags(&self) -> Option { self.parts .get_field_byte(0x09) .map(|raw| BaseboardFeatures::from(raw)) } /// This baseboard's location within the chassis (chassis is referenced by ChassisHandle). pub fn location_in_chassis(&self) -> SMBiosString { self.parts.get_field_string(0x0A) } /// Handle, or instance number, associated with the chassis in which this board resides. pub fn chassis_handle(&self) -> Option { self.parts.get_field_handle(0x0B) } /// Type of baseboard. pub fn board_type(&self) -> Option { self.parts .get_field_byte(0x0D) .map(|raw| BoardTypeData::from(raw)) } /// The count of ObjectHandles. pub fn number_of_contained_object_handles(&self) -> Option { self.parts.get_field_byte(0x0E) } /// List of handles of other structures that are contained by this baseboard. pub fn contained_object_handle_iterator(&'a self) -> ObjectHandleIterator<'a> { ObjectHandleIterator::new(self) } } impl fmt::Debug for SMBiosBaseboardInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("manufacturer", &self.manufacturer()) .field("product", &self.product()) .field("version", &self.version()) .field("serial_number", &self.serial_number()) .field("asset_tag", &self.asset_tag()) .field("feature_flags", &self.feature_flags()) .field("location_in_chassis", &self.location_in_chassis()) .field("chassis_handle", &self.chassis_handle()) .field("board_type", &self.board_type()) .field( "number_of_contained_object_handles", &self.number_of_contained_object_handles(), ) .field( "contained_object_handle_iterator", &self.contained_object_handle_iterator(), ) .finish() } } impl Serialize for SMBiosBaseboardInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosBaseboardInformation", 12)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("manufacturer", &self.manufacturer())?; state.serialize_field("product", &self.product())?; state.serialize_field("version", &self.version())?; state.serialize_field("serial_number", &self.serial_number())?; state.serialize_field("asset_tag", &self.asset_tag())?; state.serialize_field("feature_flags", &self.feature_flags())?; state.serialize_field("location_in_chassis", &self.location_in_chassis())?; state.serialize_field("chassis_handle", &self.chassis_handle())?; state.serialize_field("board_type", &self.board_type())?; state.serialize_field( "number_of_contained_object_handles", &self.number_of_contained_object_handles(), )?; state.serialize_field( "contained_object_handle_iterator", &self.contained_object_handle_iterator(), )?; state.end() } } /// # Board Type Data pub struct BoardTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [BoardType] value pub value: BoardType, } impl fmt::Debug for BoardTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for BoardTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("BoardTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for BoardTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { BoardType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for BoardTypeData { type Target = BoardType; fn deref(&self) -> &Self::Target { &self.value } } impl From for BoardTypeData { fn from(raw: u8) -> Self { BoardTypeData { value: match raw { 0x01 => BoardType::Other, 0x02 => BoardType::Unknown, 0x03 => BoardType::ServerBlade, 0x04 => BoardType::ConnectivitySwitch, 0x05 => BoardType::SystemManagementModule, 0x06 => BoardType::ProcessorModule, 0x07 => BoardType::IOModule, 0x08 => BoardType::MemoryModule, 0x09 => BoardType::Daughterboard, 0x0A => BoardType::Motherboard, 0x0B => BoardType::ProcessorMemoryModule, 0x0C => BoardType::ProcessorIOModule, 0x0D => BoardType::InterconnectBoard, _ => BoardType::None, }, raw, } } } /// # Board Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum BoardType { /// Unknown Unknown, /// Other Other, /// Server Blade ServerBlade, /// Connectivity Switch ConnectivitySwitch, /// System Management Module SystemManagementModule, /// Processor Module ProcessorModule, /// I/O Module IOModule, /// Memory Module MemoryModule, /// Daughter board Daughterboard, /// Motherboard (includes processor, memory, and I/O) Motherboard, /// Processor/Memory Module ProcessorMemoryModule, /// Processor/IO Module ProcessorIOModule, /// Interconnect board InterconnectBoard, /// A value unknown to this standard, check the raw value None, } /// # Baseboard Features #[derive(PartialEq, Eq)] pub struct BaseboardFeatures { /// Raw value /// /// _raw_ is useful when there are values not yet defiend. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, } impl Deref for BaseboardFeatures { type Target = u8; fn deref(&self) -> &Self::Target { &self.raw } } impl From for BaseboardFeatures { fn from(raw: u8) -> Self { BaseboardFeatures { raw } } } impl BaseboardFeatures { /// Set if the board is a hosting board (for example, a motherboard). pub fn hosting_board(&self) -> bool { self.raw & 0x01 == 0x01 } /// Set if the board requires at least one daughter board or auxiliary card to function properly. pub fn requires_daughterboard(&self) -> bool { self.raw & 0x02 == 0x02 } /// Set if the board is removable; it is designed to be taken in and out of the chassis without impairing the function of the chassis. pub fn is_removable(&self) -> bool { self.raw & 0x04 == 0x04 } /// Set if the board is replaceable; it is possible to replace (either as a field repair or as an upgrade) the board with a physically different board. The board is inherently removable. pub fn is_replaceable(&self) -> bool { self.raw & 0x08 == 0x08 } /// Set if the board is hot swappable; it is possible to replace the board with a physically different but equivalent board while power is applied to the board. The board is inherently replaceable and removable. pub fn is_hot_swappable(&self) -> bool { self.raw & 0x10 == 0x10 } } impl fmt::Debug for BaseboardFeatures { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("hosting_board", &self.hosting_board()) .field("requires_daughterboard", &self.requires_daughterboard()) .field("is_removable", &self.is_removable()) .field("is_replaceable", &self.is_replaceable()) .field("is_hot_swappable", &self.is_hot_swappable()) .finish() } } impl Serialize for BaseboardFeatures { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("BaseboardFeatures", 6)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("hosting_board", &self.hosting_board())?; state.serialize_field("requires_daughterboard", &self.requires_daughterboard())?; state.serialize_field("is_removable", &self.is_removable())?; state.serialize_field("is_replaceable", &self.is_replaceable())?; state.serialize_field("is_hot_swappable", &self.is_hot_swappable())?; state.end() } } /// # Object Handle Iterator /// /// Iterates over the object handles contained within the [SMBiosBaseboardInformation] structure pub struct ObjectHandleIterator<'a> { data: &'a SMBiosBaseboardInformation<'a>, current_index: usize, current_entry: u8, number_of_contained_object_handles: u8, } impl<'a> ObjectHandleIterator<'a> { const OBJECT_HANDLES_OFFSET: usize = 0x0Fusize; /// Creates an instance of the object handle iterator. pub fn new(data: &'a SMBiosBaseboardInformation<'a>) -> Self { ObjectHandleIterator { data: data, current_index: Self::OBJECT_HANDLES_OFFSET, current_entry: 0, number_of_contained_object_handles: data .number_of_contained_object_handles() .unwrap_or(0), } } fn reset(&mut self) { self.current_index = Self::OBJECT_HANDLES_OFFSET; self.current_entry = 0; } } impl<'a> IntoIterator for &'a ObjectHandleIterator<'a> { type Item = Handle; type IntoIter = ObjectHandleIterator<'a>; fn into_iter(self) -> Self::IntoIter { ObjectHandleIterator { data: self.data, current_index: ObjectHandleIterator::OBJECT_HANDLES_OFFSET, current_entry: 0, number_of_contained_object_handles: self .data .number_of_contained_object_handles() .unwrap_or(0), } } } impl<'a> Iterator for ObjectHandleIterator<'a> { type Item = Handle; fn next(&mut self) -> Option { if self.current_entry == self.number_of_contained_object_handles { self.reset(); return None; } match self.data.parts().get_field_handle(self.current_index) { Some(current_handle) => { self.current_index = self.current_index + Handle::SIZE; self.current_entry = self.current_entry + 1; Some(current_handle) } None => { self.reset(); None } } } } impl<'a> fmt::Debug for ObjectHandleIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().entries(self.into_iter()).finish() } } impl<'a> Serialize for ObjectHandleIterator<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let handles: Vec = self.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(handles.len()))?; for e in handles { seq.serialize_element(&e)?; } seq.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_baseboard_information() { let baseboard_information_bytes = vec![ // struct_type(2), length(0x13), handle(0x10) 0x02, 0x13, 0x10, 0x00, // manufacturer(1), product(2), version(0), serial_number(3), asset_tag(0), feature_flags(1), // location_in_chassis(0), chassis_handle(0x0F), board_type(0x0A), number_of_contained_object_handles(2) 0x01, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x0A, 0x02, // handle[0] == 0x0005 0x05, 0x00, // handle[1] == 0x1200 0x00, 0x12, // manufacturer: "Microsoft Corporation" (1) 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x43, 0x6F, 0x72, 0x70, 0x6F, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00, // product: "Surface Laptop 3" (2) 0x53, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x20, 0x4C, 0x61, 0x70, 0x74, 0x6F, 0x70, 0x20, 0x33, 0x00, // serial_number: "B009250100J1939B" (3) 0x42, 0x30, 0x30, 0x39, 0x32, 0x35, 0x30, 0x31, 0x30, 0x30, 0x4A, 0x31, 0x39, 0x33, 0x39, 0x42, 0x00, // end of structure 0x00, ]; let parts = UndefinedStruct::new(&baseboard_information_bytes); let baseboard_information = SMBiosBaseboardInformation::new(&parts); // header tests assert_eq!(*baseboard_information.parts().header.handle(), 0x0010); assert_eq!(baseboard_information.parts().header.length(), 0x13); // basic field tests assert_eq!( baseboard_information.manufacturer().to_string(), "Microsoft Corporation".to_string() ); assert_eq!( baseboard_information.product().to_string(), "Surface Laptop 3".to_string() ); assert_eq!(baseboard_information.version().to_string(), "".to_string()); assert_eq!( baseboard_information.serial_number().to_string(), "B009250100J1939B".to_string() ); assert_eq!( baseboard_information.asset_tag().to_string(), "".to_string() ); assert_eq!( baseboard_information.feature_flags().unwrap(), BaseboardFeatures::from(1) ); assert_eq!( baseboard_information.location_in_chassis().to_string(), "".to_string() ); assert_eq!(*baseboard_information.chassis_handle().unwrap(), 0x0F); assert_eq!( *baseboard_information.board_type().unwrap(), BoardType::Motherboard ); // contained object handle tests assert_eq!( baseboard_information .number_of_contained_object_handles() .unwrap(), 2 ); let mut iterator = baseboard_information.contained_object_handle_iterator(); let first_entry = iterator.next().expect("has a first entry"); assert_eq!(*first_entry, 0x0005); let second_entry = iterator.next().expect("has a second entry"); assert_eq!(*second_entry, 0x1200); assert!(iterator.next().is_none()); let mut counter = 0; for _entry in baseboard_information.contained_object_handle_iterator() { counter = counter + 1; } assert_eq!(counter, 2); // debug print test println!("baseboard_information: {:?}", baseboard_information); } } smbios-lib-0.9.2/src/structs/types/bios_information.rs000064400000000000000000001075771046102023000212660ustar 00000000000000use crate::core::{strings::*, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # BIOS Information (Type 0) /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.5.0 (DSP0134) /// Document Date: 2021-09-15 pub struct SMBiosInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosInformation<'a> { const STRUCT_TYPE: u8 = 0u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosInformation<'a> { /// BIOS vendor's name pub fn vendor(&self) -> SMBiosString { self.parts.get_field_string(0x4) } /// BIOS version /// /// This value is a free-form string that may contain /// Core and OEM version information. pub fn version(&self) -> SMBiosString { self.parts.get_field_string(0x5) } /// BIOS starting address segment /// /// Segment location of BIOS starting address /// (for example, 0E800h). /// /// When not applicable, such as on UEFI-based systems, /// this value is set to 0000h. /// /// NOTE: The size of the runtime BIOS image can /// be computed by subtracting the Starting /// Address Segment from 10000h and /// multiplying the result by 16. pub fn starting_address_segment(&self) -> Option { self.parts.get_field_word(0x6) } /// BIOS release date /// /// The date string, if supplied, is in either /// mm/dd/yy or mm/dd/yyyy format. If the year /// portion of the string is two digits, the year is /// assumed to be 19yy. /// /// NOTE: The mm/dd/yyyy format is required for /// SMBIOS version 2.3 and later. pub fn release_date(&self) -> SMBiosString { self.parts.get_field_string(0x8) } /// BIOS ROM size /// /// Size (n) where 64K * (n+1) is the size of the /// physical device containing the BIOS, in /// bytes. /// /// FFh - size is 16MB or greater, see Extended /// BIOS ROM Size for actual size pub fn rom_size(&self) -> Option { self.parts.get_field_byte(0x9).map(|raw| RomSize::from(raw)) } /// BIOS characteristics /// /// Defines which functions the BIOS supports: /// PCI, PCMCIA, Flash, etc pub fn characteristics(&self) -> Option { self.parts .get_field_dword(0xA) .map(|raw| BiosCharacteristics::from(raw)) } /// BIOS vendor reserved characteristics pub fn bios_vendor_reserved_characteristics(&self) -> Option { self.parts.get_field_word(0xE) } /// System vendor reserved characteristics pub fn system_vendor_reserved_characteristics(&self) -> Option { self.parts.get_field_word(0x10) } /// Characteristics extension byte 0 pub fn characteristics_extension0(&self) -> Option { self.parts .get_field_byte(0x12) .map(|raw| BiosCharacteristicsExtension0::from(raw)) } /// Characteristics extension byte 1 pub fn characteristics_extension1(&self) -> Option { self.parts .get_field_byte(0x13) .map(|raw| BiosCharacteristicsExtension1::from(raw)) } /// System BIOS major release /// /// Identifies the major release of the System /// BIOS; for example, the value is 0Ah for /// revision 10.22 and 02h for revision 2.1. /// /// This field or the System BIOS Minor /// Release field or both are updated each time /// a System BIOS update for a given system is /// released. /// /// If the system does not support the use of /// this field, the value is 0FFh for both this field /// and the System BIOS Minor Release field. pub fn system_bios_major_release(&self) -> Option { self.parts.get_field_byte(0x14) } /// System BIOS minor release /// /// Identifies the minor release of the System /// BIOS; for example, the value is 16h for /// revision 10.22 and 01h for revision 2.1. pub fn system_bios_minor_release(&self) -> Option { self.parts.get_field_byte(0x15) } /// Embedded controller firmware major release /// /// Identifies the major release of the /// embedded controller firmware; for example, /// the value would be 0Ah for revision 10.22 /// and 02h for revision 2.1. /// /// This field or the Embedded Controller /// Firmware Minor Release field or both are /// updated each time an embedded controller /// firmware update for a given system is /// released. /// /// If the system does not have field /// upgradeable embedded controller firmware, /// the value is 0FFh. pub fn e_c_firmware_major_release(&self) -> Option { self.parts.get_field_byte(0x16) } /// Embedded controller firmware minor release /// /// Identifies the minor release of the /// embedded controller firmware; for example, /// the value is 16h for revision 10.22 and 01h /// for revision 2.1. /// If the system does not have field /// upgradeable embedded controller firmware, /// the value is 0FFh. pub fn e_c_firmware_minor_release(&self) -> Option { self.parts.get_field_byte(0x17) } /// Extended BIOS ROM size /// /// Extended size of the physical device(s) /// containing the BIOS, rounded up if needed. /// /// Bits 15:14 Unit /// 00b - megabytes /// 01b - gigabytes /// 10b - reserved /// 11b - reserved /// Bits 13:0 Size /// /// Examples: a 16 MB device would be /// represented as 0010h. A 48 GB device set /// would be represented as /// 0100_0000_0011_0000b or 4030h. pub fn extended_rom_size(&self) -> Option { self.parts .get_field_word(0x18) .map(|raw| RomSize::from(raw)) } } /// # BIOS ROM size #[derive(Serialize, Debug, PartialEq, Eq)] pub enum RomSize { /// Size of this rom in bytes Kilobytes(u16), /// Extended size of the physical device(s) /// containing the BIOS (in MB). Megabytes(u16), /// Extended size of the physical device(s) /// containing the BIOS (in GB). Gigabytes(u16), /// Extended size of the physical device(s) /// containing the BIOS in raw form. /// /// The standard currently only defines MB and GB /// as given in the high nibble (bits 15-14) Undefined(u16), /// The value present is 16MB or greater and must be found using `extended_rom_size` SeeExtendedRomSize, } impl From for RomSize { fn from(raw: u16) -> Self { // Bits 15:14 Unit // 00b - megabytes // 01b - gigabytes // 10b - reserved // 11b - reserved // Bits 13:0 Size let unit = raw & 0b11000000_00000000; // 15:14 mask let size = raw & 0b00111111_11111111; // 13:0 mask if unit == 0b00000000_00000000 { RomSize::Megabytes(size) } else if unit == 0b01000000_00000000 { RomSize::Gigabytes(size) } else { RomSize::Undefined(raw) } } } impl From for RomSize { fn from(raw: u8) -> Self { match raw { 0xFF => RomSize::SeeExtendedRomSize, // Size (n) where 64K * (n+1) is the size of the // physical device containing the BIOS, in bytes. _ => RomSize::Kilobytes(64 * (raw as u16 + 1)), } } } impl fmt::Debug for SMBiosInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("vendor", &self.vendor()) .field("version", &self.version()) .field("starting_address_segment", &self.starting_address_segment()) .field("release_date", &self.release_date()) .field("rom_size", &self.rom_size()) .field("characteristics", &self.characteristics()) .field( "bios_vendor_reserved_characteristics", &self.bios_vendor_reserved_characteristics(), ) .field( "system_vendor_reserved_characteristics", &self.system_vendor_reserved_characteristics(), ) .field( "characteristics_extension0", &self.characteristics_extension0(), ) .field( "characteristics_extension1", &self.characteristics_extension1(), ) .field( "system_bios_major_release", &self.system_bios_major_release(), ) .field( "system_bios_minor_release", &self.system_bios_minor_release(), ) .field( "e_c_firmware_major_release", &self.e_c_firmware_major_release(), ) .field( "e_c_firmware_minor_release", &self.e_c_firmware_minor_release(), ) .field("extended_rom_size", &self.extended_rom_size()) .finish() } } impl Serialize for SMBiosInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosInformation", 16)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("vendor", &self.vendor())?; state.serialize_field("version", &self.version())?; state.serialize_field("starting_address_segment", &self.starting_address_segment())?; state.serialize_field("release_date", &self.release_date())?; state.serialize_field("rom_size", &self.rom_size())?; state.serialize_field("characteristics", &self.characteristics())?; state.serialize_field( "bios_vendor_reserved_characteristics", &self.bios_vendor_reserved_characteristics(), )?; state.serialize_field( "system_vendor_reserved_characteristics", &self.system_vendor_reserved_characteristics(), )?; state.serialize_field( "characteristics_extension0", &self.characteristics_extension0(), )?; state.serialize_field( "characteristics_extension1", &self.characteristics_extension1(), )?; state.serialize_field( "system_bios_major_release", &self.system_bios_major_release(), )?; state.serialize_field( "system_bios_minor_release", &self.system_bios_minor_release(), )?; state.serialize_field( "e_c_firmware_major_release", &self.e_c_firmware_major_release(), )?; state.serialize_field( "e_c_firmware_minor_release", &self.e_c_firmware_minor_release(), )?; state.serialize_field("extended_rom_size", &self.extended_rom_size())?; state.end() } } /// # BIOS Characteristics #[derive(PartialEq, Eq)] pub struct BiosCharacteristics { /// Raw value pub raw: u32, } impl Deref for BiosCharacteristics { type Target = u32; fn deref(&self) -> &Self::Target { &self.raw } } impl From for BiosCharacteristics { fn from(raw: u32) -> Self { BiosCharacteristics { raw } } } impl BiosCharacteristics { /// Unknown. pub fn unknown(&self) -> bool { self.raw & 0x00000004 == 0x00000004 } /// BIOS Characteristics are not supported. pub fn bios_characteristics_not_supported(&self) -> bool { self.raw & 0x00000008 == 0x00000008 } /// ISA is supported. pub fn isa_supported(&self) -> bool { self.raw & 0x00000010 == 0x00000010 } /// MCA is supported. pub fn mca_supported(&self) -> bool { self.raw & 0x00000020 == 0x00000020 } /// EISA is supported. pub fn eisa_supported(&self) -> bool { self.raw & 0x00000040 == 0x00000040 } /// PCI is supported. pub fn pci_supported(&self) -> bool { self.raw & 0x00000080 == 0x00000080 } /// PC card (PCMCIA) is supported. pub fn pcmcia_supported(&self) -> bool { self.raw & 0x00000100 == 0x00000100 } /// Plug and Play is supported. pub fn plug_and_play_supported(&self) -> bool { self.raw & 0x00000200 == 0x00000200 } /// APM is supported. pub fn apm_supported(&self) -> bool { self.raw & 0x00000400 == 0x00000400 } /// BIOS is upgradeable (Flash). pub fn bios_upgradeable(&self) -> bool { self.raw & 0x00000800 == 0x00000800 } /// BIOS shadowing is allowed. pub fn bios_shadowing_allowed(&self) -> bool { self.raw & 0x00001000 == 0x00001000 } /// VL-VESA is supported. pub fn vlvesa_supported(&self) -> bool { self.raw & 0x00002000 == 0x00002000 } /// ESCD support is available. pub fn escd_support_available(&self) -> bool { self.raw & 0x00004000 == 0x00004000 } /// Boot from CD is supported. pub fn boot_from_cdsupported(&self) -> bool { self.raw & 0x00008000 == 0x00008000 } /// Selectable boot is supported. pub fn selectable_boot_supported(&self) -> bool { self.raw & 0x00010000 == 0x00010000 } /// BIOS ROM is socketed (e.g. PLCC or SOP socket). pub fn bios_rom_socketed(&self) -> bool { self.raw & 0x00020000 == 0x00020000 } /// Boot from PC card (PCMCIA) is supported. pub fn boot_from_pcmcia_supported(&self) -> bool { self.raw & 0x00040000 == 0x00040000 } /// EDD specification is supported. pub fn edd_specification_supported(&self) -> bool { self.raw & 0x00080000 == 0x00080000 } /// Int 13h — Japanese floppy for NEC 9800 1.2 MB (3.5”, 1K bytes/sector, 360 RPM) is supported. pub fn floppy_nec_japanese_supported(&self) -> bool { self.raw & 0x00100000 == 0x00100000 } /// Int 13h — Japanese floppy for Toshiba 1.2 MB (3.5”, 360 RPM) is supported. pub fn floppy_toshiba_japanese_supported(&self) -> bool { self.raw & 0x00200000 == 0x00200000 } /// Int 13h — 5.25” / 360 KB floppy services are supported. pub fn floppy_525_360_supported(&self) -> bool { self.raw & 0x00400000 == 0x00400000 } /// Int 13h — 5.25” /1.2 MB floppy services are supported. pub fn floppy_525_12_supported(&self) -> bool { self.raw & 0x00800000 == 0x00800000 } /// Int 13h — 3.5” / 720 KB floppy services are supported. pub fn floppy_35_720_supported(&self) -> bool { self.raw & 0x01000000 == 0x01000000 } /// Int 13h — 3.5” / 2.88 MB floppy services are supported. pub fn floppy_35_288_supported(&self) -> bool { self.raw & 0x02000000 == 0x02000000 } /// Int 5h, print screen Service is supported. pub fn print_screen_service_supported(&self) -> bool { self.raw & 0x04000000 == 0x04000000 } /// Int 9h, 8042 keyboard services are supported. pub fn keyboard_8042services_supported(&self) -> bool { self.raw & 0x08000000 == 0x08000000 } /// Int 14h, serial services are supported. pub fn serial_services_supported(&self) -> bool { self.raw & 0x10000000 == 0x10000000 } /// Int 17h, printer services are supported. pub fn printer_services_supported(&self) -> bool { self.raw & 0x20000000 == 0x20000000 } /// Int 10h, CGA/Mono Video Services are supported. pub fn cga_mono_video_services_supported(&self) -> bool { self.raw & 0x40000000 == 0x40000000 } /// NEC PC-98. pub fn nec_pc_98supported(&self) -> bool { self.raw & 0x80000000 == 0x80000000 } } impl fmt::Debug for BiosCharacteristics { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("unknown", &self.unknown()) .field( "bios_characteristics_not_supported", &self.bios_characteristics_not_supported(), ) .field("isa_supported", &self.isa_supported()) .field("mca_supported", &self.mca_supported()) .field("eisa_supported", &self.eisa_supported()) .field("pci_supported", &self.pci_supported()) .field("pcmcia_supported", &self.pcmcia_supported()) .field("plug_and_play_supported", &self.plug_and_play_supported()) .field("apm_supported", &self.apm_supported()) .field("bios_upgradeable", &self.bios_upgradeable()) .field("bios_shadowing_allowed", &self.bios_shadowing_allowed()) .field("vlvesa_supported", &self.vlvesa_supported()) .field("escd_support_available", &self.escd_support_available()) .field("boot_from_cdsupported", &self.boot_from_cdsupported()) .field( "selectable_boot_supported", &self.selectable_boot_supported(), ) .field("bios_rom_socketed", &self.bios_rom_socketed()) .field( "boot_from_pcmcia_supported", &self.boot_from_pcmcia_supported(), ) .field( "edd_specification_supported", &self.edd_specification_supported(), ) .field( "floppy_nec_japanese_supported", &self.floppy_nec_japanese_supported(), ) .field( "floppy_toshiba_japanese_supported", &self.floppy_toshiba_japanese_supported(), ) .field("floppy_525_360_supported", &self.floppy_525_360_supported()) .field("floppy_525_12_supported", &self.floppy_525_12_supported()) .field("floppy_35_720_supported", &self.floppy_35_720_supported()) .field("floppy_35_288_supported", &self.floppy_35_288_supported()) .field( "print_screen_service_supported", &self.print_screen_service_supported(), ) .field( "keyboard_8042services_supported", &self.keyboard_8042services_supported(), ) .field( "serial_services_supported", &self.serial_services_supported(), ) .field( "printer_services_supported", &self.printer_services_supported(), ) .field( "cga_mono_video_services_supported", &self.cga_mono_video_services_supported(), ) .field("nec_pc_98supported", &self.nec_pc_98supported()) .finish() } } impl Serialize for BiosCharacteristics { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("BiosCharacteristics", 31)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("unknown", &self.unknown())?; state.serialize_field( "bios_characteristics_not_supported", &self.bios_characteristics_not_supported(), )?; state.serialize_field("isa_supported", &self.isa_supported())?; state.serialize_field("mca_supported", &self.mca_supported())?; state.serialize_field("eisa_supported", &self.eisa_supported())?; state.serialize_field("pci_supported", &self.pci_supported())?; state.serialize_field("pcmcia_supported", &self.pcmcia_supported())?; state.serialize_field("plug_and_play_supported", &self.plug_and_play_supported())?; state.serialize_field("apm_supported", &self.apm_supported())?; state.serialize_field("bios_upgradeable", &self.bios_upgradeable())?; state.serialize_field("bios_shadowing_allowed", &self.bios_shadowing_allowed())?; state.serialize_field("vlvesa_supported", &self.vlvesa_supported())?; state.serialize_field("escd_support_available", &self.escd_support_available())?; state.serialize_field("boot_from_cdsupported", &self.boot_from_cdsupported())?; state.serialize_field( "selectable_boot_supported", &self.selectable_boot_supported(), )?; state.serialize_field("bios_rom_socketed", &self.bios_rom_socketed())?; state.serialize_field( "boot_from_pcmcia_supported", &self.boot_from_pcmcia_supported(), )?; state.serialize_field( "edd_specification_supported", &self.edd_specification_supported(), )?; state.serialize_field( "floppy_nec_japanese_supported", &self.floppy_nec_japanese_supported(), )?; state.serialize_field( "floppy_toshiba_japanese_supported", &self.floppy_toshiba_japanese_supported(), )?; state.serialize_field("floppy_525_360_supported", &self.floppy_525_360_supported())?; state.serialize_field("floppy_525_12_supported", &self.floppy_525_12_supported())?; state.serialize_field("floppy_35_720_supported", &self.floppy_35_720_supported())?; state.serialize_field("floppy_35_288_supported", &self.floppy_35_288_supported())?; state.serialize_field( "print_screen_service_supported", &self.print_screen_service_supported(), )?; state.serialize_field( "keyboard_8042services_supported", &self.keyboard_8042services_supported(), )?; state.serialize_field( "serial_services_supported", &self.serial_services_supported(), )?; state.serialize_field( "printer_services_supported", &self.printer_services_supported(), )?; state.serialize_field( "cga_mono_video_services_supported", &self.cga_mono_video_services_supported(), )?; state.serialize_field("nec_pc_98supported", &self.nec_pc_98supported())?; state.end() } } /// # BIOS Characteristics Extension Byte 0 #[derive(PartialEq, Eq)] pub struct BiosCharacteristicsExtension0 { /// Raw value pub raw: u8, } impl Deref for BiosCharacteristicsExtension0 { type Target = u8; fn deref(&self) -> &Self::Target { &self.raw } } impl From for BiosCharacteristicsExtension0 { fn from(raw: u8) -> Self { BiosCharacteristicsExtension0 { raw } } } impl BiosCharacteristicsExtension0 { /// ACPI is supported. pub fn acpi_is_supported(&self) -> bool { self.raw & 0b0000_0001 == 0b0000_0001 } /// USB Legacy is supported. pub fn usb_legacy_is_supported(&self) -> bool { self.raw & 0b0000_0010 == 0b0000_0010 } /// AGP is supported. pub fn agp_is_supported(&self) -> bool { self.raw & 0b0000_0100 == 0b0000_0100 } /// I2O boot is supported. pub fn i2oboot_is_supported(&self) -> bool { self.raw & 0b0000_1000 == 0b0000_1000 } /// LS-120 SuperDisk boot is supported. pub fn ls120super_disk_boot_is_supported(&self) -> bool { self.raw & 0b0001_0000 == 0b0001_0000 } /// ATAPI ZIP drive boot is supported. pub fn atapi_zip_drive_boot_is_supported(&self) -> bool { self.raw & 0b0010_0000 == 0b0010_0000 } /// 1394 boot is supported. pub fn boot_1394is_supported(&self) -> bool { self.raw & 0b0100_0000 == 0b0100_0000 } /// Smart battery is supported. pub fn smart_battery_is_supported(&self) -> bool { self.raw & 0b1000_0000 == 0b1000_0000 } } impl fmt::Debug for BiosCharacteristicsExtension0 { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("acpi_is_supported", &self.acpi_is_supported()) .field("usb_legacy_is_supported", &self.usb_legacy_is_supported()) .field("agp_is_supported", &self.agp_is_supported()) .field("i2oboot_is_supported", &self.i2oboot_is_supported()) .field( "ls120super_disk_boot_is_supported", &self.ls120super_disk_boot_is_supported(), ) .field( "atapi_zip_drive_boot_is_supported", &self.atapi_zip_drive_boot_is_supported(), ) .field("boot_1394is_supported", &self.boot_1394is_supported()) .field( "smart_battery_is_supported", &self.smart_battery_is_supported(), ) .finish() } } impl Serialize for BiosCharacteristicsExtension0 { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("BiosCharacteristicsExtension0", 9)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("acpi_is_supported", &self.acpi_is_supported())?; state.serialize_field("usb_legacy_is_supported", &self.usb_legacy_is_supported())?; state.serialize_field("agp_is_supported", &self.agp_is_supported())?; state.serialize_field("i2oboot_is_supported", &self.i2oboot_is_supported())?; state.serialize_field( "ls120super_disk_boot_is_supported", &self.ls120super_disk_boot_is_supported(), )?; state.serialize_field( "atapi_zip_drive_boot_is_supported", &self.atapi_zip_drive_boot_is_supported(), )?; state.serialize_field("boot_1394is_supported", &self.boot_1394is_supported())?; state.serialize_field( "smart_battery_is_supported", &self.smart_battery_is_supported(), )?; state.end() } } /// # BIOS Characteristics Extension Byte 1 #[derive(PartialEq, Eq)] pub struct BiosCharacteristicsExtension1 { /// Raw value pub raw: u8, } impl Deref for BiosCharacteristicsExtension1 { type Target = u8; fn deref(&self) -> &Self::Target { &self.raw } } impl From for BiosCharacteristicsExtension1 { fn from(raw: u8) -> Self { BiosCharacteristicsExtension1 { raw } } } impl BiosCharacteristicsExtension1 { /// BIOS Boot Specification is supported. /// /// Available version 2.3.0 and later. pub fn bios_boot_specification_is_supported(&self) -> bool { self.raw & 0b0000_0001 == 0b0000_0001 } /// Function key-initiated network service boot is supported. When function key-uninitiated /// network service boot is not supported, a network adapter option ROM may choose to offer /// this functionality on its own, thus offering this capability to legacy systems. When the /// function is supported, the network adapter option ROM shall not offer this capability. /// /// Available version 2.3.1 and later. pub fn fkey_initiated_network_boot_is_supported(&self) -> bool { self.raw & 0b0000_0010 == 0b0000_0010 } /// Enable targeted content distribution. The manufacturer has ensured that the SMBIOS data /// is useful in identifying the computer for targeted delivery of model-specific software and /// firmware content through third-party content distribution services. /// /// Available version 2.4 and later. pub fn targeted_content_distribution_is_supported(&self) -> bool { self.raw & 0b0000_0100 == 0b0000_0100 } /// UEFI Specification is supported. /// /// Available version 2.7 and later. pub fn uefi_specification_is_supported(&self) -> bool { self.raw & 0b0000_1000 == 0b0000_1000 } /// SMBIOS table describes a virtual machine. (If this bit is not set, no inference can be made /// about the virtuality of the system.) /// /// Available version 2.7 and later. pub fn smbios_table_describes_avirtual_machine(&self) -> bool { self.raw & 0b0001_0000 == 0b0001_0000 } /// Manufacturing mode is supported. (Manufacturing mode is a special boot mode, not normally /// available to end users, that modifies BIOS features and settings for use while the computer is being /// manufactured and tested.) /// /// Available version 3.5 and later. pub fn manufacturing_mode_is_supported(&self) -> bool { self.raw & 0b0010_0000 == 0b0010_0000 } /// Manufacturing mode is enabled. /// /// Available version 3.5 and later. pub fn manufacturing_mode_is_enabled(&self) -> bool { self.raw & 0b0100_0000 == 0b0100_0000 } } impl fmt::Debug for BiosCharacteristicsExtension1 { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field( "bios_boot_specification_is_supported", &self.bios_boot_specification_is_supported(), ) .field( "fkey_initiated_network_boot_is_supported", &self.fkey_initiated_network_boot_is_supported(), ) .field( "targeted_content_distribution_is_supported", &self.targeted_content_distribution_is_supported(), ) .field( "uefi_specification_is_supported", &self.uefi_specification_is_supported(), ) .field( "smbios_table_describes_avirtual_machine", &self.smbios_table_describes_avirtual_machine(), ) .field( "manufacturing_mode_is_supported", &self.manufacturing_mode_is_supported(), ) .field( "manufacturing_mode_is_enabled", &self.manufacturing_mode_is_enabled(), ) .finish() } } impl Serialize for BiosCharacteristicsExtension1 { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("BiosCharacteristicsExtension1", 6)?; state.serialize_field("raw", &self.raw)?; state.serialize_field( "bios_boot_specification_is_supported", &self.bios_boot_specification_is_supported(), )?; state.serialize_field( "fkey_initiated_network_boot_is_supported", &self.fkey_initiated_network_boot_is_supported(), )?; state.serialize_field( "targeted_content_distribution_is_supported", &self.targeted_content_distribution_is_supported(), )?; state.serialize_field( "uefi_specification_is_supported", &self.uefi_specification_is_supported(), )?; state.serialize_field( "smbios_table_describes_avirtual_machine", &self.smbios_table_describes_avirtual_machine(), )?; state.serialize_field( "manufacturing_mode_is_supported", &self.manufacturing_mode_is_supported(), )?; state.serialize_field( "manufacturing_mode_is_enabled", &self.manufacturing_mode_is_enabled(), )?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { // BIOS Information structure is sensitive to BIOS specification versions // and prone to bugs. Therefore, it is important to test different // structure versions. // // The length field specifies: // 12h + number of BIOS Characteristics // Extension Bytes. If no Extension Bytes are // used the Length is 12h. // // For version 2.1 and 2.2 implementations, the length is 13h // because one extension byte is defined. // // For version 2.3 and later implementations, the // length is at least 14h because two extension // bytes are defined. // // For version 2.4 to 3.0, implementations, the length // is at least 18h because bytes 14-17h are defined. // // For version 3.1 and later implementations, the // length is at least 1Ah because bytes 14-19h // are defined. // 2.4 to 3.0 BIOS Information structure. Does not include _extended_rom_size()_ // field or fields beyond. let struct_type0 = vec![ 0x00, 0x18, 0x00, 0x00, 0x01, 0x02, 0x00, 0xF0, 0x03, 0xFF, 0x80, 0x98, 0x8B, 0x3F, 0x01, 0x00, 0x11, 0x00, 0x03, 0x0D, 0x00, 0x21, 0x11, 0x2D, 0x4C, 0x45, 0x4E, 0x4F, 0x56, 0x4F, 0x00, 0x53, 0x30, 0x33, 0x4B, 0x54, 0x33, 0x33, 0x41, 0x00, 0x30, 0x38, 0x2F, 0x30, 0x36, 0x2F, 0x32, 0x30, 0x31, 0x39, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type0); let test_struct = SMBiosInformation::new(&parts); assert_eq!(test_struct.vendor().to_string(), "LENOVO".to_string()); assert_eq!(test_struct.version().to_string(), "S03KT33A".to_string()); assert_eq!(test_struct.starting_address_segment(), Some(61440)); assert_eq!( test_struct.release_date().to_string(), "08/06/2019".to_string() ); assert_eq!(test_struct.rom_size(), Some(RomSize::SeeExtendedRomSize)); assert_eq!( test_struct.characteristics(), Some(BiosCharacteristics::from(1066113152)) ); assert_eq!(test_struct.bios_vendor_reserved_characteristics(), Some(1)); assert_eq!( test_struct.system_vendor_reserved_characteristics(), Some(17) ); assert_eq!( test_struct.characteristics_extension0(), Some(BiosCharacteristicsExtension0::from(3)) ); assert_eq!( test_struct.characteristics_extension1(), Some(BiosCharacteristicsExtension1::from(13)) ); assert_eq!(test_struct.system_bios_major_release(), Some(0)); assert_eq!(test_struct.system_bios_minor_release(), Some(33)); assert_eq!(test_struct.e_c_firmware_major_release(), Some(17)); assert_eq!(test_struct.e_c_firmware_minor_release(), Some(45)); // 2.4 to 3.0 BIOS Information does not include _extended_rom_size()_ or // fields beyond. assert!(test_struct.extended_rom_size().is_none()); // 3.1 BIOS (includes _extended_rom_size_) let struct_type0 = vec![ 0x00, 0x1A, 0x00, 0x00, 0x01, 0x02, 0x00, 0xF0, 0x03, 0xFF, 0x80, 0x98, 0x8B, 0x3F, 0x01, 0x00, 0x11, 0x00, 0x03, 0x0D, 0x00, 0x21, 0x11, 0x2D, 0x30, 0x40, 0x4C, 0x45, 0x4E, 0x4F, 0x56, 0x4F, 0x00, 0x53, 0x30, 0x33, 0x4B, 0x54, 0x33, 0x33, 0x41, 0x00, 0x30, 0x38, 0x2F, 0x30, 0x36, 0x2F, 0x32, 0x30, 0x31, 0x39, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type0); let test_struct = SMBiosInformation::new(&parts); let extended_rom_size = test_struct.extended_rom_size().unwrap(); assert_eq!(extended_rom_size, RomSize::from(0x4030u16)); match extended_rom_size { RomSize::Gigabytes(size) => assert_eq!(size, 48), _ => panic!("incorrect unit"), } println!("{:?}", test_struct); } #[test] pub fn test_rom_size() { let struct_type0 = vec![ 0x00, 0x18, 0x00, 0x00, 0x01, 0x02, 0x00, 0xF0, 0x03, 0xFE, 0x80, 0x98, 0x8B, 0x3F, 0x01, 0x00, 0x11, 0x00, 0x03, 0x0D, 0x00, 0x21, 0x11, 0x2D, 0x4C, 0x45, 0x4E, 0x4F, 0x56, 0x4F, 0x00, 0x53, 0x30, 0x33, 0x4B, 0x54, 0x33, 0x33, 0x41, 0x00, 0x30, 0x38, 0x2F, 0x30, 0x36, 0x2F, 0x32, 0x30, 0x31, 0x39, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type0); let test_struct = SMBiosInformation::new(&parts); assert_eq!(test_struct.rom_size(), Some(RomSize::Kilobytes(16320))) } } smbios-lib-0.9.2/src/structs/types/bios_language_information.rs000064400000000000000000000157601046102023000231210ustar 00000000000000use crate::{strings::*, SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # BIOS Language Information (Type 13) /// /// The information in this structure defines the installable language attributes of the BIOS. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosBiosLanguageInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosBiosLanguageInformation<'a> { const STRUCT_TYPE: u8 = 13u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosBiosLanguageInformation<'a> { /// Number of languages available /// Each available language has a description /// string. This field contains the number of strings /// that follow the formatted area of the structure. pub fn number_of_installable_languages(&self) -> Option { self.parts.get_field_byte(0x4) } /// Bit field indicating the format of the languages. pub fn flags(&self) -> Option { self.parts .get_field_byte(0x5) .map(|raw| BiosLanguageFlags::from(raw)) } /// The currently installed language. pub fn current_language(&self) -> SMBiosString { self.parts.get_field_string(0x15) } /// Iterable collection of the installable languages. pub fn installable_langauges(&self) -> &SMBiosStringSet { &self.parts.strings } } impl fmt::Debug for SMBiosBiosLanguageInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field( "number_of_installable_languages", &self.number_of_installable_languages(), ) .field("flags", &self.flags()) .field("current_language", &self.current_language()) .field("installable_languages", &self.installable_langauges()) .finish() } } impl Serialize for SMBiosBiosLanguageInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosBiosLanguageInformation", 5)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field( "number_of_installable_languages", &self.number_of_installable_languages(), )?; state.serialize_field("flags", &self.flags())?; state.serialize_field("current_language", &self.current_language())?; state.serialize_field("installable_languages", &self.installable_langauges())?; state.end() } } /// # Language Format #[derive(Serialize, Debug)] pub enum LanguageFormat { /// Language strings use the abbreviated format. /// /// Example: "frCA" Abbreviated, /// Language strings use the long format. /// /// Example: "fr|CA|iso8859-1" Long, } /// # BIOS Language Flags #[derive(PartialEq, Eq)] pub struct BiosLanguageFlags { /// Raw value pub raw: u8, } impl Deref for BiosLanguageFlags { type Target = u8; fn deref(&self) -> &Self::Target { &self.raw } } impl From for BiosLanguageFlags { fn from(raw: u8) -> Self { BiosLanguageFlags { raw } } } impl BiosLanguageFlags { /// If set to 1, the Current Language strings use the abbreviated format. Otherwise, the strings use the long format. pub fn language_format(&self) -> LanguageFormat { if self.raw & 0x01 == 0x01 { LanguageFormat::Abbreviated } else { LanguageFormat::Long } } } impl fmt::Debug for BiosLanguageFlags { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("language_format", &self.language_format()) .finish() } } impl Serialize for BiosLanguageFlags { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("BiosLanguageFlags", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("language_format", &self.language_format())?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_bios_language_information() { let bios_language_information_bytes = vec![ 0x0Du8, 0x16, 0x21, 0x00, // number_of_installable_languages: Some(3), flags: Some(0), current_language: Some("en|US|iso8859-1") 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // "en|US|iso8859-1" 0x65, 0x6E, 0x7C, 0x55, 0x53, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31, 0x00, // "hr|HR|iso8859-2" 0x68, 0x72, 0x7C, 0x48, 0x52, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x32, 0x00, // "ja|JP|unicode" 0x6A, 0x61, 0x7C, 0x4A, 0x50, 0x7C, 0x75, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, 0x00, // end of structure 0x00, ]; let parts = UndefinedStruct::new(&bios_language_information_bytes); let bios_language_information = SMBiosBiosLanguageInformation::new(&parts); // header tests assert_eq!(*bios_language_information.parts().header.handle(), 0x0021); assert_eq!(bios_language_information.parts().header.length(), 0x16); // basic field tests assert_eq!( bios_language_information.current_language().to_string(), "en|US|iso8859-1".to_string() ); assert_eq!( bios_language_information .number_of_installable_languages() .expect("number_of_installable_languages field exists"), 3 ); assert_eq!( bios_language_information.flags().unwrap(), BiosLanguageFlags::from(0) ); // installable_languages tests let mut string_iterator = bios_language_information .installable_langauges() .into_iter(); let first_string = string_iterator.next().expect("has a first string").ok(); assert_eq!(first_string, Some("en|US|iso8859-1".to_string())); let second_string = string_iterator.next().expect("has a second string").ok(); assert_eq!(second_string, Some("hr|HR|iso8859-2".to_string())); let third_string = string_iterator.next().expect("has a third string").ok(); assert_eq!(third_string, Some("ja|JP|unicode".to_string())); assert!(string_iterator.next().is_none()); // debug print test println!("bios_language_information: {:?}", bios_language_information); } } smbios-lib-0.9.2/src/structs/types/bis_entry_point.rs000064400000000000000000000103511046102023000211130ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; // The BIS (Boot Integrity Services) Entry Point structure is not defined in the SMBIOS DMTF document. // bisapi037.pdf, section 3.1.3 // typedef struct _BIS_ENTRY_POINT // { // UINT8 smBiosType; // UINT8 length; // UINT16 structHandle; // UINT8 structChecksum; // UINT8 reserved1; // UINT16 reserved2; // pBisEntry16 bisEntry16; // pBisEntry32 bisEntry32; // UINT64 reserved3; // UINT32 reserved4; // UINT16 doubleNull; // } // BIS_ENTRY_POINT, // *pBIS_ENTRY_POINT; /// # Boot Integrity Services (BIS) (Type 31) /// Structure is reserved for use by the Boot Integrity Services (BIS) /// /// This class is compliant with: /// Boot Integrity Services Application Programming Interface Version 1.0 /// with added corrigenda: bis037 /// Published August 31, 1999 /// /// Note: /// The BIS (Boot Integrity Services) Entry Point structure is not defined in the SMBIOS DMTF document. /// bisapi037.pdf, section 3.1.3 /// typedef struct _BIS_ENTRY_POINT pub struct SMBiosBisEntryPoint<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosBisEntryPoint<'a> { const STRUCT_TYPE: u8 = 31u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosBisEntryPoint<'a> { /// Used to make the 8-bit checksum of this structure equal zero. pub fn checksum(&self) -> Option { self.parts.get_field_byte(0x04) } // fn reserved_1(&self) -> Option { // self.parts.get_field_byte(0x05) // } // fn reserved_2(&self) -> Option { // self.parts.get_field_word(0x06) // } /// BIS entry point pointer for use by 16-bit real-mode callers. This is a segmented pointer(in segment:offset form). /// /// Real Mode: In Real Mode all addresses are composed of Segment:Offset pairs, with /// both Segment and Offset being 16 bits.These combine to form a 20-bit physical address /// that cannot access above approximately the 1 Megabyte boundary.This mode is /// referred to in this section as “16-bit real-mode” or “16-bit mode”. Callers in this mode /// may only invoke BIS through the bisEntry16 entry point. The bisEntry16 function /// returns with the processor in 16-bit real-mode. pub fn bis_entry_16(&self) -> Option { self.parts.get_field_dword(0x08) } /// BIS entry point pointer for use by 32-bit flat physical address mode callers. This is a 32-bit physical address. /// /// Flat Mode: A 32-bit (protected) IA-32 processor mode where CS:0, DS:0, and SS:0 all /// refer to physical location 0 and all have 4 GB of address space.This mode is referred to /// in this section as “32-bit flat-mode” or “32-bit mode”. Callers in this mode may only /// invoke BIS through the bisEntry32 entry point. The bisEntry32 function returns with the /// processor in 32-bit flat-mode. pub fn bis_entry_32(&self) -> Option { self.parts.get_field_dword(0x0C) } // fn reserved_3(&self) -> Option { // self.parts.get_field_qword(0x10) // } // fn reserved_4(&self) -> Option { // self.parts.get_field_dword(0x18) // } } impl fmt::Debug for SMBiosBisEntryPoint<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("checksum", &self.checksum()) .field("bis_entry_16", &self.bis_entry_16()) .field("bis_entry_32", &self.bis_entry_32()) .finish() } } impl Serialize for SMBiosBisEntryPoint<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosBisEntryPoint", 4)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("checksum", &self.checksum())?; state.serialize_field("bis_entry_16", &self.bis_entry_16())?; state.serialize_field("bis_entry_32", &self.bis_entry_32())?; state.end() } } smbios-lib-0.9.2/src/structs/types/built_in_pointing_device.rs000064400000000000000000000212421046102023000227400ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # Built-in Pointing Device (Type 21) /// /// This structure describes the attributes of the built-in pointing device for the system. /// Details are provided in Table 87. /// The presence of this structure does not imply that the built-in pointing device is active /// for the system’s use. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.5.0 (DSP0134) /// Document Date: 2021-09-15 pub struct SMBiosBuiltInPointingDevice<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosBuiltInPointingDevice<'a> { const STRUCT_TYPE: u8 = 21u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosBuiltInPointingDevice<'a> { /// Type of pointing device. pub fn device_type(&self) -> Option { self.parts .get_field_byte(0x04) .map(|raw| PointingDeviceTypeData::from(raw)) } /// Interface type for the pointing device. pub fn interface(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| PointingDeviceInterfaceData::from(raw)) } /// Number of buttons on the pointing device. /// If the device has 3 buttons, the field value is 3. pub fn number_of_buttons(&self) -> Option { self.parts.get_field_byte(0x06) } } impl fmt::Debug for SMBiosBuiltInPointingDevice<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("device_type", &self.device_type()) .field("interface", &self.interface()) .field("number_of_buttons", &self.number_of_buttons()) .finish() } } impl Serialize for SMBiosBuiltInPointingDevice<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosBuiltInPointingDevice", 4)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("device_type", &self.device_type())?; state.serialize_field("interface", &self.interface())?; state.serialize_field("number_of_buttons", &self.number_of_buttons())?; state.end() } } /// # Built-in Pointing Device Type Data pub struct PointingDeviceTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [PointingDeviceType] value pub value: PointingDeviceType, } impl fmt::Debug for PointingDeviceTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for PointingDeviceTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("PointingDeviceTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for PointingDeviceTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { PointingDeviceType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for PointingDeviceTypeData { type Target = PointingDeviceType; fn deref(&self) -> &Self::Target { &self.value } } /// # Built-in Pointing Device Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum PointingDeviceType { /// Other Other, /// Unknown Unknown, /// Mouse Mouse, /// Track Ball TrackBall, /// Track Point TrackPoint, /// Glide Point GlidePoint, /// Touch Pad TouchPad, /// Touch Screen TouchScreen, /// Optical Sensor OpticalSensor, /// A value unknown to this standard, check the raw value None, } impl From for PointingDeviceTypeData { fn from(raw: u8) -> Self { PointingDeviceTypeData { value: match raw { 0x01 => PointingDeviceType::Other, 0x02 => PointingDeviceType::Unknown, 0x03 => PointingDeviceType::Mouse, 0x04 => PointingDeviceType::TrackBall, 0x05 => PointingDeviceType::TrackPoint, 0x06 => PointingDeviceType::GlidePoint, 0x07 => PointingDeviceType::TouchPad, 0x08 => PointingDeviceType::TouchScreen, 0x09 => PointingDeviceType::OpticalSensor, _ => PointingDeviceType::None, }, raw, } } } /// # Built-in Pointing Device Interface Data pub struct PointingDeviceInterfaceData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [PointingDeviceInterface] value pub value: PointingDeviceInterface, } impl fmt::Debug for PointingDeviceInterfaceData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for PointingDeviceInterfaceData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("PointingDeviceInterfaceData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for PointingDeviceInterfaceData { type Target = PointingDeviceInterface; fn deref(&self) -> &Self::Target { &self.value } } /// # Built-in Pointing Device Interface #[derive(Serialize, Debug, PartialEq, Eq)] pub enum PointingDeviceInterface { /// Other field Other, /// Unknown Unknown, /// Serial Serial, /// PS/2 PS2, /// Infrared Infrared, /// HP-HIL HpHil, /// Bus mouse BusMouse, /// ADB (Apple Desktop Bus) Adb, /// Bus mouse DB-9 BusMouseDB9, /// Bus mouse micro-DIN BusMouseMicroDin, /// USB USB, /// I2C /// /// Available in version 3.5.0 and later. I2C, /// SPI /// /// Available in version 3.5.0 and later. SPI, /// A value unknown to this standard, check the raw value None, } impl From for PointingDeviceInterfaceData { fn from(raw: u8) -> Self { PointingDeviceInterfaceData { value: match raw { 0x01 => PointingDeviceInterface::Other, 0x02 => PointingDeviceInterface::Unknown, 0x03 => PointingDeviceInterface::Serial, 0x04 => PointingDeviceInterface::PS2, 0x05 => PointingDeviceInterface::Infrared, 0x06 => PointingDeviceInterface::HpHil, 0x07 => PointingDeviceInterface::BusMouse, 0x08 => PointingDeviceInterface::Adb, 0xA0 => PointingDeviceInterface::BusMouseDB9, 0xA1 => PointingDeviceInterface::BusMouseMicroDin, 0xA2 => PointingDeviceInterface::USB, 0xA3 => PointingDeviceInterface::I2C, 0xA4 => PointingDeviceInterface::SPI, _ => PointingDeviceInterface::None, }, raw, } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type21 = vec![0x15, 0x07, 0x31, 0x00, 0x05, 0x04, 0x03, 0x00, 0x00]; let parts = UndefinedStruct::new(&struct_type21); let test_struct = SMBiosBuiltInPointingDevice::new(&parts); assert_eq!( *test_struct.device_type().unwrap(), PointingDeviceType::TrackPoint ); assert_eq!( *test_struct.interface().unwrap(), PointingDeviceInterface::PS2 ); assert_eq!(test_struct.number_of_buttons(), Some(3)); } } smbios-lib-0.9.2/src/structs/types/cache_information.rs000064400000000000000000000553671046102023000213740ustar 00000000000000use crate::core::{strings::*, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # Cache Information (Type 7) /// /// This structure defines the attributes of CPU cache device in the /// system. One structure is specified for each such device, whether the device is internal to or external to /// the CPU module. Cache modules can be associated with a processor structure in one or two ways /// depending on the SMBIOS version /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosCacheInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosCacheInformation<'a> { const STRUCT_TYPE: u8 = 7u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosCacheInformation<'a> { /// String number for reference designation pub fn socket_designation(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Bit fields describing the cache configuration pub fn cache_configuration(&self) -> Option { self.parts .get_field_word(0x05) .map(|raw| CacheConfiguaration::from(raw)) } /// Maximum size that can be installed pub fn maximum_cache_size(&self) -> Option { self.parts .get_field_word(0x07) .map(|raw| CacheMemorySize::from(raw)) } /// Same format as Max Cache Size field; set to 0 if no cache is installed pub fn installed_size(&self) -> Option { self.parts .get_field_word(0x09) .map(|raw| CacheMemorySize::from(raw)) } /// Supported SRAM type pub fn supported_sram_type(&self) -> Option { self.parts .get_field_word(0x0B) .map(|raw| SramTypes::from(raw)) } /// Current SRAM type pub fn current_sram_type(&self) -> Option { self.parts .get_field_word(0x0D) .map(|raw| SramTypes::from(raw)) } /// Cache module speed, in nanoseconds. /// The value is 0 if the speed is unknown. pub fn cache_speed(&self) -> Option { self.parts.get_field_byte(0x0F) } /// Error-correction scheme supported by this cache component pub fn error_correction_type(&self) -> Option { self.parts .get_field_byte(0x10) .map(|raw| ErrorCorrectionTypeData::from(raw)) } /// Logical type of cache pub fn system_cache_type(&self) -> Option { self.parts .get_field_byte(0x11) .map(|raw| SystemCacheTypeData::from(raw)) } /// Associativity of the cache pub fn associativity(&self) -> Option { self.parts .get_field_byte(0x12) .map(|raw| CacheAssociativityData::from(raw)) } /// Maximum cache size pub fn maximum_cache_size_2(&self) -> Option { self.parts .get_field_dword(0x13) .map(|raw| CacheMemorySize::from(raw)) } /// Installed cache size pub fn installed_cache_size_2(&self) -> Option { self.parts .get_field_dword(0x17) .map(|raw| CacheMemorySize::from(raw)) } } impl fmt::Debug for SMBiosCacheInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("socket_designation", &self.socket_designation()) .field("cache_configuration", &self.cache_configuration()) .field("maximum_cache_size", &self.maximum_cache_size()) .field("installed_size", &self.installed_size()) .field("supported_sram_type", &self.supported_sram_type()) .field("current_sram_type", &self.current_sram_type()) .field("cache_speed", &self.cache_speed()) .field("error_correction_type", &self.error_correction_type()) .field("system_cache_type", &self.system_cache_type()) .field("associativity", &self.associativity()) .field("maximum_cache_size_2", &self.maximum_cache_size_2()) .field("installed_cache_size_2", &self.installed_cache_size_2()) .finish() } } impl Serialize for SMBiosCacheInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosCacheInformation", 13)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("socket_designation", &self.socket_designation())?; state.serialize_field("cache_configuration", &self.cache_configuration())?; state.serialize_field("maximum_cache_size", &self.maximum_cache_size())?; state.serialize_field("installed_size", &self.installed_size())?; state.serialize_field("supported_sram_type", &self.supported_sram_type())?; state.serialize_field("current_sram_type", &self.current_sram_type())?; state.serialize_field("cache_speed", &self.cache_speed())?; state.serialize_field("error_correction_type", &self.error_correction_type())?; state.serialize_field("system_cache_type", &self.system_cache_type())?; state.serialize_field("associativity", &self.associativity())?; state.serialize_field("maximum_cache_size_2", &self.maximum_cache_size_2())?; state.serialize_field("installed_cache_size_2", &self.installed_cache_size_2())?; state.end() } } /// # Maximum memory capacity, in kilobytes, for this cache item #[derive(Serialize, Debug, PartialEq, Eq)] pub enum CacheMemorySize { /// Maximum memory capacity in Kilobytes Kilobytes(u64), /// Use `maximum_cache_size_2` to retrieve the maximum capacity or `installed_cache_size_2` to retrieve the installed size. SeeCacheSize2, } impl From for CacheMemorySize { fn from(raw: u16) -> Self { match raw { 0xFFFF => CacheMemorySize::SeeCacheSize2, // When bit 15 is set, the size units of the remaining bits are 64k _ if raw & 0x8000 == 0x8000 => CacheMemorySize::Kilobytes((raw & 0x7FFF) as u64 * 64), _ => CacheMemorySize::Kilobytes(raw as u64), } } } impl From for CacheMemorySize { fn from(raw: u32) -> Self { match raw { // When bit 31 is set, the size units of the remaining bits are 64k _ if raw & 0x80000000 == 0x80000000 => { CacheMemorySize::Kilobytes((raw & 0x7FFFFFFF) as u64 * 64) } _ => CacheMemorySize::Kilobytes(raw as u64), } } } /// # Cache Associativity Data pub struct CacheAssociativityData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [CacheAssociativity] value pub value: CacheAssociativity, } impl fmt::Debug for CacheAssociativityData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for CacheAssociativityData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("CacheAssociativityData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for CacheAssociativityData { type Target = CacheAssociativity; fn deref(&self) -> &Self::Target { &self.value } } /// # Cache Associativity #[derive(Serialize, Debug, PartialEq, Eq)] pub enum CacheAssociativity { /// Other Other = 0x01, /// Unknown Unknown = 0x02, /// Direct Mapped DirectMapped = 0x03, /// 2-way Set-Associative SetAssociative2Way = 0x04, /// 4-way Set-Associative SetAssociative4Way = 0x05, /// Fully Associative FullyAssociative = 0x06, /// 8-way Set-Associative SetAssociative8Way = 0x07, /// 16-way Set-Associative SetAssociative16Way = 0x08, /// 12-way Set-Associative SetAssociative12Way = 0x09, /// 24-way Set-Associative SetAssociative24Way = 0x0A, /// 32-way Set-Associative SetAssociative32Way = 0x0B, /// 48-way Set-Associative SetAssociative48Way = 0x0C, /// 64-way Set-Associative SetAssociative64Way = 0x0D, /// 20-way Set-Associative SetAssociative20Way = 0x0E, /// A value unknown to this standard, check the raw value None, } impl From for CacheAssociativityData { fn from(raw: u8) -> Self { CacheAssociativityData { value: match raw { 0x01 => CacheAssociativity::Other, 0x02 => CacheAssociativity::Unknown, 0x03 => CacheAssociativity::DirectMapped, 0x04 => CacheAssociativity::SetAssociative2Way, 0x05 => CacheAssociativity::SetAssociative4Way, 0x06 => CacheAssociativity::FullyAssociative, 0x07 => CacheAssociativity::SetAssociative8Way, 0x08 => CacheAssociativity::SetAssociative16Way, 0x09 => CacheAssociativity::SetAssociative12Way, 0x0A => CacheAssociativity::SetAssociative24Way, 0x0B => CacheAssociativity::SetAssociative32Way, 0x0C => CacheAssociativity::SetAssociative48Way, 0x0D => CacheAssociativity::SetAssociative64Way, 0x0E => CacheAssociativity::SetAssociative20Way, _ => CacheAssociativity::None, }, raw, } } } /// # System Cache Type Data pub struct SystemCacheTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [SystemCacheType] value pub value: SystemCacheType, } impl fmt::Debug for SystemCacheTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for SystemCacheTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SystemCacheTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for SystemCacheTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { SystemCacheType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for SystemCacheTypeData { type Target = SystemCacheType; fn deref(&self) -> &Self::Target { &self.value } } /// # System Cache Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum SystemCacheType { /// Other Other, /// Unknown Unknown, /// Instruction Instruction, /// Data Data, /// Unified Unified, /// A value unknown to this standard, check the raw value None, } impl From for SystemCacheTypeData { fn from(raw: u8) -> Self { SystemCacheTypeData { value: match raw { 0x01 => SystemCacheType::Other, 0x02 => SystemCacheType::Unknown, 0x03 => SystemCacheType::Instruction, 0x04 => SystemCacheType::Data, 0x05 => SystemCacheType::Unified, _ => SystemCacheType::None, }, raw, } } } /// # System Cache Error Correction Type Data pub struct ErrorCorrectionTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [ErrorCorrectionType] value pub value: ErrorCorrectionType, } impl fmt::Debug for ErrorCorrectionTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for ErrorCorrectionTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ErrorCorrectionTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for ErrorCorrectionTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { ErrorCorrectionType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for ErrorCorrectionTypeData { type Target = ErrorCorrectionType; fn deref(&self) -> &Self::Target { &self.value } } /// # System Cache Error Correction Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum ErrorCorrectionType { /// Other Other = 0x01, /// Unknown Unknown = 0x02, /// None (No Correction) NoCorrection = 0x03, /// Parity Parity = 0x04, /// Single-bit ECC SingleBitEcc = 0x05, /// Multi-bit ECC MultiBitEcc = 0x06, /// A value unknown to this standard, check the raw value None, } impl From for ErrorCorrectionTypeData { fn from(raw: u8) -> Self { ErrorCorrectionTypeData { value: match raw { 0x01 => ErrorCorrectionType::Other, 0x02 => ErrorCorrectionType::Unknown, 0x03 => ErrorCorrectionType::NoCorrection, 0x04 => ErrorCorrectionType::Parity, 0x05 => ErrorCorrectionType::SingleBitEcc, 0x06 => ErrorCorrectionType::MultiBitEcc, _ => ErrorCorrectionType::None, }, raw, } } } /// # System Cache SRAM Types #[derive(PartialEq, Eq)] pub struct SramTypes { /// Raw value pub raw: u16, } impl Deref for SramTypes { type Target = u16; fn deref(&self) -> &Self::Target { &self.raw } } impl From for SramTypes { fn from(raw: u16) -> Self { SramTypes { raw } } } impl SramTypes { /// Other pub fn other(&self) -> bool { self.raw & 0x0001 == 0x0001 } /// Unknown pub fn unknown(&self) -> bool { self.raw & 0x0002 == 0x0002 } /// Non-Burst pub fn non_burst(&self) -> bool { self.raw & 0x0004 == 0x0004 } /// Burst pub fn burst(&self) -> bool { self.raw & 0x0008 == 0x0008 } /// Pipeline Burst pub fn pipeline_burst(&self) -> bool { self.raw & 0x0010 == 0x0010 } /// Synchronous pub fn synchronous(&self) -> bool { self.raw & 0x0020 == 0x0020 } /// Asynchronous pub fn asynchronous(&self) -> bool { self.raw & 0x0040 == 0x0040 } } impl fmt::Debug for SramTypes { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("other", &self.other()) .field("unknown", &self.unknown()) .field("non_burst", &self.non_burst()) .field("burst", &self.burst()) .field("pipeline_burst", &self.pipeline_burst()) .field("synchronous", &self.synchronous()) .field("asynchronous", &self.asynchronous()) .finish() } } impl Serialize for SramTypes { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SramTypes", 8)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("other", &self.other())?; state.serialize_field("unknown", &self.unknown())?; state.serialize_field("non_burst", &self.non_burst())?; state.serialize_field("burst", &self.burst())?; state.serialize_field("pipeline_burst", &self.pipeline_burst())?; state.serialize_field("synchronous", &self.synchronous())?; state.serialize_field("asynchronous", &self.asynchronous())?; state.end() } } /// # System Cache Configuration #[derive(PartialEq, Eq)] pub struct CacheConfiguaration { /// Raw value pub raw: u16, } impl Deref for CacheConfiguaration { type Target = u16; fn deref(&self) -> &Self::Target { &self.raw } } impl From for CacheConfiguaration { fn from(raw: u16) -> Self { CacheConfiguaration { raw } } } impl CacheConfiguaration { /// Cache Level (1 through 8) pub fn cache_level(&self) -> u8 { // [bits 0, 1, 2] Cache Level – 1 through 8 // (For example, an L1 cache would use value // 000b and an L3 cache would use 010b. (self.raw & 0x0007) as u8 + 1 } /// Cache Socketed (e.g. Cache on a Stick) /// /// true - socketed /// false - non-socketed pub fn cache_socketed(&self) -> bool { // [bit 3] Cache Socketed // 1b - Socketed // 0b - Not socketed self.raw & 0x0008 == 0x0008 } /// Cache Location (relative to the CPU module) pub fn location(&self) -> CacheLocation { // [bits 5, 6] Location, relative to the CPU module: // 00b - Internal // 01b - External // 10b - Reserved // 11b - Unknown match self.raw & 0x0060 { 0x0000 => CacheLocation::Internal, 0x0020 => CacheLocation::External, 0x0040 => CacheLocation::Reserved, 0x0060 => CacheLocation::Unknown, _ => panic!("Impossible condition"), } } /// Cache Enabled (at boot time) pub fn enabled_at_boot(&self) -> bool { // [bit 7] self.raw & 0x0080 == 0x0080 } /// Cache Operational Mode pub fn operational_mode(&self) -> CacheOperationalMode { // [bits 8, 9] Operational Mode // 00b - Write Through // 01b - Write Back // 10b - Varies with Memory Address // 11b - Unknown match self.raw & 0x0300 { 0x0000 => CacheOperationalMode::WriteThrough, 0x0100 => CacheOperationalMode::WriteBack, 0x0200 => CacheOperationalMode::VariesWithMemoryAddress, 0x0300 => CacheOperationalMode::Unknown, _ => panic!("Impossible condition"), } } } impl fmt::Debug for CacheConfiguaration { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("cache_level", &self.cache_level()) .field("cache_socketed", &self.cache_socketed()) .field("location", &self.location()) .field("enabled_at_boot", &self.enabled_at_boot()) .field("operational_mode", &self.operational_mode()) .finish() } } impl Serialize for CacheConfiguaration { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("CacheConfiguaration", 6)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("cache_level", &self.cache_level())?; state.serialize_field("cache_socketed", &self.cache_socketed())?; state.serialize_field("location", &self.location())?; state.serialize_field("enabled_at_boot", &self.enabled_at_boot())?; state.serialize_field("operational_mode", &self.operational_mode())?; state.end() } } /// # System Cache Location (relative to the CPU module) #[derive(Serialize, Debug, PartialEq, Eq)] pub enum CacheLocation { /// Internal to the CPU Internal, /// External to the CPU External, /// Reserved Reserved, /// Location Unknown Unknown, } /// # System Cache Operational Mode #[derive(Serialize, Debug, PartialEq, Eq)] pub enum CacheOperationalMode { /// Write Through WriteThrough = 0x00, /// Write Back WriteBack = 0x01, /// Varies with Memory Address VariesWithMemoryAddress = 0x02, /// Unknown Operational Mode Unknown = 0x03, } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type7 = vec![ 0x07, 0x1B, 0x03, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x10, 0x00, 0x10, 0x00, 0x01, 0x06, 0x05, 0x07, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x4C, 0x31, 0x20, 0x2D, 0x20, 0x43, 0x61, 0x63, 0x68, 0x65, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type7); let test_struct = SMBiosCacheInformation::new(&parts); let cache_configuration = test_struct.cache_configuration().unwrap(); assert_eq!(cache_configuration.cache_level(), 1); assert!(!cache_configuration.cache_socketed()); assert_eq!(cache_configuration.location(), CacheLocation::Internal); assert!(cache_configuration.enabled_at_boot()); assert_eq!( cache_configuration.operational_mode(), CacheOperationalMode::WriteBack ); let cache_size = test_struct.maximum_cache_size().unwrap(); assert_eq!(cache_size, CacheMemorySize::Kilobytes(384)); println!("{:?}", test_struct); } #[test] fn memory_size_parsing_test() { assert_eq!( CacheMemorySize::from(0x8200u16), CacheMemorySize::Kilobytes(32768) ); assert_eq!( CacheMemorySize::from(0x00000200u32), CacheMemorySize::Kilobytes(512) ); assert_eq!( CacheMemorySize::from(0x80000200u32), CacheMemorySize::Kilobytes(32768) ); assert_eq!( CacheMemorySize::from(0xFFFFFFFFu32), CacheMemorySize::Kilobytes(2u64.pow(37) - 64) ); } } smbios-lib-0.9.2/src/structs/types/cooling_device.rs000064400000000000000000000225621046102023000206640ustar 00000000000000use crate::core::{strings::*, Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Cooling Device (Type 27) /// /// This structure describes the attributes for a cooling device in the system. Each structure describes a single cooling device. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosCoolingDevice<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosCoolingDevice<'a> { const STRUCT_TYPE: u8 = 27u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosCoolingDevice<'a> { /// Handle, or instance number, of the temperature /// probe monitoring this cooling device. /// A value of 0xFFFF indicates that no probe is /// provided. pub fn temperature_probe_handle(&self) -> Option { self.parts.get_field_handle(0x04) } /// Cooling device type and status. pub fn device_type_and_status(&self) -> Option { self.parts .get_field_byte(0x06) .map(|raw| CoolingDeviceTypeAndStatus::from(raw)) } /// Cooling unit group to which this cooling device is associated /// Having multiple cooling devices in the same /// cooling unit implies a redundant configuration. The /// value is 00h if the cooling device is not a member /// of a redundant cooling unit. Non-zero values imply /// redundancy and that at least one other cooling /// device will be enumerated with the same value pub fn cooling_unit_group(&self) -> Option { self.parts.get_field_byte(0x07) } /// OEM or BIOS vendor-specific information. pub fn oem_defined(&self) -> Option { self.parts.get_field_dword(0x08) } /// Nominal value for the cooling device’s rotational /// speed, in revolutions-per-minute (rpm) /// If the value is unknown or the cooling device is /// non-rotating, the field is set to 0x8000. This field is /// present in the structure only if the structure’s /// length is larger than 0Ch pub fn nominal_speed(&self) -> Option { self.parts .get_field_word(0x0C) .map(|raw| RotationalSpeed::from(raw)) } /// Additional descriptive information about the cooling device or its location /// This field is present in the structure only if the /// structure’s length is 0Fh or larger. pub fn description(&self) -> SMBiosString { self.parts.get_field_string(0x0E) } } /// # Rotational Speed #[derive(Serialize, Debug)] pub enum RotationalSpeed { /// Revolutions per minute (RPM) Rpm(u16), /// RPM is unknown Unknown, } impl From for RotationalSpeed { fn from(raw: u16) -> Self { match raw { 0x8000 => RotationalSpeed::Unknown, _ => RotationalSpeed::Rpm(raw), } } } impl fmt::Debug for SMBiosCoolingDevice<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("temperature_probe_handle", &self.temperature_probe_handle()) .field("device_type_and_status", &self.device_type_and_status()) .field("cooling_unit_group", &self.cooling_unit_group()) .field("oem_defined", &self.oem_defined()) .field("nominal_speed", &self.nominal_speed()) .field("description", &self.description()) .finish() } } impl Serialize for SMBiosCoolingDevice<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosCoolingDevice", 7)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("temperature_probe_handle", &self.temperature_probe_handle())?; state.serialize_field("device_type_and_status", &self.device_type_and_status())?; state.serialize_field("cooling_unit_group", &self.cooling_unit_group())?; state.serialize_field("oem_defined", &self.oem_defined())?; state.serialize_field("nominal_speed", &self.nominal_speed())?; state.serialize_field("description", &self.description())?; state.end() } } /// # Cooling Device Type and Status #[derive(PartialEq, Eq)] pub struct CoolingDeviceTypeAndStatus { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The [CoolingDeviceStatus] pub device_status: CoolingDeviceStatus, /// The [CoolingDeviceType] pub device_type: CoolingDeviceType, } impl fmt::Debug for CoolingDeviceTypeAndStatus { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("device_status", &self.device_status) .field("device_type", &self.device_type) .finish() } } impl Serialize for CoolingDeviceTypeAndStatus { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("CoolingDeviceTypeAndStatus", 3)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("device_status", &self.device_status)?; state.serialize_field("device_type", &self.device_type)?; state.end() } } /// # Cooling Device Status #[derive(Serialize, Debug, PartialEq, Eq)] pub enum CoolingDeviceStatus { /// Other Other, /// Unknown Unknown, /// OK OK, /// Non-critical NonCritical, /// Critical Critical, /// Non-recoverable NonRecoverable, /// A value unknown to this standard, check the raw value None, } /// # Cooling Device Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum CoolingDeviceType { /// Other Other, /// Unknown Unknown, /// Fan Fan, /// Centrifugal Blower CentrifugalBlower, /// Chip Fan ChipFan, /// Cabinet Fan CabinetFan, /// Power Supply Fan PowerSupplyFan, /// Heat Pipe HeatPipe, /// Integrated Refrigeration IntegratedRefrigeration, /// Active Cooling ActiveCooling, /// Passive Cooling PassiveCooling, /// A value unknown to this standard, check the raw value None, } impl From for CoolingDeviceTypeAndStatus { fn from(raw: u8) -> Self { CoolingDeviceTypeAndStatus { device_status: match raw & 0b111_00000 { 0b001_00000 => CoolingDeviceStatus::Other, 0b010_00000 => CoolingDeviceStatus::Unknown, 0b011_00000 => CoolingDeviceStatus::OK, 0b100_00000 => CoolingDeviceStatus::NonCritical, 0b101_00000 => CoolingDeviceStatus::Critical, 0b110_00000 => CoolingDeviceStatus::NonRecoverable, _ => CoolingDeviceStatus::None, }, device_type: match raw & 0b000_11111 { 0b000_00001 => CoolingDeviceType::Other, 0b000_00010 => CoolingDeviceType::Unknown, 0b000_00011 => CoolingDeviceType::Fan, 0b000_00100 => CoolingDeviceType::CentrifugalBlower, 0b000_00101 => CoolingDeviceType::ChipFan, 0b000_00110 => CoolingDeviceType::CabinetFan, 0b000_00111 => CoolingDeviceType::PowerSupplyFan, 0b000_01000 => CoolingDeviceType::HeatPipe, 0b000_01001 => CoolingDeviceType::IntegratedRefrigeration, 0b000_10000 => CoolingDeviceType::ActiveCooling, 0b000_10001 => CoolingDeviceType::PassiveCooling, _ => CoolingDeviceType::None, }, raw, } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type27 = vec![ 0x1B, 0x0F, 0x2D, 0x00, 0x2A, 0x00, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x43, 0x6F, 0x6F, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x44, 0x65, 0x76, 0x20, 0x31, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type27); let test_struct = SMBiosCoolingDevice::new(&parts); //assert_eq!(test_struct.temperature_probe_handle(), Some(Handle(42))); let device_type_and_status = test_struct.device_type_and_status().unwrap(); assert_eq!( device_type_and_status.device_status, CoolingDeviceStatus::OK ); assert_eq!( device_type_and_status.device_type, CoolingDeviceType::PowerSupplyFan ); assert_eq!(test_struct.cooling_unit_group(), Some(1)); assert_eq!(test_struct.oem_defined(), Some(0)); match test_struct.nominal_speed().unwrap() { RotationalSpeed::Rpm(_) => panic!("expected unknown"), RotationalSpeed::Unknown => (), } assert_eq!( test_struct.description().to_string(), "Cooling Dev 1".to_string() ); } } smbios-lib-0.9.2/src/structs/types/electrical_current_probe.rs000064400000000000000000000270361046102023000227540ustar 00000000000000use crate::SMBiosStruct; use crate::{strings::*, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Electrical Current Probe (Type 29) /// /// This structure describes the attributes for an electrical current probe in the system. Each structure describes a single electrical current probe. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosElectricalCurrentProbe<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosElectricalCurrentProbe<'a> { const STRUCT_TYPE: u8 = 29u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosElectricalCurrentProbe<'a> { /// A string that contains additional descriptive information about the probe or its location pub fn description(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Probe’s physical location and status of the current monitored by this current probe pub fn location_and_status(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| CurrentProbeLocationAndStatus::from(raw)) } /// Maximum current level readable by this probe, in milliamps pub fn maximum_value(&self) -> Option { self.parts .get_field_word(0x06) .map(|raw| ProbeAmperage::from(raw)) } /// Minimum current level readable by this probe, in milliamps pub fn minimum_value(&self) -> Option { self.parts .get_field_word(0x08) .map(|raw| ProbeAmperage::from(raw)) } /// Resolution for the probe’s reading, in tenths of milliamps pub fn resolution(&self) -> Option { self.parts .get_field_word(0x0A) .map(|raw| CurrentProbeResolution::from(raw)) } /// Tolerance for reading from this probe, in plus/minus milliamps pub fn tolerance(&self) -> Option { self.parts .get_field_word(0x0C) .map(|raw| ProbeAmperage::from(raw)) } /// Accuracy for reading from this probe, in plus/minus 1/100th of a percent pub fn accuracy(&self) -> Option { self.parts .get_field_word(0x0E) .map(|raw| CurrentProbeAccuracy::from(raw)) } /// OEM- or BIOS vendor-specific information. pub fn oem_defined(&self) -> Option { self.parts.get_field_dword(0x10) } /// Nominal value for the probe’s reading in milliamps pub fn nominal_value(&self) -> Option { self.parts .get_field_word(0x14) .map(|raw| ProbeAmperage::from(raw)) } } impl fmt::Debug for SMBiosElectricalCurrentProbe<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("description", &self.description()) .field("location_and_status", &self.location_and_status()) .field("maximum_value", &self.maximum_value()) .field("minimum_value", &self.minimum_value()) .field("resolution", &self.resolution()) .field("tolerance", &self.tolerance()) .field("accuracy", &self.accuracy()) .field("oem_defined", &self.oem_defined()) .field("nominal_value", &self.nominal_value()) .finish() } } impl Serialize for SMBiosElectricalCurrentProbe<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosElectricalCurrentProbe", 10)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("description", &self.description())?; state.serialize_field("location_and_status", &self.location_and_status())?; state.serialize_field("maximum_value", &self.maximum_value())?; state.serialize_field("minimum_value", &self.minimum_value())?; state.serialize_field("resolution", &self.resolution())?; state.serialize_field("tolerance", &self.tolerance())?; state.serialize_field("accuracy", &self.accuracy())?; state.serialize_field("oem_defined", &self.oem_defined())?; state.serialize_field("nominal_value", &self.nominal_value())?; state.end() } } /// # Electrical Current Probe Location and Status #[derive(PartialEq, Eq)] pub struct CurrentProbeLocationAndStatus { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The [CurrentProbeStatus] pub status: CurrentProbeStatus, /// The [CurrentProbeLocation] pub location: CurrentProbeLocation, } impl fmt::Debug for CurrentProbeLocationAndStatus { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("status", &self.status) .field("location", &self.location) .finish() } } impl Serialize for CurrentProbeLocationAndStatus { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("CurrentProbeLocationAndStatus", 3)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("status", &self.status)?; state.serialize_field("location", &self.location)?; state.end() } } /// # Electrical Current Probe Status #[derive(Serialize, Debug, PartialEq, Eq)] pub enum CurrentProbeStatus { /// Other Other, /// Unknown Unknown, /// OK OK, /// Non-critical NonCritical, /// Critical Critical, /// Non-recoverable NonRecoverable, /// A value unknown to this standard, check the raw value None, } /// # Electrical Current Probe Location #[derive(Serialize, Debug, PartialEq, Eq)] pub enum CurrentProbeLocation { /// Other Other, /// Unknown Unknown, /// Processor Processor, /// Disk Disk, /// Peripheral Bay PeripheralBay, /// System Management Module SystemManagementModule, /// Motherboard Motherboard, /// Memory Module MemoryModule, /// Processor Module ProcessorModule, /// Power Unit PowerUnit, /// Add-in Card AddInCard, /// A value unknown to this standard, check the raw value None, } impl From for CurrentProbeLocationAndStatus { fn from(raw: u8) -> Self { CurrentProbeLocationAndStatus { status: match raw & 0b111_00000 { 0b001_00000 => CurrentProbeStatus::Other, 0b010_00000 => CurrentProbeStatus::Unknown, 0b011_00000 => CurrentProbeStatus::OK, 0b100_00000 => CurrentProbeStatus::NonCritical, 0b101_00000 => CurrentProbeStatus::Critical, 0b110_00000 => CurrentProbeStatus::NonRecoverable, _ => CurrentProbeStatus::None, }, location: match raw & 0b000_11111 { 0b000_00001 => CurrentProbeLocation::Other, 0b000_00010 => CurrentProbeLocation::Unknown, 0b000_00011 => CurrentProbeLocation::Processor, 0b000_00100 => CurrentProbeLocation::Disk, 0b000_00101 => CurrentProbeLocation::PeripheralBay, 0b000_00110 => CurrentProbeLocation::SystemManagementModule, 0b000_00111 => CurrentProbeLocation::Motherboard, 0b000_01000 => CurrentProbeLocation::MemoryModule, 0b000_01001 => CurrentProbeLocation::ProcessorModule, 0b000_01010 => CurrentProbeLocation::PowerUnit, 0b000_01011 => CurrentProbeLocation::AddInCard, _ => CurrentProbeLocation::None, }, raw, } } } /// # Probe Amperage #[derive(Serialize, Debug)] pub enum ProbeAmperage { /// Amperage in milliamps Milliamps(u16), /// Amperage is unknown Unknown, } impl From for ProbeAmperage { fn from(raw: u16) -> Self { match raw { 0x8000 => ProbeAmperage::Unknown, _ => ProbeAmperage::Milliamps(raw), } } } /// # Current Probe Resolution #[derive(Serialize, Debug)] pub enum CurrentProbeResolution { /// Resolution for the probe's reading in tenths of milliamps TenthsOfMilliamps(u16), /// Resolution is unknown Unknown, } impl From for CurrentProbeResolution { fn from(raw: u16) -> Self { match raw { 0x8000 => CurrentProbeResolution::Unknown, _ => CurrentProbeResolution::TenthsOfMilliamps(raw), } } } /// # Current Probe Accuracy #[derive(Serialize, Debug)] pub enum CurrentProbeAccuracy { /// Accuracy for the probe's reading in 1/100th of a percent OneOneHundredthPercent(u16), /// Accuracy is unknown Unknown, } impl From for CurrentProbeAccuracy { fn from(raw: u16) -> Self { match raw { 0x8000 => CurrentProbeAccuracy::Unknown, _ => CurrentProbeAccuracy::OneOneHundredthPercent(raw), } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type29 = vec![ 0x1D, 0x16, 0x33, 0x00, 0x01, 0x67, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, b'A', b'B', b'C', 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type29); let test_struct = SMBiosElectricalCurrentProbe::new(&parts); assert_eq!(test_struct.description().to_string(), "ABC".to_string()); let location_and_status = test_struct.location_and_status().unwrap(); assert_eq!(location_and_status.status, CurrentProbeStatus::OK); assert_eq!( location_and_status.location, CurrentProbeLocation::Motherboard ); assert_eq!( test_struct.location_and_status(), Some(CurrentProbeLocationAndStatus::from(103)) ); match test_struct.maximum_value().unwrap() { ProbeAmperage::Milliamps(_) => panic!("expected unknown"), ProbeAmperage::Unknown => (), } match test_struct.minimum_value().unwrap() { ProbeAmperage::Milliamps(_) => panic!("expected unknown"), ProbeAmperage::Unknown => (), } match test_struct.resolution().unwrap() { CurrentProbeResolution::TenthsOfMilliamps(_) => panic!("expected unknown"), CurrentProbeResolution::Unknown => (), } match test_struct.tolerance().unwrap() { ProbeAmperage::Milliamps(_) => panic!("expected unknown"), ProbeAmperage::Unknown => (), } match test_struct.accuracy().unwrap() { CurrentProbeAccuracy::OneOneHundredthPercent(_) => panic!("expected unknown"), CurrentProbeAccuracy::Unknown => (), } assert_eq!(test_struct.oem_defined(), Some(0)); match test_struct.nominal_value().unwrap() { ProbeAmperage::Milliamps(_) => panic!("expected unknown"), ProbeAmperage::Unknown => (), } } } smbios-lib-0.9.2/src/structs/types/end_of_table.rs000064400000000000000000000034601046102023000203100ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # End-of-Table (Type 127) /// /// This structure type identifies the end of the structure table that might be earlier than the last byte within the buffer specified by the structure. /// /// To ensure backward compatibility with management software written to previous versions of this /// specification, a system implementation should use the end-of-table indicator in a manner similar to the /// [super::SMBiosInactive] (Type 126) structure type; the structure table is still reported as a fixed-length, and the entire /// length of the table is still indexable. If the end-of-table indicator is used in the last physical structure in a /// table, the field’s length is encoded as 4. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosEndOfTable<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosEndOfTable<'a> { const STRUCT_TYPE: u8 = 127u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosEndOfTable<'a> {} impl fmt::Debug for SMBiosEndOfTable<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .finish() } } impl Serialize for SMBiosEndOfTable<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosEndOfTable", 1)?; state.serialize_field("header", &self.parts.header)?; state.end() } } smbios-lib-0.9.2/src/structs/types/firmware_inventory_information.rs000064400000000000000000000642271046102023000242550ustar 00000000000000use crate::core::{strings::*, Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # Firmware Inventory Information (Type 45) /// /// The information in this structure defines an inventory of firmware components in the system. This can /// include firmware components such as BIOS, BMC, as well as firmware for other devices in the system. /// /// The information can be used by software to display the firmware inventory in a uniform manner. It can /// also be used by a management controller, such as a BMC, for remote system management. This /// structure is not intended to replace other standard programmatic interfaces for firmware updates. /// /// One Type 45 structure is provided for each firmware component. /// /// NOTE: This structure type was added in version 3.5 of this specification. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.5.0 (DSP0134) /// Document Date: 2021-09-15 pub struct SMBiosFirmwareInventoryInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosFirmwareInventoryInformation<'a> { const STRUCT_TYPE: u8 = 45u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosFirmwareInventoryInformation<'a> { /// Firmware Component Name /// /// EXAMPLE: 'BMC Firmware',0 pub fn firmware_component_name(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Firmware Version /// /// The format of this value is defined by _version_format_ pub fn firmware_version(&self) -> SMBiosString { self.parts.get_field_string(0x05) } /// Version Format pub fn version_format(&self) -> Option { self.parts .get_field_byte(0x06) .map(|raw| VersionFormatData::from(raw)) } /// Firmware ID /// /// The format of this value is defined by _firmware_id_format_ pub fn firmware_id(&self) -> SMBiosString { self.parts.get_field_string(0x07) } /// Firmware ID Format pub fn firmware_id_format(&self) -> Option { self.parts .get_field_byte(0x08) .map(|raw| FirmwareIdFormatData::from(raw)) } /// Release Date pub fn release_date(&self) -> SMBiosString { self.parts.get_field_string(0x09) } /// Manufacturer pub fn manufacturer(&self) -> SMBiosString { self.parts.get_field_string(0x0A) } /// Lowest Supported Firmware Version /// /// The format of this value is defined by _version_format_ pub fn lowest_supported_firmware_version(&self) -> SMBiosString { self.parts.get_field_string(0x0B) } /// Image Size /// /// Size of the firmware image that is currently programmed /// in the device, in bytes. If the Firmware Image Size is /// unknown, the field is set to FirmwareImageSize::Unknown. pub fn image_size(&self) -> Option { self.parts .get_field_qword(0x0C) .map(|raw| FirmwareImageSize::from(raw)) } /// Firmware characteristics information. pub fn characteristics(&self) -> Option { self.parts .get_field_word(0x14) .map(|raw| FirmwareInventoryCharacteristics::from(raw)) } /// Firmware state information. pub fn state(&self) -> Option { self.parts .get_field_byte(0x16) .map(|raw| FirmwareInventoryStateInformationData::from(raw)) } /// Defines how many Associated Component Handles are associated with this firmware. pub fn number_of_associated_components(&self) -> Option { self.parts.get_field_byte(0x17) } /// Lists the SMBIOS structure handles that are associated /// with this firmware, if any. /// /// Value of _number_of_associated_components_ field (n) defines the count. /// /// NOTE: This list may contain zero or more handles to any /// SMBIOS structure that represents a device with a /// firmware component. pub fn associated_component_handle_iterator(&'a self) -> AssociatedComponentHandleIterator<'a> { AssociatedComponentHandleIterator::new(self) } } impl fmt::Debug for SMBiosFirmwareInventoryInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("firmware_component_name", &self.firmware_component_name()) .field("firmware_version", &self.firmware_version()) .field("version_format", &self.version_format()) .field("firmware_id", &self.firmware_id()) .field("firmware_id_format", &self.firmware_id_format()) .field("release_date", &self.release_date()) .field("manufacturer", &self.manufacturer()) .field( "lowest_supported_firmware_version", &self.lowest_supported_firmware_version(), ) .field("image_size", &self.image_size()) .field("characteristics", &self.characteristics()) .field("state", &self.state()) .field( "number_of_associated_components", &self.number_of_associated_components(), ) .field( "associated_component_handle_iterator", &self.associated_component_handle_iterator(), ) .finish() } } impl Serialize for SMBiosFirmwareInventoryInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosFirmwareInventoryInformation", 12)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("firmware_component_name", &self.firmware_component_name())?; state.serialize_field("firmware_version", &self.firmware_version())?; state.serialize_field("version_format", &self.version_format())?; state.serialize_field("firmware_id", &self.firmware_id())?; state.serialize_field("firmware_id_format", &self.firmware_id_format())?; state.serialize_field("release_date", &self.release_date())?; state.serialize_field("manufacturer", &self.manufacturer())?; state.serialize_field( "lowest_supported_firmware_version", &self.lowest_supported_firmware_version(), )?; state.serialize_field("image_size", &self.image_size())?; state.serialize_field("characteristics", &self.characteristics())?; state.serialize_field("state", &self.state())?; state.serialize_field( "number_of_associated_components", &self.number_of_associated_components(), )?; state.serialize_field( "associated_component_handle_iterator", &self.associated_component_handle_iterator(), )?; state.end() } } /// # Size of Image in Bytes #[derive(Serialize, Debug)] pub enum FirmwareImageSize { /// Image Size is Unknown Unknown, /// Size of Image (bytes) Bytes(u64), } impl From for FirmwareImageSize { fn from(raw: u64) -> Self { match raw { 0xFFFFFFFFFFFFFFFF => FirmwareImageSize::Unknown, _ => FirmwareImageSize::Bytes(raw), } } } /// # Version Format Data of [SMBiosFirmwareInventoryInformation]. pub struct VersionFormatData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [VersionFormat] value pub value: VersionFormat, } impl fmt::Debug for VersionFormatData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for VersionFormatData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("VersionFormatData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for VersionFormatData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { VersionFormat::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for VersionFormatData { type Target = VersionFormat; fn deref(&self) -> &Self::Target { &self.value } } impl From for VersionFormatData { fn from(raw: u8) -> Self { VersionFormatData { value: match raw { 0x00 => VersionFormat::FreeForm, 0x01 => VersionFormat::MajorMinor, 0x02 => VersionFormat::HexidecimalString32, 0x03 => VersionFormat::HexidecimalString64, _ => match raw & 0x80 { 0x80 => VersionFormat::VendorOemSpecific, _ => VersionFormat::None, }, }, raw, } } } /// # Version Format of [SMBiosFirmwareInventoryInformation] #[derive(Serialize, Debug, PartialEq, Eq)] pub enum VersionFormat { /// The format is a free-form string that is implementation specific. /// /// EXAMPLE: '1.45.455b66-rev4',0 FreeForm, /// The format is “MAJOR.MINOR”, where MAJOR and MINOR are decimal string representations of the /// numeric values of the major/minor version numbers. /// /// EXAMPLE: '1.45',0 MajorMinor, /// The format is a hexadecimal string representation of the 32-bit numeric value of the version, in the /// format of "0xhhhhhhhh". Each h represents a hexadecimal digit (0-f). /// /// EXAMPLE: '0x0001002d',0 HexidecimalString32, /// The format is a hexadecimal string representation of the 64-bit numeric value of the version, in the /// format of "0xhhhhhhhhhhhhhhhh". Each h represents a hexadecimal digit (0-f). /// /// EXAMPLE: '0x000000010000002d',0 HexidecimalString64, /// BIOS Vendor/OEM-specific VendorOemSpecific, /// A value unknown to this standard, check the raw value None, } /// # Firmware Id Format Data of [SMBiosFirmwareInventoryInformation]. pub struct FirmwareIdFormatData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [FirmwareIdFormat] value pub value: FirmwareIdFormat, } impl fmt::Debug for FirmwareIdFormatData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for FirmwareIdFormatData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("FirmwareIdFormatData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for FirmwareIdFormatData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { FirmwareIdFormat::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for FirmwareIdFormatData { type Target = FirmwareIdFormat; fn deref(&self) -> &Self::Target { &self.value } } impl From for FirmwareIdFormatData { fn from(raw: u8) -> Self { FirmwareIdFormatData { value: match raw { 0x00 => FirmwareIdFormat::FreeForm, 0x01 => FirmwareIdFormat::UefiGuid, _ => match raw & 0x80 { 0x80 => FirmwareIdFormat::VendorOemSpecific, _ => FirmwareIdFormat::None, }, }, raw, } } } /// # Firmware Id Format of [SMBiosFirmwareInventoryInformation] #[derive(Serialize, Debug, PartialEq, Eq)] pub enum FirmwareIdFormat { /// The format is a free-form string that is implementation specific. /// /// EXAMPLE: '35EQP72B',0 FreeForm, /// The format is a string representation of the UEFI ESRT FwClass GUID or the UEFI Firmware /// Management Protocol ImageTypeId, as defined by the UEFI Specification. To represent the GUID, the /// string is formatted using the 36-character UUID string format specified in RFC4122: "xxxxxxxx-xxxxxxxx-xxxx-xxxxxxxxxxxx." Each x represents a hexadecimal digit (0-F). /// /// EXAMPLE: '1624a9df-5e13-47fc-874a-df3aff143089',0 UefiGuid, /// BIOS Vendor/OEM-specific VendorOemSpecific, /// A value unknown to this standard, check the raw value None, } /// # Firmware Inventory Characteristics of [SMBiosFirmwareInventoryInformation] #[derive(PartialEq, Eq)] pub struct FirmwareInventoryCharacteristics { /// Raw value /// /// _raw_ is useful when there are values not yet defiend. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u16, } impl Deref for FirmwareInventoryCharacteristics { type Target = u16; fn deref(&self) -> &Self::Target { &self.raw } } impl From for FirmwareInventoryCharacteristics { fn from(raw: u16) -> Self { FirmwareInventoryCharacteristics { raw } } } impl FirmwareInventoryCharacteristics { /// Updatable /// /// This firmware can be updated by software. pub fn updatable(&self) -> bool { self.raw & 0b0000_0000_0000_0001 == 0b0000_0000_0000_0001 } /// Write-Protect /// /// This firmware is in a write-protected state. pub fn write_protect(&self) -> bool { self.raw & 0b0000_0000_0000_0010 == 0b0000_0000_0000_0010 } } impl fmt::Debug for FirmwareInventoryCharacteristics { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("updatable", &self.updatable()) .field("write_protect", &self.write_protect()) .finish() } } impl Serialize for FirmwareInventoryCharacteristics { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("FirmwareInventoryCharacteristics", 6)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("updatable", &self.updatable())?; state.serialize_field("write_protect", &self.write_protect())?; state.end() } } /// # Firmware Inventory State Information Data of [SMBiosFirmwareInventoryInformation]. pub struct FirmwareInventoryStateInformationData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [FirmwareInventoryStateInformation] value pub value: FirmwareInventoryStateInformation, } impl fmt::Debug for FirmwareInventoryStateInformationData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for FirmwareInventoryStateInformationData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("FirmwareInventoryStateInformationData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for FirmwareInventoryStateInformationData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { FirmwareInventoryStateInformation::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for FirmwareInventoryStateInformationData { type Target = FirmwareInventoryStateInformation; fn deref(&self) -> &Self::Target { &self.value } } impl From for FirmwareInventoryStateInformationData { fn from(raw: u8) -> Self { FirmwareInventoryStateInformationData { value: match raw { 0x01 => FirmwareInventoryStateInformation::Other, 0x02 => FirmwareInventoryStateInformation::Unknown, 0x03 => FirmwareInventoryStateInformation::Disabled, 0x04 => FirmwareInventoryStateInformation::Enabled, 0x05 => FirmwareInventoryStateInformation::Absent, 0x06 => FirmwareInventoryStateInformation::StandbyOffline, 0x07 => FirmwareInventoryStateInformation::StandbySpare, 0x08 => FirmwareInventoryStateInformation::UnavailableOffline, _ => FirmwareInventoryStateInformation::None, }, raw, } } } /// # Firmware Inventory State Information of [SMBiosFirmwareInventoryInformation] #[derive(Serialize, Debug, PartialEq, Eq)] pub enum FirmwareInventoryStateInformation { /// Other Other, /// Unknown Unknown, /// Disabled /// /// This firmware component is disabled Disabled, /// Enabled /// /// This firmware component is enabled Enabled, /// Absent /// /// This firmware component is either not present or not detected Absent, /// Standby Offline /// /// This firmware is enabled but awaits an external action to activate it StandbyOffline, /// Standby Spare /// /// This firmware is part of a redundancy set and awaits a failover or other external action to /// activate it StandbySpare, /// Unavailable Offline /// /// This firmware component is present but cannot be used UnavailableOffline, /// A value unknown to this standard, check the raw value None, } /// # Associated Component Handle Iterator /// /// Iterates over the associated component handles contained within the [SMBiosFirmwareInventoryInformation] structure pub struct AssociatedComponentHandleIterator<'a> { data: &'a SMBiosFirmwareInventoryInformation<'a>, current_index: usize, current_entry: u8, number_of_associated_components: u8, } impl<'a> AssociatedComponentHandleIterator<'a> { const HANDLES_OFFSET: usize = 0x18usize; /// Creates an instance of the associated component handle iterator. pub fn new(data: &'a SMBiosFirmwareInventoryInformation<'a>) -> Self { AssociatedComponentHandleIterator { data: data, current_index: Self::HANDLES_OFFSET, current_entry: 0, number_of_associated_components: data.number_of_associated_components().unwrap_or(0), } } fn reset(&mut self) { self.current_index = Self::HANDLES_OFFSET; self.current_entry = 0; } } impl<'a> IntoIterator for &'a AssociatedComponentHandleIterator<'a> { type Item = Handle; type IntoIter = AssociatedComponentHandleIterator<'a>; fn into_iter(self) -> Self::IntoIter { AssociatedComponentHandleIterator { data: self.data, current_index: AssociatedComponentHandleIterator::HANDLES_OFFSET, current_entry: 0, number_of_associated_components: self .data .number_of_associated_components() .unwrap_or(0), } } } impl<'a> Iterator for AssociatedComponentHandleIterator<'a> { type Item = Handle; fn next(&mut self) -> Option { if self.current_entry == self.number_of_associated_components { self.reset(); return None; } match self.data.parts().get_field_handle(self.current_index) { Some(current_handle) => { self.current_index = self.current_index + Handle::SIZE; self.current_entry = self.current_entry + 1; Some(current_handle) } None => { self.reset(); None } } } } impl<'a> fmt::Debug for AssociatedComponentHandleIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().entries(self.into_iter()).finish() } } impl<'a> Serialize for AssociatedComponentHandleIterator<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let handles: Vec = self.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(handles.len()))?; for e in handles { seq.serialize_element(&e)?; } seq.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_firmware_inventory_information() { let firmware_inventory_information_bytes = vec![ // struct_type(45), length(0x1A), handle(0x10) 0x2D, 0x1A, 0x10, 0x00, // firmware_component_name(1), firmware_version(2), version_format (FreeForm - 0), firmware_id(3), firmware_id_format (FreeForm - 0), release_date(4), manufacturer(5), lowest_supported_firmware_version(6) 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x05, 0x06, // image_size(0xFFFFFFFFFFFFFFFF), characteristics(0x0001), state(StandbySpare - 0x07), number_of_components(1) 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x07, 0x01, // handle[0] == 0x0005 0x05, 0x00, // firmware_component_name: "BMC Firmware" (1) b'B', b'M', b'C', b' ', b'F', b'i', b'r', b'm', b'w', b'a', b'r', b'e', 0x00, // firmware_version: "1.45.455b66-rev4" (2) b'1', b'.', b'4', b'5', b'.', b'4', b'5', b'5', b'b', b'6', b'6', b'-', b'r', b'e', b'v', b'4', 0x00, // firmware_id: "35EQP72B" (3) b'3', b'5', b'E', b'Q', b'P', b'7', b'2', b'B', 0x00, // release_date: "2021-05-15T04:14:33+06:00" (4) b'2', b'0', b'2', b'1', b'-', b'0', b'5', b'-', b'1', b'5', b'T', b'0', b'4', b':', b'1', b'4', b':', b'3', b'3', b'+', b'0', b'6', b':', b'0', b'0', 0x00, // manufacturer: "Apple" (5) b'A', b'p', b'p', b'l', b'e', 0x00, // lowest_supported_firmware_version: "1.23.456b78-rev9" (6) b'1', b'.', b'2', b'3', b'.', b'4', b'5', b'6', b'b', b'7', b'8', b'-', b'r', b'e', b'v', b'9', 0x00, // end of structure 0x00, ]; let parts = UndefinedStruct::new(&firmware_inventory_information_bytes); let firmware_inventory_information = SMBiosFirmwareInventoryInformation::new(&parts); // basic field tests assert_eq!( firmware_inventory_information .firmware_component_name() .to_string(), "BMC Firmware".to_string() ); assert_eq!( firmware_inventory_information .firmware_version() .to_string(), "1.45.455b66-rev4".to_string() ); assert_eq!( firmware_inventory_information .version_format() .unwrap() .value, VersionFormat::FreeForm ); assert_eq!( firmware_inventory_information.firmware_id().to_string(), "35EQP72B".to_string() ); assert_eq!( firmware_inventory_information .firmware_id_format() .unwrap() .value, FirmwareIdFormat::FreeForm ); assert_eq!( firmware_inventory_information.release_date().to_string(), "2021-05-15T04:14:33+06:00".to_string() ); assert_eq!( firmware_inventory_information.manufacturer().to_string(), "Apple".to_string() ); assert_eq!( firmware_inventory_information .lowest_supported_firmware_version() .to_string(), "1.23.456b78-rev9".to_string() ); match firmware_inventory_information.image_size().unwrap() { FirmwareImageSize::Unknown => (), FirmwareImageSize::Bytes(_) => panic!("expected unknown"), } assert_eq!( firmware_inventory_information .characteristics() .unwrap() .updatable(), true ); assert_eq!( firmware_inventory_information.state().unwrap().value, FirmwareInventoryStateInformation::StandbySpare ); assert_eq!( firmware_inventory_information .number_of_associated_components() .unwrap(), 1u8 ); let mut iterator = firmware_inventory_information.associated_component_handle_iterator(); let first_entry = iterator.next().expect("has a first entry"); assert_eq!(*first_entry, 0x0005); assert!(iterator.next().is_none()); let mut counter = 0; for _entry in firmware_inventory_information.associated_component_handle_iterator() { counter = counter + 1; } assert_eq!(counter, 1); // debug print test println!( "firmware_inventory_information: {:?}", firmware_inventory_information ); } } smbios-lib-0.9.2/src/structs/types/group_associations.rs000064400000000000000000000175521046102023000216310ustar 00000000000000use crate::core::{strings::*, Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Group Associations (Type 14) /// /// The Group Associations structure is provided for OEMs who want to specify the arrangement or hierarchy /// of certain components (including other Group Associations) within the system. For example, you can use /// the Group Associations structure to indicate that two CPUs share a common external cache system. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosGroupAssociations<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosGroupAssociations<'a> { const STRUCT_TYPE: u8 = 14u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosGroupAssociations<'a> { /// A string describing the group pub fn group_name(&self) -> SMBiosString { self.parts.get_field_string(0x4) } /// Number of [GroupAssociationItem] entries pub fn number_of_items(&self) -> Option { let length = self.parts.header.length() as usize; if length < GroupAssociationItemIterator::ITEMS_OFFSET { return None; } let byte_count = length - GroupAssociationItemIterator::ITEMS_OFFSET; if byte_count % GroupAssociationItem::SIZE != 0 { return None; } Some(byte_count / GroupAssociationItem::SIZE) } /// Iterates over the [GroupAssociationItem] entries pub fn item_iterator(&'a self) -> GroupAssociationItemIterator<'a> { GroupAssociationItemIterator::new(self) } } impl fmt::Debug for SMBiosGroupAssociations<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("group_name", &self.group_name()) .field("number_of_items", &self.number_of_items()) .field("item_iterator", &self.item_iterator()) .finish() } } impl Serialize for SMBiosGroupAssociations<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosGroupAssociations", 4)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("group_name", &self.group_name())?; state.serialize_field("number_of_items", &self.number_of_items())?; state.serialize_field("item_iterator", &self.item_iterator())?; state.end() } } /// # Group Association Item contained within [SMBiosGroupAssociations] pub struct GroupAssociationItem<'a> { group_associations: &'a SMBiosGroupAssociations<'a>, entry_offset: usize, } impl<'a> GroupAssociationItem<'a> { /// Size in bytes of a GroupAssociationItem const SIZE: usize = 3usize; fn new(group_associations: &'a SMBiosGroupAssociations<'a>, entry_offset: usize) -> Self { Self { group_associations, entry_offset, } } /// Item Type /// /// Item (Structure) Type of this member pub fn struct_type(&self) -> Option { self.group_associations .parts() .get_field_byte(self.entry_offset) } /// Item Handle /// /// Handle corresponding to this structure pub fn item_handle(&self) -> Option { self.group_associations .parts() .get_field_handle(self.entry_offset + 1) } } impl fmt::Debug for GroupAssociationItem<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("struct_type", &self.struct_type()) .field("item_handle", &self.item_handle()) .finish() } } impl Serialize for GroupAssociationItem<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("GroupAssociationItem", 2)?; state.serialize_field("struct_type", &self.struct_type())?; state.serialize_field("item_handle", &self.item_handle())?; state.end() } } /// Iterates over the [GroupAssociationItem] entries contained within [SMBiosGroupAssociations] pub struct GroupAssociationItemIterator<'a> { data: &'a SMBiosGroupAssociations<'a>, current_index: usize, current_entry: usize, number_of_entries: usize, } impl<'a> GroupAssociationItemIterator<'a> { const ITEMS_OFFSET: usize = 5usize; fn new(data: &'a SMBiosGroupAssociations<'a>) -> Self { GroupAssociationItemIterator { data: data, current_index: Self::ITEMS_OFFSET, current_entry: 0, number_of_entries: data.number_of_items().unwrap_or(0), } } fn reset(&mut self) { self.current_index = Self::ITEMS_OFFSET; self.current_entry = 0; } } impl<'a> IntoIterator for &'a GroupAssociationItemIterator<'a> { type Item = GroupAssociationItem<'a>; type IntoIter = GroupAssociationItemIterator<'a>; fn into_iter(self) -> Self::IntoIter { GroupAssociationItemIterator { data: self.data, current_index: GroupAssociationItemIterator::ITEMS_OFFSET, current_entry: 0, number_of_entries: self.data.number_of_items().unwrap_or(0), } } } impl<'a> Iterator for GroupAssociationItemIterator<'a> { type Item = GroupAssociationItem<'a>; fn next(&mut self) -> Option { if self.current_entry == self.number_of_entries { self.reset(); return None; } let next_index = self.current_index + GroupAssociationItem::SIZE; match self .data .parts() .get_field_data(self.current_index, next_index) { Some(_entry_block) => { let result = GroupAssociationItem::new(self.data, self.current_index); self.current_index = next_index; self.current_entry += 1; Some(result) } None => { self.reset(); None } } } } impl<'a> fmt::Debug for GroupAssociationItemIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().entries(self.into_iter()).finish() } } impl<'a> Serialize for GroupAssociationItemIterator<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let items: Vec> = self.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(items.len()))?; for e in items { seq.serialize_element(&e)?; } seq.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type14 = vec![ 0x0E, 0x08, 0x5F, 0x00, 0x01, 0xDD, 0x5B, 0x00, 0x46, 0x69, 0x72, 0x6D, 0x77, 0x61, 0x72, 0x65, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x49, 0x6E, 0x66, 0x6F, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type14); let test_struct = SMBiosGroupAssociations::new(&parts); println!("{:?}", test_struct); assert_eq!( test_struct.group_name().to_string(), "Firmware Version Info".to_string() ); let mut iterator = test_struct.item_iterator().into_iter(); let first_item = iterator.next().unwrap(); assert_eq!(first_item.struct_type(), Some(221)); assert_eq!(*first_item.item_handle().unwrap(), 91); } } smbios-lib-0.9.2/src/structs/types/hardware_security.rs000064400000000000000000000137451046102023000214420ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Hardware Security (Type 24) /// /// This structure describes the system-wide hardware security settings. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosHardwareSecurity<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosHardwareSecurity<'a> { const STRUCT_TYPE: u8 = 24u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosHardwareSecurity<'a> { /// Bit field that identifies the password and reset status for the system pub fn hardware_security_settings(&self) -> Option { self.parts .get_field_byte(0x4) .map(|raw| HardwareSecuritySettings::from(raw)) } } impl fmt::Debug for SMBiosHardwareSecurity<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field( "hardware_security_settings", &self.hardware_security_settings(), ) .finish() } } impl Serialize for SMBiosHardwareSecurity<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosHardwareSecurity", 2)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field( "hardware_security_settings", &self.hardware_security_settings(), )?; state.end() } } /// # Hardware Security Settings #[derive(PartialEq, Eq)] pub struct HardwareSecuritySettings { /// Raw value pub raw: u8, /// Power-on Password Status pub power_on_password_status: HardwareSecurityStatus, /// Keyboard Password Status pub keyboard_password_status: HardwareSecurityStatus, /// Administrator Password Status pub administrator_password_status: HardwareSecurityStatus, /// Front Panel Reset Status pub front_panel_reset_status: HardwareSecurityStatus, } impl fmt::Debug for HardwareSecuritySettings { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("power_on_password_status", &self.power_on_password_status) .field("keyboard_password_status", &self.keyboard_password_status) .field( "administrator_password_status", &self.administrator_password_status, ) .field("front_panel_reset_status", &self.front_panel_reset_status) .finish() } } impl Serialize for HardwareSecuritySettings { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("HardwareSecuritySettings", 5)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("power_on_password_status", &self.power_on_password_status)?; state.serialize_field("keyboard_password_status", &self.keyboard_password_status)?; state.serialize_field( "administrator_password_status", &self.administrator_password_status, )?; state.serialize_field("front_panel_reset_status", &self.front_panel_reset_status)?; state.end() } } /// # Hardware Security Status #[derive(Serialize, Debug, PartialEq, Eq)] pub enum HardwareSecurityStatus { /// Disabled Disabled, /// Enabled Enabled, /// Not implemented NotImplemented, /// Unknown status Unknown, } impl From for HardwareSecuritySettings { fn from(raw: u8) -> Self { HardwareSecuritySettings { power_on_password_status: match raw & 0b11_000000 { 0b00_000000 => HardwareSecurityStatus::Disabled, 0b01_000000 => HardwareSecurityStatus::Enabled, 0b10_000000 => HardwareSecurityStatus::NotImplemented, 0b11_000000 => HardwareSecurityStatus::Unknown, _ => panic!("Impossible value"), }, keyboard_password_status: match raw & 0b00_11_0000 { 0b00_00_0000 => HardwareSecurityStatus::Disabled, 0b00_01_0000 => HardwareSecurityStatus::Enabled, 0b00_10_0000 => HardwareSecurityStatus::NotImplemented, 0b00_11_0000 => HardwareSecurityStatus::Unknown, _ => panic!("Impossible value"), }, administrator_password_status: match raw & 0b0000_11_00 { 0b0000_00_00 => HardwareSecurityStatus::Disabled, 0b0000_01_00 => HardwareSecurityStatus::Enabled, 0b0000_10_00 => HardwareSecurityStatus::NotImplemented, 0b0000_11_00 => HardwareSecurityStatus::Unknown, _ => panic!("Impossible value"), }, front_panel_reset_status: match raw & 0b000000_11 { 0b000000_00 => HardwareSecurityStatus::Disabled, 0b000000_01 => HardwareSecurityStatus::Enabled, 0b000000_10 => HardwareSecurityStatus::NotImplemented, 0b000000_11 => HardwareSecurityStatus::Unknown, _ => panic!("Impossible value"), }, raw, } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type24 = vec![0x18, 0x05, 0x24, 0x00, 0x16, 0x00, 0x00]; let parts = UndefinedStruct::new(&struct_type24); let test_struct = SMBiosHardwareSecurity::new(&parts); assert_eq!( test_struct.hardware_security_settings(), Some(HardwareSecuritySettings::from(22)) ); } } smbios-lib-0.9.2/src/structs/types/inactive.rs000064400000000000000000000027071046102023000175140ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Inactive (Type 126) /// /// This structure definition supports a system implementation where the SMBIOS structure-table is a /// superset of all supported system attributes and provides a standard mechanism for the system BIOS to /// signal that a structure is currently inactive and should not be interpreted by the upper-level software. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosInactive<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosInactive<'a> { const STRUCT_TYPE: u8 = 126u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosInactive<'a> {} impl fmt::Debug for SMBiosInactive<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .finish() } } impl Serialize for SMBiosInactive<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosInactive", 1)?; state.serialize_field("header", &self.parts.header)?; state.end() } } smbios-lib-0.9.2/src/structs/types/ipmi_device_information.rs000064400000000000000000000310411046102023000225650ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # IPMI Device Information (Type 38) /// /// The information in this structure defines the attributes of an Intelligent Platform Management Interface /// (IPMI) Baseboard Management Controller (BMC). /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosIpmiDeviceInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosIpmiDeviceInformation<'a> { const STRUCT_TYPE: u8 = 38u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosIpmiDeviceInformation<'a> { /// Baseboard Management Controller (BMC) interface type. pub fn interface_type(&self) -> Option { self.parts .get_field_byte(0x04) .map(|raw| IpmiInterfaceTypeData::from(raw)) } /// IPMI specification revision, in BCD format, to which the BMC was designed pub fn ipmi_specification_revision(&self) -> Option { self.parts.get_field_byte(0x05) } /// Slave address on the I2C bus of this BMC pub fn i2c_target_address(&self) -> Option { self.parts.get_field_byte(0x06) } /// Bus ID of the NV storage device. /// /// If no storage device exists for this BMC, the field is set to 0FFh. pub fn nvstorage_device_address(&self) -> Option { self.parts.get_field_byte(0x07) } /// Base address (either memory-mapped or I/O) of the BMC /// /// If the least-significant bit of the field is a 1, the address is in /// I/O space; otherwise, the address is memory-mapped. Refer /// to the [IPMI Interface Specification](https://www.intel.com/content/www/us/en/products/docs/servers/ipmi/ipmi-home.html) for usage details. pub fn base_address(&self) -> Option { self.parts.get_field_qword(0x08) } /// Base Address Modifier and Interrupt Info pub fn base_address_modifier(&self) -> Option { self.parts .get_field_byte(0x10) .map(|raw| BaseAddressModifier::from(raw)) } /// Interrupt number for IPMI System Interface /// /// 00h = unspecified/unsupported pub fn interrupt_number(&self) -> Option { self.parts.get_field_byte(0x11) } } impl fmt::Debug for SMBiosIpmiDeviceInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("interface_type", &self.interface_type()) .field( "ipmi_specification_revision", &self.ipmi_specification_revision(), ) .field("i2c_target_address", &self.i2c_target_address()) .field("nvstorage_device_address", &self.nvstorage_device_address()) .field("base_address", &self.base_address()) .field("base_address_modifier", &self.base_address_modifier()) .field("interrupt_number", &self.interrupt_number()) .finish() } } impl Serialize for SMBiosIpmiDeviceInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosIpmiDeviceInformation", 8)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("interface_type", &self.interface_type())?; state.serialize_field( "ipmi_specification_revision", &self.ipmi_specification_revision(), )?; state.serialize_field("i2c_target_address", &self.i2c_target_address())?; state.serialize_field("nvstorage_device_address", &self.nvstorage_device_address())?; state.serialize_field("base_address", &self.base_address())?; state.serialize_field("base_address_modifier", &self.base_address_modifier())?; state.serialize_field("interrupt_number", &self.interrupt_number())?; state.end() } } /// # Electrical Current Probe Location and Status #[derive(PartialEq, Eq)] pub struct BaseAddressModifier { /// Raw value pub raw: u8, /// Register Spacing pub register_spacing: RegisterSpacing, /// LS-bit for addresses pub ls_address_bit: AddressBit, /// Interrupt Info /// /// Identifies the type and polarity of the interrupt /// associated with the IPMI system interface, if any pub interrupt_info: InterruptInfo, /// Interrupt Polarity pub interrupt_polarity: InterruptPolarity, /// Interrupt Trigger Mode pub interrupt_trigger_mode: InterruptTriggerMode, } impl fmt::Debug for BaseAddressModifier { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("register_spacing", &self.register_spacing) .field("ls_address_bit", &self.ls_address_bit) .field("interrupt_info", &self.interrupt_info) .field("interrupt_polarity", &self.interrupt_polarity) .field("interrupt_trigger_mode", &self.interrupt_trigger_mode) .finish() } } impl Serialize for BaseAddressModifier { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("BaseAddressModifier", 6)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("register_spacing", &self.register_spacing)?; state.serialize_field("ls_address_bit", &self.ls_address_bit)?; state.serialize_field("interrupt_info", &self.interrupt_info)?; state.serialize_field("interrupt_polarity", &self.interrupt_polarity)?; state.serialize_field("interrupt_trigger_mode", &self.interrupt_trigger_mode)?; state.end() } } /// # Register Spacing #[derive(Serialize, Debug, PartialEq, Eq)] pub enum RegisterSpacing { /// Interface registers are on successive byte boundaries. BoundaryByte, /// Interface registers are on 32-bit boundaries. Boundary32Bit, /// Interface registers are on 16-byte boundaries. Boundary16Bit, /// A value unknown to this standard, check the raw value None, } /// # LS-Bit for Addresses #[derive(Serialize, Debug, PartialEq, Eq)] pub enum AddressBit { /// Address bit 0 = 0b Zero, /// Address bit 1 = 1b One, } /// # Interrupt Info /// /// Identifies the type and polarity of the interrupt /// associated with the IPMI system interface, if any #[derive(Serialize, Debug, PartialEq, Eq)] pub enum InterruptInfo { /// Interrupt information specified Specified, /// Interrupt information not specified NotSpecified, } /// # Interrupt Polarity #[derive(Serialize, Debug, PartialEq, Eq)] pub enum InterruptPolarity { /// active high ActiveHigh, /// active low ActiveLow, } /// # Interrupt Trigger Mode #[derive(Serialize, Debug, PartialEq, Eq)] pub enum InterruptTriggerMode { /// level Level, /// edge Edge, } impl From for BaseAddressModifier { fn from(raw: u8) -> Self { BaseAddressModifier { register_spacing: match raw & 0b11_000000 { 0b00_000000 => RegisterSpacing::BoundaryByte, 0b01_000000 => RegisterSpacing::Boundary32Bit, 0b10_000000 => RegisterSpacing::Boundary16Bit, _ => RegisterSpacing::None, }, ls_address_bit: match raw & 0b000_1_0000 { 0b000_0_0000 => AddressBit::Zero, 0b000_1_0000 => AddressBit::One, _ => panic!("Impossible value"), }, interrupt_info: match raw & 0b0000_1_000 { 0b0000_1_000 => InterruptInfo::Specified, 0b0000_0_000 => InterruptInfo::NotSpecified, _ => panic!("Impossible value"), }, interrupt_polarity: match raw & 0b000000_1_0 { 0b000000_1_0 => InterruptPolarity::ActiveHigh, 0b000000_0_0 => InterruptPolarity::ActiveLow, _ => panic!("Impossible value"), }, interrupt_trigger_mode: match raw & 0b0000000_1 { 0b0000000_1 => InterruptTriggerMode::Level, 0b0000000_0 => InterruptTriggerMode::Edge, _ => panic!("Impossible value"), }, raw, } } } /// # Baseboard Management Controller (BMC) interface type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum IpmiInterfaceType { /// Unknown Unknown, /// KCS: Keyboard Controller Style KeyboardControllerStyle, /// SMIC: Server Management Interface Chip ServerManagementInterfaceChip, /// BT: Block Transfer BlockTransfer, /// SSIF: SMBus System Interface SMBusSystemInterface, /// A value unknown to this standard, check the raw value None, } /// # Baseboard Management Controller (BMC) interface type data pub struct IpmiInterfaceTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [IpmiInterfaceType] value pub value: IpmiInterfaceType, } impl fmt::Debug for IpmiInterfaceTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for IpmiInterfaceTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("IpmiInterfaceTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for IpmiInterfaceTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { IpmiInterfaceType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for IpmiInterfaceTypeData { type Target = IpmiInterfaceType; fn deref(&self) -> &Self::Target { &self.value } } impl From for IpmiInterfaceTypeData { fn from(raw: u8) -> Self { IpmiInterfaceTypeData { value: match raw { 0x00 => IpmiInterfaceType::Unknown, 0x01 => IpmiInterfaceType::KeyboardControllerStyle, 0x02 => IpmiInterfaceType::ServerManagementInterfaceChip, 0x03 => IpmiInterfaceType::BlockTransfer, 0x04 => IpmiInterfaceType::SMBusSystemInterface, _ => IpmiInterfaceType::None, }, raw, } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type38 = vec![ 0x26, 0x12, 0x24, 0x00, 0x01, 0x10, 0x05, 0xFF, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0b10010010, 0x00, ]; let parts = UndefinedStruct::new(&struct_type38); let test_struct = SMBiosIpmiDeviceInformation::new(&parts); assert_eq!( *test_struct.interface_type().unwrap(), IpmiInterfaceType::KeyboardControllerStyle ); assert_eq!(test_struct.ipmi_specification_revision(), Some(0x10)); assert_eq!(test_struct.i2c_target_address(), Some(5)); assert_eq!(test_struct.nvstorage_device_address(), Some(0xFF)); assert_eq!(test_struct.base_address(), Some(0x0102030405060708)); let base_address_modifier = test_struct.base_address_modifier().unwrap(); assert_eq!( base_address_modifier.register_spacing, RegisterSpacing::Boundary16Bit ); assert_eq!(base_address_modifier.ls_address_bit, AddressBit::One); assert_eq!( base_address_modifier.interrupt_info, InterruptInfo::NotSpecified ); assert_eq!( base_address_modifier.interrupt_polarity, InterruptPolarity::ActiveHigh ); assert_eq!( base_address_modifier.interrupt_trigger_mode, InterruptTriggerMode::Edge ); } } smbios-lib-0.9.2/src/structs/types/management_controller_host_interface.rs000064400000000000000000000457301046102023000253510ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # Management Controller Host Interface (Type 42) /// /// The information in this structure defines the attributes of a Management Controller Host Interface that is /// not discoverable by "Plug and Play" mechanisms. The Type 42 structure can /// be used to describe a physical management controller host interface and one or more protocols that /// share that interface. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 /// /// In SMBIOS 3.2, a Change Request is applied to this structure to add the missing information that is /// needed to parse the structure completely. The addition of the Interface Type Specific Data Length field /// may cause parser (prior to SMBIOS 3.2) compatibility issue when Interface Type = OEM. Prior to /// SMBIOS 3.2, when Interface Type = OEM, the first four bytes following the Interface Type field is the /// IANA-assigned vendor ID. pub struct SMBiosManagementControllerHostInterface<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosManagementControllerHostInterface<'a> { const STRUCT_TYPE: u8 = 42u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosManagementControllerHostInterface<'a> { const INTERFACE_TYPE_OFFSET: usize = 4usize; const SPECIFIC_DATA_LENGTH_OFFSET: usize = 5usize; const SPECIFIC_DATA_OFFSET: usize = 6usize; const PROTOCOL_RECORDS_RELATIVE_OFFSET: usize = 7usize; /// Management Controller Interface Type pub fn interface_type(&self) -> Option { self.parts .get_field_byte(Self::INTERFACE_TYPE_OFFSET) .map(|raw| HostInterfaceTypeData::from(raw)) } /// Interface Type Specific Data Length pub fn interface_type_specific_data_length(&self) -> Option { self.parts.get_field_byte(Self::SPECIFIC_DATA_LENGTH_OFFSET) } /// Management Controller Host Interface Data as specified by the Interface Type /// /// This field has a minimum of four bytes. /// /// If interface type = OEM, the first four bytes are the vendor ID (MSB first), as assigned by the Internet Assigned Numbers Authority (IANA). /// /// This format uses the "Enterprise Number" that is assigned and maintained by IANA (www.iana.org) as the means of identifying a particular vendor, company, or organization. pub fn interface_type_specific_data(&self) -> Option<&[u8]> { self.interface_type_specific_data_length() .and_then(|length| { self.parts().get_field_data( Self::SPECIFIC_DATA_OFFSET, Self::SPECIFIC_DATA_OFFSET + length as usize, ) }) } /// X number of Protocol Records for this Host Interface Type pub fn number_of_protocol_records(&self) -> Option { self.interface_type_specific_data_length() .and_then(|length| { self.parts() .get_field_byte(Self::SPECIFIC_DATA_OFFSET + length as usize) }) } /// private function for calculating the protocol records offset fn protocol_records_offset(&self) -> Option { self.interface_type_specific_data_length() .and_then(|length| Some(Self::PROTOCOL_RECORDS_RELATIVE_OFFSET + length as usize)) } /// Protocol Records pub fn protocol_record_iterator(&self) -> ProtocolRecordIterator<'_> { ProtocolRecordIterator::new(self) } } impl fmt::Debug for SMBiosManagementControllerHostInterface<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::< SMBiosManagementControllerHostInterface<'_>, >()) .field("header", &self.parts.header) .field("interface_type", &self.interface_type()) .field( "interface_type_specific_data_length", &self.interface_type_specific_data_length(), ) .field( "interface_type_specific_data", &self.interface_type_specific_data(), ) .field( "number_of_protocol_records", &self.number_of_protocol_records(), ) .field("protocol_record_iterator", &self.protocol_record_iterator()) .finish() } } impl Serialize for SMBiosManagementControllerHostInterface<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosManagementControllerHostInterface", 6)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("interface_type", &self.interface_type())?; state.serialize_field( "interface_type_specific_data_length", &self.interface_type_specific_data_length(), )?; state.serialize_field( "interface_type_specific_data", &self.interface_type_specific_data(), )?; state.serialize_field( "number_of_protocol_records", &self.number_of_protocol_records(), )?; state.serialize_field("protocol_record_iterator", &self.protocol_record_iterator())?; state.end() } } /// # Management Controller Host Interface Types /// /// 00h-3Fh: MCTP Host Interfaces - Refer to [DSP0239](https://www.dmtf.org/sites/default/files/standards/documents/DSP0239_1.1.0.pdf) for the definition and assignment of MCTP host interface type values /// 40h: Network Host Interface - Refer to [DSP0270](https://www.dmtf.org/sites/default/files/DSP0270_1.0.1.pdf) for the definition and details of the Network Host Interface type /// F0h: OEM-defined /// All others: Reserved #[derive(Serialize, Debug, PartialEq, Eq)] pub enum HostInterfaceType { /// KCS: Keyboard Controller Style /// /// Refer to _Intelligent Platform /// Management Interface Specification_ Section 9 Keyboard Controller /// Style (KCS) Interface KeyboardControllerStyle, /// 8250 UART Register Compatible Uart8250, /// 16450 UART Register Compatible Uart16450, /// 16550/16550A UART Register Compatible Uart16550, /// 16650/16650A UART Register Compatible Uart16650, /// 16750/16750A UART Register Compatible Uart16750, /// 16850/16850A UART Register Compatible Uart16850, /// Redfish Network Host Interface /// /// See [DSP0270](https://www.dmtf.org/sites/default/files/DSP0270_1.0.1.pdf) Redfish Host Interface Specification NetworkHostInterface, /// OEM Defined OemDefined, /// A value unknown to this standard, check the raw value None, } /// # Management Controller Host Interface Type Data pub struct HostInterfaceTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [HostInterfaceType] value pub value: HostInterfaceType, } impl fmt::Debug for HostInterfaceTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for HostInterfaceTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("HostInterfaceTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for HostInterfaceTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { HostInterfaceType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for HostInterfaceTypeData { type Target = HostInterfaceType; fn deref(&self) -> &Self::Target { &self.value } } impl From for HostInterfaceType { fn from(raw: u8) -> Self { match raw { 0x02 => HostInterfaceType::KeyboardControllerStyle, 0x03 => HostInterfaceType::Uart8250, 0x04 => HostInterfaceType::Uart16450, 0x05 => HostInterfaceType::Uart16550, 0x06 => HostInterfaceType::Uart16650, 0x07 => HostInterfaceType::Uart16750, 0x08 => HostInterfaceType::Uart16850, 0x40 => HostInterfaceType::NetworkHostInterface, 0xF0 => HostInterfaceType::OemDefined, _ => HostInterfaceType::None, } } } impl From for HostInterfaceTypeData { fn from(raw: u8) -> Self { Self { raw, value: HostInterfaceType::from(raw), } } } /// # Management Controller Host Interface - Protocol Types #[derive(Serialize, Debug, PartialEq, Eq)] pub enum HostProtocolType { /// IPMI: Intelligent Platform Management Interface /// /// Refer to IPMI Appendix C1 Ipmi, /// MCTP: Management Component Transport Protocol /// /// Refer to DSP0236 for the definition and details of the MCTP protocol type Mctp, /// Redfish over IP /// /// Refer to [DSP0270](https://www.dmtf.org/sites/default/files/DSP0270_1.0.1.pdf) for the definition and details of the Redfish over IP protocol type RedfishOverIP, /// OEM Defined OemDefined, /// A value unknown to this standard, check the raw value None, } impl From for HostProtocolType { fn from(raw: u8) -> Self { match raw { 0x02 => HostProtocolType::Ipmi, 0x03 => HostProtocolType::Mctp, 0x04 => HostProtocolType::RedfishOverIP, 0xF0 => HostProtocolType::OemDefined, _ => HostProtocolType::None, } } } /// # Management Controller Host Interface - Protocol Types Data pub struct HostProtocolTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [HostProtocolType] value pub value: HostProtocolType, } impl From for HostProtocolTypeData { fn from(raw: u8) -> Self { Self { raw, value: HostProtocolType::from(raw), } } } impl fmt::Debug for HostProtocolTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for HostProtocolTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("HostProtocolTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for HostProtocolTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { HostProtocolType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for HostProtocolTypeData { type Target = HostProtocolType; fn deref(&self) -> &Self::Target { &self.value } } /// # Protocol Record Data contained within [SMBiosManagementControllerHostInterface] pub struct ProtocolRecord<'a> { host_interface: &'a SMBiosManagementControllerHostInterface<'a>, entry_offset: usize, } impl<'a> ProtocolRecord<'a> { const PROTOCOL_TYPE_OFFSET: usize = 0usize; const SPECIFIC_DATA_LENGTH_OFFSET: usize = 1usize; const SPECIFIC_DATA_OFFSET: usize = 2usize; fn new( host_interface: &'a SMBiosManagementControllerHostInterface<'a>, entry_offset: usize, ) -> Self { Self { host_interface, entry_offset, } } /// Protocol Type pub fn protocol_type(&self) -> Option { self.host_interface .parts() .get_field_byte(self.entry_offset + Self::PROTOCOL_TYPE_OFFSET) .map(|raw| HostProtocolTypeData::from(raw)) } /// Protocol Type Specific Data Length pub fn protocol_type_specific_data_length(&self) -> Option { self.host_interface .parts() .get_field_byte(self.entry_offset + Self::SPECIFIC_DATA_LENGTH_OFFSET) } /// Protocol Type Specific Data pub fn protocol_type_specific_data(&self) -> Option<&[u8]> { let start_index = self.entry_offset + Self::SPECIFIC_DATA_OFFSET; self.protocol_type_specific_data_length() .and_then(|length| { self.host_interface .parts() .get_field_data(start_index, start_index + length as usize) }) } } impl fmt::Debug for ProtocolRecord<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("protocol_type", &self.protocol_type()) .field( "protocol_type_specific_data_length", &self.protocol_type_specific_data_length(), ) .field( "protocol_type_specific_data", &self.protocol_type_specific_data(), ) .finish() } } impl Serialize for ProtocolRecord<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ProtocolRecord", 3)?; state.serialize_field("protocol_type", &self.protocol_type())?; state.serialize_field( "protocol_type_specific_data_length", &self.protocol_type_specific_data_length(), )?; state.serialize_field( "protocol_type_specific_data", &self.protocol_type_specific_data(), )?; state.end() } } /// Iterates over the [ProtocolRecord] entries contained within [SMBiosManagementControllerHostInterface] pub struct ProtocolRecordIterator<'a> { data: &'a SMBiosManagementControllerHostInterface<'a>, start_index: usize, current_index: usize, current_entry: u8, number_of_entries: u8, } impl<'a> ProtocolRecordIterator<'a> { fn new(data: &'a SMBiosManagementControllerHostInterface<'a>) -> Self { let start_index = data.protocol_records_offset().unwrap_or(0); ProtocolRecordIterator { data, start_index, current_index: start_index, current_entry: 0, number_of_entries: data.number_of_protocol_records().unwrap_or(0), } } fn reset(&mut self) { self.current_index = self.start_index; self.current_entry = 0; } } impl<'a> IntoIterator for &'a ProtocolRecordIterator<'a> { type Item = ProtocolRecord<'a>; type IntoIter = ProtocolRecordIterator<'a>; fn into_iter(self) -> Self::IntoIter { ProtocolRecordIterator { data: self.data, start_index: self.start_index, current_index: self.start_index, current_entry: 0, number_of_entries: self.data.number_of_protocol_records().unwrap_or(0), } } } impl<'a> Iterator for ProtocolRecordIterator<'a> { type Item = ProtocolRecord<'a>; fn next(&mut self) -> Option { if self.current_entry == self.number_of_entries { self.reset(); return None; } match self .data .parts() .get_field_byte(self.current_index + ProtocolRecord::SPECIFIC_DATA_LENGTH_OFFSET) { Some(specific_data_length) => { // Length of 0 would result in an endless loop because we would never advance to the next entry if specific_data_length == 0 { self.reset(); return None; } let next_index = self.current_index + specific_data_length as usize + ProtocolRecord::SPECIFIC_DATA_OFFSET; match self .data .parts() .get_field_data(self.current_index, next_index) { Some(_entry_block) => { let result = ProtocolRecord::new(self.data, self.current_index); self.current_index = next_index; self.current_entry += 1; Some(result) } None => { self.reset(); None } } } None => { self.reset(); None } } } } impl<'a> fmt::Debug for ProtocolRecordIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().entries(self.into_iter()).finish() } } impl<'a> Serialize for ProtocolRecordIterator<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let records: Vec> = self.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(records.len()))?; for e in records { seq.serialize_element(&e)?; } seq.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type42 = vec![ 42u8, 0x13, 0x24, 0x00, 0x02, 0x04, 0x01, 0x02, 0x03, 0x04, 0x02, 0x03, 0x01, 0xDD, 0x02, 0x01, 0xEE, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type42); let test_struct = SMBiosManagementControllerHostInterface::new(&parts); assert_eq!( *test_struct.interface_type().unwrap(), HostInterfaceType::KeyboardControllerStyle ); assert_eq!(test_struct.interface_type_specific_data_length(), Some(4)); assert_eq!( test_struct.interface_type_specific_data(), [1u8, 2, 3, 4].get(0..4) ); assert_eq!(test_struct.number_of_protocol_records(), Some(2)); let mut iterator = test_struct.protocol_record_iterator().into_iter(); let first = iterator.next().unwrap(); assert_eq!(*first.protocol_type().unwrap(), HostProtocolType::Mctp); let second = iterator.next().unwrap(); assert_eq!(*second.protocol_type().unwrap(), HostProtocolType::Ipmi); assert!(iterator.next().is_none()); } } smbios-lib-0.9.2/src/structs/types/management_device.rs000064400000000000000000000222261046102023000213430ustar 00000000000000use crate::core::{strings::*, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # Management Device (Type 34) /// /// The information in this structure defines the attributes of a Management Device. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosManagementDevice<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosManagementDevice<'a> { const STRUCT_TYPE: u8 = 34u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosManagementDevice<'a> { /// Additional descriptive information about the device or its location pub fn description(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Device's type pub fn device_type(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| ManagementDeviceTypeData::from(raw)) } /// Device's address pub fn address(&self) -> Option { self.parts.get_field_dword(0x06) } /// Type of addressing used to access the device pub fn address_type(&self) -> Option { self.parts .get_field_byte(0x0A) .map(|raw| ManagementDeviceAddressTypeData::from(raw)) } } impl fmt::Debug for SMBiosManagementDevice<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("description", &self.description()) .field("device_type", &self.device_type()) .field("address", &self.address()) .field("address_type", &self.address_type()) .finish() } } impl Serialize for SMBiosManagementDevice<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosManagementDevice", 5)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("description", &self.description())?; state.serialize_field("device_type", &self.device_type())?; state.serialize_field("address", &self.address())?; state.serialize_field("address_type", &self.address_type())?; state.end() } } /// # Management Device - Type Data pub struct ManagementDeviceTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [ManagementDeviceType] value pub value: ManagementDeviceType, } impl fmt::Debug for ManagementDeviceTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for ManagementDeviceTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ManagementDeviceTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for ManagementDeviceTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { ManagementDeviceType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for ManagementDeviceTypeData { type Target = ManagementDeviceType; fn deref(&self) -> &Self::Target { &self.value } } /// # Management Device - Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum ManagementDeviceType { /// Other Other, /// Unknown Unknown, /// National Semiconductor LM75 NationalSemiconductorLM75, /// National Semiconductor LM78 NationalSemiconductorLM78, /// National Semiconductor LM79 NationalSemiconductorLM79, /// National Semiconductor LM80 NationalSemiconductorLM80, /// National Semiconductor LM81 NationalSemiconductorLM81, /// Analog Devices ADM9240 AnalogDevicesADM9240, /// Dallas Semiconductor DS1780 DallasSemiconductorDS1780, /// Maxim 1617 Maxim1617, /// Genesys GL518SM GenesysGL518SM, /// Winbond W83781D WinbondW83781D, /// Holtek HT82H791 HoltekHT82H791, /// A value unknown to this standard, check the raw value None, } impl From for ManagementDeviceTypeData { fn from(raw: u8) -> Self { ManagementDeviceTypeData { value: match raw { 0x01 => ManagementDeviceType::Other, 0x02 => ManagementDeviceType::Unknown, 0x03 => ManagementDeviceType::NationalSemiconductorLM75, 0x04 => ManagementDeviceType::NationalSemiconductorLM78, 0x05 => ManagementDeviceType::NationalSemiconductorLM79, 0x06 => ManagementDeviceType::NationalSemiconductorLM80, 0x07 => ManagementDeviceType::NationalSemiconductorLM81, 0x08 => ManagementDeviceType::AnalogDevicesADM9240, 0x09 => ManagementDeviceType::DallasSemiconductorDS1780, 0x0A => ManagementDeviceType::Maxim1617, 0x0B => ManagementDeviceType::GenesysGL518SM, 0x0C => ManagementDeviceType::WinbondW83781D, 0x0D => ManagementDeviceType::HoltekHT82H791, _ => ManagementDeviceType::None, }, raw, } } } /// # Management Device — Address Type Data pub struct ManagementDeviceAddressTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [ManagementDeviceAddressType] value pub value: ManagementDeviceAddressType, } impl fmt::Debug for ManagementDeviceAddressTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for ManagementDeviceAddressTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ManagementDeviceAddressTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for ManagementDeviceAddressTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { ManagementDeviceAddressType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for ManagementDeviceAddressTypeData { type Target = ManagementDeviceAddressType; fn deref(&self) -> &Self::Target { &self.value } } /// # Management Device — Address Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum ManagementDeviceAddressType { /// Other Other, /// Unknown Unknown, /// I/O Port IOPort, /// Memory Memory, /// SM Bus SMBus, /// A value unknown to this standard, check the raw value None, } impl From for ManagementDeviceAddressTypeData { fn from(raw: u8) -> Self { ManagementDeviceAddressTypeData { value: match raw { 0x01 => ManagementDeviceAddressType::Other, 0x02 => ManagementDeviceAddressType::Unknown, 0x03 => ManagementDeviceAddressType::IOPort, 0x04 => ManagementDeviceAddressType::Memory, 0x05 => ManagementDeviceAddressType::SMBus, _ => ManagementDeviceAddressType::None, }, raw, } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type34 = vec![ 0x22, 0x0B, 0x26, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x4C, 0x4D, 0x37, 0x38, 0x2D, 0x31, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type34); let test_struct = SMBiosManagementDevice::new(&parts); assert_eq!(test_struct.description().to_string(), "LM78-1".to_string()); assert_eq!( *test_struct.device_type().unwrap(), ManagementDeviceType::NationalSemiconductorLM78 ); assert_eq!(test_struct.address(), Some(0)); assert_eq!( *test_struct.address_type().unwrap(), ManagementDeviceAddressType::IOPort ); } } smbios-lib-0.9.2/src/structs/types/management_device_component.rs000064400000000000000000000072771046102023000234360ustar 00000000000000use crate::core::{strings::*, Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Management Device Component (Type 35) /// /// This structure associates a cooling device or environmental probe with structures that define the /// controlling hardware device and (optionally) the component’s thresholds. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosManagementDeviceComponent<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosManagementDeviceComponent<'a> { const STRUCT_TYPE: u8 = 35u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosManagementDeviceComponent<'a> { /// Number of the string that contains additional descriptive information about the component pub fn description(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Handle, or instance number, of the Management Device that contains this component pub fn management_device_handle(&self) -> Option { self.parts.get_field_handle(0x05) } /// Handle, or instance number, of the probe or cooling device that defines this component pub fn component_handle(&self) -> Option { self.parts.get_field_handle(0x07) } /// Handle, or instance number, associated with the device /// thresholds; /// A value of 0FFFFh indicates that no Threshold Data /// structure is associated with this component. pub fn threshold_handle(&self) -> Option { self.parts.get_field_handle(0x09) } } impl fmt::Debug for SMBiosManagementDeviceComponent<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("description", &self.description()) .field("management_device_handle", &self.management_device_handle()) .field("component_handle", &self.component_handle()) .field("threshold_handle", &self.threshold_handle()) .finish() } } impl Serialize for SMBiosManagementDeviceComponent<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosManagementDeviceComponent", 5)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("description", &self.description())?; state.serialize_field("management_device_handle", &self.management_device_handle())?; state.serialize_field("component_handle", &self.component_handle())?; state.serialize_field("threshold_handle", &self.threshold_handle())?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type35 = vec![ 0x23, 0x0B, 0x29, 0x00, 0x01, 0x26, 0x00, 0x27, 0x00, 0x28, 0x00, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type35); let test_struct = SMBiosManagementDeviceComponent::new(&parts); assert_eq!( test_struct.description().to_string(), "Default string".to_string() ); assert_eq!(*test_struct.management_device_handle().unwrap(), 38); assert_eq!(*test_struct.component_handle().unwrap(), 39); assert_eq!(*test_struct.threshold_handle().unwrap(), 40); } } smbios-lib-0.9.2/src/structs/types/management_device_threshold_data.rs000064400000000000000000000120151046102023000244030ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Management Device Threshold Data (Type 36) /// /// The information in this structure defines threshold information for a component (probe or cooling-unit) contained within a Management Device /// /// For each threshold field present in the structure: /// - The threshold units (millivolts, milliamps, 1/10th degrees C, or RPMs) are as defined by the associated probe or cooling-unit component structure. /// - If the value is unavailable, the field is set to 0x8000. /// /// NOTE This structure type was added in version 2.3 of this specification. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosManagementDeviceThresholdData<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosManagementDeviceThresholdData<'a> { const STRUCT_TYPE: u8 = 36u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosManagementDeviceThresholdData<'a> { /// Lower non-critical threshold for this component pub fn lower_threshold_non_critical(&self) -> Option { self.parts.get_field_word(0x04) } /// Upper non-critical threshold for this component pub fn upper_threshold_non_critical(&self) -> Option { self.parts.get_field_word(0x06) } /// Lower critical threshold for this component pub fn lower_threshold_critical(&self) -> Option { self.parts.get_field_word(0x08) } /// Upper critical threshold for this component pub fn upper_threshold_critical(&self) -> Option { self.parts.get_field_word(0x0A) } /// Lower non-recoverable threshold for this component pub fn lower_threshold_non_recoverable(&self) -> Option { self.parts.get_field_word(0x0C) } /// Upper non-recoverable threshold for this component pub fn upper_threshold_non_recoverable(&self) -> Option { self.parts.get_field_word(0x0E) } } impl fmt::Debug for SMBiosManagementDeviceThresholdData<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field( "lower_threshold_non_critical", &self.lower_threshold_non_critical(), ) .field( "upper_threshold_non_critical", &self.upper_threshold_non_critical(), ) .field("lower_threshold_critical", &self.lower_threshold_critical()) .field("upper_threshold_critical", &self.upper_threshold_critical()) .field( "lower_threshold_non_recoverable", &self.lower_threshold_non_recoverable(), ) .field( "upper_threshold_non_recoverable", &self.upper_threshold_non_recoverable(), ) .finish() } } impl Serialize for SMBiosManagementDeviceThresholdData<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosManagementDeviceThresholdData", 7)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field( "lower_threshold_non_critical", &self.lower_threshold_non_critical(), )?; state.serialize_field( "upper_threshold_non_critical", &self.upper_threshold_non_critical(), )?; state.serialize_field("lower_threshold_critical", &self.lower_threshold_critical())?; state.serialize_field("upper_threshold_critical", &self.upper_threshold_critical())?; state.serialize_field( "lower_threshold_non_recoverable", &self.lower_threshold_non_recoverable(), )?; state.serialize_field( "upper_threshold_non_recoverable", &self.upper_threshold_non_recoverable(), )?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type36 = vec![ 0x24, 0x10, 0x28, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type36); let test_struct = SMBiosManagementDeviceThresholdData::new(&parts); assert_eq!(test_struct.lower_threshold_non_critical(), Some(1)); assert_eq!(test_struct.upper_threshold_non_critical(), Some(2)); assert_eq!(test_struct.lower_threshold_critical(), Some(3)); assert_eq!(test_struct.upper_threshold_critical(), Some(4)); assert_eq!(test_struct.lower_threshold_non_recoverable(), Some(5)); assert_eq!(test_struct.upper_threshold_non_recoverable(), Some(6)); } } smbios-lib-0.9.2/src/structs/types/memory_array_mapped_address.rs000064400000000000000000000141561046102023000234540ustar 00000000000000use crate::core::{Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Memory Array Mapped Address (Type 19) /// /// This structure provides the address mapping for a Physical Memory Array. /// /// One structure is present for each contiguous address range described. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosMemoryArrayMappedAddress<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosMemoryArrayMappedAddress<'a> { const STRUCT_TYPE: u8 = 19u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosMemoryArrayMappedAddress<'a> { /// Physical address, in kilobytes, of a range of /// memory mapped to the specified Physical Memory /// Array /// When the field value is FFFF FFFFh, the actual /// address is stored in the Extended Starting /// Address field. When this field contains a valid /// address, Ending Address must also contain a valid /// address. When this field contains FFFF FFFFh, /// Ending Address must also contain FFFF FFFFh. pub fn starting_address(&self) -> Option { self.parts.get_field_dword(0x4) } /// Physical ending address of the last kilobyte of a /// range of addresses mapped to the specified /// Physical Memory Array /// When the field value is FFFF FFFFh and the /// Starting Address field also contains FFFF FFFFh, /// the actual address is stored in the Extended /// Ending Address field. When this field contains a /// valid address, Starting Address must also contain /// a valid address. pub fn ending_address(&self) -> Option { self.parts.get_field_dword(0x8) } /// Handle, or instance number, associated with the /// Physical Memory Array to which this address /// range is mapped /// Multiple address ranges can be mapped to a /// single Physical Memory Array. pub fn physical_memory_array_handle(&self) -> Option { self.parts.get_field_handle(0xC) } /// Number of Memory Devices that form a single row /// of memory for the address partition defined by this /// structure pub fn partition_width(&self) -> Option { self.parts.get_field_byte(0xE) } /// Physical address, in bytes, of a range of memory /// mapped to the specified Physical Memory Array /// This field is valid when Starting Address contains /// the value FFFF FFFFh. If Starting Address /// contains a value other than FFFF FFFFh, this field /// contains zeros. When this field contains a valid /// address, Extended Ending Address must also /// contain a valid address. pub fn extended_starting_address(&self) -> Option { self.parts.get_field_qword(0xF) } /// Physical ending address, in bytes, of the last of a /// range of addresses mapped to the specified /// Physical Memory Array /// This field is valid when both Starting Address and /// Ending Address contain the value FFFF FFFFh. If /// Ending Address contains a value other than FFFF /// FFFFh, this field contains zeros. When this field /// contains a valid address, Extended Starting /// Address must also contain a valid address. pub fn extended_ending_address(&self) -> Option { self.parts.get_field_qword(0x17) } } impl fmt::Debug for SMBiosMemoryArrayMappedAddress<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("starting_address", &self.starting_address()) .field("ending_address", &self.ending_address()) .field( "physical_memory_array_handle", &self.physical_memory_array_handle(), ) .field("partition_width", &self.partition_width()) .field( "extended_starting_address", &self.extended_starting_address(), ) .field("extended_ending_address", &self.extended_ending_address()) .finish() } } impl Serialize for SMBiosMemoryArrayMappedAddress<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosMemoryArrayMappedAddress", 7)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("starting_address", &self.starting_address())?; state.serialize_field("ending_address", &self.ending_address())?; state.serialize_field( "physical_memory_array_handle", &self.physical_memory_array_handle(), )?; state.serialize_field("partition_width", &self.partition_width())?; state.serialize_field( "extended_starting_address", &self.extended_starting_address(), )?; state.serialize_field("extended_ending_address", &self.extended_ending_address())?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type19 = vec![ 0x13, 0x1F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x3E, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type19); let test_struct = SMBiosMemoryArrayMappedAddress::new(&parts); assert_eq!(test_struct.starting_address(), Some(0)); assert_eq!(test_struct.ending_address(), Some(16777215)); assert_eq!(*test_struct.physical_memory_array_handle().unwrap(), 62); assert_eq!(test_struct.partition_width(), Some(4)); assert_eq!(test_struct.extended_starting_address(), Some(0)); assert_eq!(test_struct.extended_ending_address(), Some(0)); } } smbios-lib-0.9.2/src/structs/types/memory_channel.rs000064400000000000000000000250131046102023000207050ustar 00000000000000use crate::core::{Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # Memory Channel (Type 37) /// /// The information in this structure provides the correlation between a Memory Channel and its associated [super::SMBiosMemoryDevice]s. /// /// Each device presents one or more loads to the channel; the sum of all device loads cannot exceed the channel’s defined maximum. /// /// NOTE This structure type was added in version 2.3 of this specification. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosMemoryChannel<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosMemoryChannel<'a> { const STRUCT_TYPE: u8 = 37u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosMemoryChannel<'a> { /// Type of memory associated with the channel pub fn channel_type(&self) -> Option { self.parts .get_field_byte(0x04) .map(|raw| MemoryChannelTypeData::from(raw)) } /// Maximum load supported by the channel; the sum of all /// device loads cannot exceed this value pub fn maximum_channel_load(&self) -> Option { self.parts.get_field_byte(0x05) } /// Number of [super::SMBiosMemoryDevice]s (Type 11h) that are /// associated with this channel /// /// This value also defines the number of Load/Handle pairs /// that follow. pub fn memory_device_count(&self) -> Option { self.parts.get_field_byte(0x06) } /// Load/Handle pairs defining the [super::SMBiosMemoryDevice]s /// associated with this memory channel. pub fn load_handle_pairs_iterator(&self) -> LoadHandlePairIterator<'_> { LoadHandlePairIterator::new(self) } } impl fmt::Debug for SMBiosMemoryChannel<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("channel_type", &self.channel_type()) .field("maximum_channel_load", &self.maximum_channel_load()) .field("memory_device_count", &self.memory_device_count()) .field( "load_handle_pairs_iterator", &self.load_handle_pairs_iterator(), ) .finish() } } impl Serialize for SMBiosMemoryChannel<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosMemoryChannel", 5)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("channel_type", &self.channel_type())?; state.serialize_field("maximum_channel_load", &self.maximum_channel_load())?; state.serialize_field("memory_device_count", &self.memory_device_count())?; state.serialize_field( "load_handle_pairs_iterator", &self.load_handle_pairs_iterator(), )?; state.end() } } /// # Memory Channel — Channel Type Data pub struct MemoryChannelTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [MemoryChannelType] value pub value: MemoryChannelType, } impl fmt::Debug for MemoryChannelTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for MemoryChannelTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryChannelTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for MemoryChannelTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { MemoryChannelType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for MemoryChannelTypeData { type Target = MemoryChannelType; fn deref(&self) -> &Self::Target { &self.value } } /// # Memory Channel — Channel Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemoryChannelType { /// Other, Other, /// Unknown, Unknown, /// RamBus, RamBus, /// SyncLink, SyncLink, /// A value unknown to this standard, check the raw value None, } impl From for MemoryChannelTypeData { fn from(raw: u8) -> Self { MemoryChannelTypeData { value: match raw { 0x01 => MemoryChannelType::Other, 0x02 => MemoryChannelType::Unknown, 0x03 => MemoryChannelType::RamBus, 0x04 => MemoryChannelType::SyncLink, _ => MemoryChannelType::None, }, raw, } } } /// # Load/Handle Pair contained within [SMBiosMemoryChannel] pub struct LoadHandlePair<'a> { memory_channel: &'a SMBiosMemoryChannel<'a>, entry_offset: usize, } impl<'a> LoadHandlePair<'a> { /// Size in bytes of a LoadHandlePair const SIZE: usize = 3usize; fn new(memory_channel: &'a SMBiosMemoryChannel<'a>, entry_offset: usize) -> Self { Self { memory_channel, entry_offset, } } /// Channel load provided by the [super::SMBiosMemoryDevice] associated with this channel pub fn load(&self) -> Option { self.memory_channel .parts() .get_field_byte(self.entry_offset) } /// Structure handle that identifies the [super::SMBiosMemoryDevice] associated with this channel pub fn handle(&self) -> Option { self.memory_channel .parts() .get_field_handle(self.entry_offset + 1) } } impl fmt::Debug for LoadHandlePair<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("load", &self.load()) .field("handle", &self.handle()) .finish() } } impl Serialize for LoadHandlePair<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("LoadHandlePair", 2)?; state.serialize_field("load", &self.load())?; state.serialize_field("handle", &self.handle())?; state.end() } } /// Iterates over the [LoadHandlePair] entries contained within [SMBiosMemoryChannel] pub struct LoadHandlePairIterator<'a> { data: &'a SMBiosMemoryChannel<'a>, current_index: usize, current_entry: u8, number_of_entries: u8, } impl<'a> LoadHandlePairIterator<'a> { const LOAD_HANDLE_PAIRS_OFFSET: usize = 7usize; fn new(data: &'a SMBiosMemoryChannel<'a>) -> Self { LoadHandlePairIterator { data: data, current_index: Self::LOAD_HANDLE_PAIRS_OFFSET, current_entry: 0, number_of_entries: data.memory_device_count().unwrap_or(0), } } fn reset(&mut self) { self.current_index = Self::LOAD_HANDLE_PAIRS_OFFSET; self.current_entry = 0; } } impl<'a> IntoIterator for &'a LoadHandlePairIterator<'a> { type Item = LoadHandlePair<'a>; type IntoIter = LoadHandlePairIterator<'a>; fn into_iter(self) -> Self::IntoIter { LoadHandlePairIterator { data: self.data, current_index: LoadHandlePairIterator::LOAD_HANDLE_PAIRS_OFFSET, current_entry: 0, number_of_entries: self.data.memory_device_count().unwrap_or(0), } } } impl<'a> Iterator for LoadHandlePairIterator<'a> { type Item = LoadHandlePair<'a>; fn next(&mut self) -> Option { if self.current_entry == self.number_of_entries { self.reset(); return None; } let next_index = self.current_index + LoadHandlePair::SIZE; match self .data .parts() .get_field_data(self.current_index, next_index) { Some(_entry_block) => { let result = LoadHandlePair::new(self.data, self.current_index); self.current_index = next_index; self.current_entry += 1; Some(result) } None => { self.reset(); None } } } } impl<'a> fmt::Debug for LoadHandlePairIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().entries(self.into_iter()).finish() } } impl<'a> Serialize for LoadHandlePairIterator<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let pairs: Vec> = self.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(pairs.len()))?; for e in pairs { seq.serialize_element(&e)?; } seq.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type37 = vec![ 37u8, 0x0D, 0x3F, 0x00, 0x03, 0x30, 0x02, 0x01, 0x02, 0x00, 0x03, 0x04, 0x00, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type37); let test_struct = SMBiosMemoryChannel::new(&parts); assert_eq!( *test_struct.channel_type().unwrap(), MemoryChannelType::RamBus ); assert_eq!(test_struct.maximum_channel_load(), Some(0x30)); assert_eq!(test_struct.memory_device_count(), Some(2)); let mut iterator = test_struct.load_handle_pairs_iterator().into_iter(); let first = iterator.next().unwrap(); assert_eq!(first.load(), Some(1)); assert_eq!(*first.handle().unwrap(), 2); let second = iterator.next().unwrap(); assert_eq!(second.load(), Some(3)); assert_eq!(*second.handle().unwrap(), 4); assert!(iterator.next().is_none()); } } smbios-lib-0.9.2/src/structs/types/memory_controller_information.rs000064400000000000000000000670611046102023000240760ustar 00000000000000use crate::core::{Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # Memory Controller Information (Type 5, Obsolete) /// /// The information in this structure defines the attributes of the system’s memory controller(s) and the /// supported attributes of any memory-modules present in the sockets controlled by this controller. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosMemoryControllerInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosMemoryControllerInformation<'a> { const STRUCT_TYPE: u8 = 5u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosMemoryControllerInformation<'a> { /// Error detecting method pub fn error_detecting_method(&self) -> Option { self.parts .get_field_byte(0x04) .map(|raw| ErrorDetectingMethodData::from(raw)) } /// Error correcting capability pub fn error_correcting_capability(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| ErrorCorrectingCapabilities::from(raw)) } /// Supported interleave pub fn supported_interleave(&self) -> Option { self.parts .get_field_byte(0x06) .map(|raw| InterleaveSupportData::from(raw)) } /// Current interleave pub fn current_interleave(&self) -> Option { self.parts .get_field_byte(0x07) .map(|raw| InterleaveSupportData::from(raw)) } /// Maximum Memory Module Size /// /// Size of the largest memory module supported (per slot), /// specified as n, where 2**n is the maximum size in MB /// /// The maximum amount of memory supported by this controller /// is that value times the number of slots, as specified in /// offset 0Eh of this structure. pub fn maximum_memory_module_size(&self) -> Option { self.parts.get_field_byte(0x08) } /// Supported Speeds pub fn supported_speeds(&self) -> Option { self.parts .get_field_word(0x09) .map(|raw| MemorySpeeds::from(raw)) } /// Supported Memory Types pub fn supported_memory_types(&self) -> Option { self.parts .get_field_word(0x0B) .map(|raw| MemoryTypes::from(raw)) } /// Memory Module Voltage pub fn memory_module_voltage(&self) -> Option { self.parts .get_field_byte(0x0D) .map(|raw| ModuleVoltage::from(raw)) } /// Number of Associated Memory Slots pub fn number_of_associated_memory_slots(&self) -> Option { self.parts.get_field_byte(0x0E) } /// Memory Module Configuration Handles pub fn memory_module_handle_iterator(&self) -> ModuleHandleIterator<'_> { ModuleHandleIterator::new(self) } /// Memory Moduel Error Correcting Capabilities pub fn error_correcting_capabilities_iterator(&self) -> ErrorCapabilitiesIterator<'_> { ErrorCapabilitiesIterator::new(self) } } impl fmt::Debug for SMBiosMemoryControllerInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("error_detecting_method", &self.error_detecting_method()) .field( "error_correcting_capability", &self.error_correcting_capability(), ) .field("supported_interleave", &self.supported_interleave()) .field("current_interleave", &self.current_interleave()) .field( "maximum_memory_module_size", &self.maximum_memory_module_size(), ) .field("supported_speeds", &self.supported_speeds()) .field("supported_memory_types", &self.supported_memory_types()) .field("memory_module_voltage", &self.memory_module_voltage()) .field( "number_of_associated_memory_slots", &self.number_of_associated_memory_slots(), ) .field( "memory_module_handle_iterator", &self.memory_module_handle_iterator(), ) .field( "error_correcting_capabilities_iterator", &self.error_correcting_capabilities_iterator(), ) .finish() } } impl Serialize for SMBiosMemoryControllerInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosMemoryControllerInformation", 12)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("error_detecting_method", &self.error_detecting_method())?; state.serialize_field( "error_correcting_capability", &self.error_correcting_capability(), )?; state.serialize_field("supported_interleave", &self.supported_interleave())?; state.serialize_field("current_interleave", &self.current_interleave())?; state.serialize_field( "maximum_memory_module_size", &self.maximum_memory_module_size(), )?; state.serialize_field("supported_speeds", &self.supported_speeds())?; state.serialize_field("supported_memory_types", &self.supported_memory_types())?; state.serialize_field("memory_module_voltage", &self.memory_module_voltage())?; state.serialize_field( "number_of_associated_memory_slots", &self.number_of_associated_memory_slots(), )?; state.serialize_field( "memory_module_handle_iterator", &self.memory_module_handle_iterator(), )?; state.serialize_field( "error_correcting_capabilities_iterator", &self.error_correcting_capabilities_iterator(), )?; state.end() } } /// # Memory Controller Error Detecting Method Data pub struct ErrorDetectingMethodData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [ErrorDetectingMethod] value pub value: ErrorDetectingMethod, } impl fmt::Debug for ErrorDetectingMethodData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for ErrorDetectingMethodData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ErrorDetectingMethodData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for ErrorDetectingMethodData { type Target = ErrorDetectingMethod; fn deref(&self) -> &Self::Target { &self.value } } /// # Memory Controller Error Detecting Method #[derive(Serialize, Debug, PartialEq, Eq)] pub enum ErrorDetectingMethod { /// Other Other, /// Unknown Unknown, /// No Error Detection NoErrorDetection, /// 8-bit Parity Parity8Bit, /// 32-bit ECC Ecc32Bit, /// 64-bit ECC Ecc64Bit, /// 128-bit ECC Ecc128Bit, /// CRC Crc, /// A value unknown to this standard, check the raw value None, } impl From for ErrorDetectingMethodData { fn from(raw: u8) -> Self { ErrorDetectingMethodData { value: match raw { 0x01 => ErrorDetectingMethod::Other, 0x02 => ErrorDetectingMethod::Unknown, 0x03 => ErrorDetectingMethod::NoErrorDetection, 0x04 => ErrorDetectingMethod::Parity8Bit, 0x05 => ErrorDetectingMethod::Ecc32Bit, 0x06 => ErrorDetectingMethod::Ecc64Bit, 0x07 => ErrorDetectingMethod::Ecc128Bit, 0x08 => ErrorDetectingMethod::Crc, _ => ErrorDetectingMethod::None, }, raw, } } } /// # Memory Controller Error Correcting Capability #[derive(PartialEq, Eq)] pub struct ErrorCorrectingCapabilities { /// Raw value pub raw: u8, } impl Deref for ErrorCorrectingCapabilities { type Target = u8; fn deref(&self) -> &Self::Target { &self.raw } } impl From for ErrorCorrectingCapabilities { fn from(raw: u8) -> Self { ErrorCorrectingCapabilities { raw } } } impl ErrorCorrectingCapabilities { /// ErrorCorrectingCapabilities Size (1 byte) pub const SIZE: usize = 1usize; /// Other pub fn other(&self) -> bool { self.raw & 0x01 == 0x01 } /// Unknown pub fn unknown(&self) -> bool { self.raw & 0x02 == 0x02 } /// None pub fn no_capabilities(&self) -> bool { self.raw & 0x04 == 0x04 } /// Single-Bit Error Correcting pub fn single_bit_error_correcting(&self) -> bool { self.raw & 0x08 == 0x08 } /// Double-Bit Error Correcting pub fn double_bit_error_correcting(&self) -> bool { self.raw & 0x10 == 0x10 } /// Error Scrubbing pub fn error_scrubbing(&self) -> bool { self.raw & 0x20 == 0x20 } } impl fmt::Debug for ErrorCorrectingCapabilities { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("other", &self.other()) .field("unknown", &self.unknown()) .field("no_capabilities", &self.no_capabilities()) .field( "single_bit_error_correcting", &self.single_bit_error_correcting(), ) .field( "double_bit_error_correcting", &self.double_bit_error_correcting(), ) .field("error_scrubbing", &self.error_scrubbing()) .finish() } } impl Serialize for ErrorCorrectingCapabilities { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ErrorCorrectingCapabilities", 7)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("other", &self.other())?; state.serialize_field("unknown", &self.unknown())?; state.serialize_field("no_capabilities", &self.no_capabilities())?; state.serialize_field( "single_bit_error_correcting", &self.single_bit_error_correcting(), )?; state.serialize_field( "double_bit_error_correcting", &self.double_bit_error_correcting(), )?; state.serialize_field("error_scrubbing", &self.error_scrubbing())?; state.end() } } /// # Memory Controller Information — Interleave Support Data pub struct InterleaveSupportData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [InterleaveSupport] value pub value: InterleaveSupport, } impl fmt::Debug for InterleaveSupportData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for InterleaveSupportData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("InterleaveSupportData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for InterleaveSupportData { type Target = InterleaveSupport; fn deref(&self) -> &Self::Target { &self.value } } /// # Memory Controller Information — Interleave Support #[derive(Serialize, Debug, PartialEq, Eq)] pub enum InterleaveSupport { /// Other Other, /// Unknown Unknown, /// One-Way Interleave OneWay, /// Two-Way Interleave TwoWay, /// Four-Way Interleave FourWay, /// Eight-Way Interleave EightWay, /// Sixteen-Way Interleave SixteenWay, /// A value unknown to this standard, check the raw value None, } impl From for InterleaveSupportData { fn from(raw: u8) -> Self { InterleaveSupportData { value: match raw { 0x01 => InterleaveSupport::Other, 0x02 => InterleaveSupport::Unknown, 0x03 => InterleaveSupport::OneWay, 0x04 => InterleaveSupport::TwoWay, 0x05 => InterleaveSupport::FourWay, 0x06 => InterleaveSupport::EightWay, 0x07 => InterleaveSupport::SixteenWay, _ => InterleaveSupport::None, }, raw, } } } /// # Memory Controller Information — Memory Speeds #[derive(PartialEq, Eq)] pub struct MemorySpeeds { /// Raw value pub raw: u16, } impl Deref for MemorySpeeds { type Target = u16; fn deref(&self) -> &Self::Target { &self.raw } } impl From for MemorySpeeds { fn from(raw: u16) -> Self { MemorySpeeds { raw } } } impl MemorySpeeds { /// Other pub fn other(&self) -> bool { self.raw & 0x01 == 0x01 } /// Unknown pub fn unknown(&self) -> bool { self.raw & 0x02 == 0x02 } /// 70ns pub fn ns70(&self) -> bool { self.raw & 0x04 == 0x04 } /// 60ns pub fn ns60(&self) -> bool { self.raw & 0x08 == 0x08 } /// 50ns pub fn ns50(&self) -> bool { self.raw & 0x10 == 0x10 } } impl fmt::Debug for MemorySpeeds { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("other", &self.other()) .field("unknown", &self.unknown()) .field("ns70", &self.ns70()) .field("ns60", &self.ns60()) .field("ns50", &self.ns50()) .finish() } } impl Serialize for MemorySpeeds { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemorySpeeds", 6)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("other", &self.other())?; state.serialize_field("unknown", &self.unknown())?; state.serialize_field("ns70", &self.ns70())?; state.serialize_field("ns60", &self.ns60())?; state.serialize_field("ns50", &self.ns50())?; state.end() } } /// # Memory Module Information: Memory Types #[derive(PartialEq, Eq)] pub struct MemoryTypes { /// Raw value pub raw: u16, } impl Deref for MemoryTypes { type Target = u16; fn deref(&self) -> &Self::Target { &self.raw } } impl From for MemoryTypes { fn from(raw: u16) -> Self { MemoryTypes { raw } } } impl MemoryTypes { /// Bit 0 Other pub fn other(&self) -> bool { self.raw & 0x0001 == 0x0001 } /// Bit 1 Unknown pub fn unknown(&self) -> bool { self.raw & 0x0002 == 0x0002 } /// Bit 2 Standard pub fn standard(&self) -> bool { self.raw & 0x0004 == 0x0004 } /// Bit 3 Fast Page Mode pub fn fast_page_mode(&self) -> bool { self.raw & 0x0008 == 0x0008 } /// Bit 4 EDO pub fn edo(&self) -> bool { self.raw & 0x0010 == 0x0010 } /// Bit 5 Parity pub fn parity(&self) -> bool { self.raw & 0x0020 == 0x0020 } /// Bit 6 ECC pub fn ecc(&self) -> bool { self.raw & 0x0040 == 0x0040 } /// Bit 7 SIMM pub fn simm(&self) -> bool { self.raw & 0x0080 == 0x0080 } /// Bit 8 DIMM pub fn dimm(&self) -> bool { self.raw & 0x0100 == 0x0100 } /// Bit 9 Burst EDO pub fn burst_edo(&self) -> bool { self.raw & 0x0200 == 0x0200 } /// Bit 10 SDRAM pub fn sdram(&self) -> bool { self.raw & 0x0400 == 0x0400 } } impl fmt::Debug for MemoryTypes { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("other", &self.other()) .field("unknown", &self.unknown()) .field("standard", &self.standard()) .field("fast_page_mode", &self.fast_page_mode()) .field("edo", &self.edo()) .field("parity", &self.parity()) .field("ecc", &self.ecc()) .field("simm", &self.simm()) .field("dimm", &self.dimm()) .field("burst_edo", &self.burst_edo()) .field("sdram", &self.sdram()) .finish() } } impl Serialize for MemoryTypes { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryTypes", 12)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("other", &self.other())?; state.serialize_field("unknown", &self.unknown())?; state.serialize_field("standard", &self.standard())?; state.serialize_field("fast_page_mode", &self.fast_page_mode())?; state.serialize_field("edo", &self.edo())?; state.serialize_field("parity", &self.parity())?; state.serialize_field("ecc", &self.ecc())?; state.serialize_field("simm", &self.simm())?; state.serialize_field("dimm", &self.dimm())?; state.serialize_field("burst_edo", &self.burst_edo())?; state.serialize_field("sdram", &self.sdram())?; state.end() } } /// # Memory Module Voltage #[derive(PartialEq, Eq)] pub struct ModuleVoltage { /// Raw value pub raw: u8, } impl Deref for ModuleVoltage { type Target = u8; fn deref(&self) -> &Self::Target { &self.raw } } impl From for ModuleVoltage { fn from(raw: u8) -> Self { ModuleVoltage { raw } } } impl ModuleVoltage { /// Bit 0 5V pub fn volts_5(&self) -> bool { self.raw & 0x0001 == 0x0001 } /// Bit 1 3.3V pub fn volts_3_3(&self) -> bool { self.raw & 0x0002 == 0x0002 } /// Bit 2 2.9V pub fn volts_2_9(&self) -> bool { self.raw & 0x0004 == 0x0004 } } impl fmt::Debug for ModuleVoltage { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("volts_5", &self.volts_5()) .field("volts_3_3", &self.volts_3_3()) .field("volts_2_9", &self.volts_2_9()) .finish() } } impl Serialize for ModuleVoltage { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ModuleVoltage", 4)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("volts_5", &self.volts_5())?; state.serialize_field("volts_3_3", &self.volts_3_3())?; state.serialize_field("volts_2_9", &self.volts_2_9())?; state.end() } } /// # Memory Module Handle Iterator /// /// Iterates over the memory module handles contained within the [SMBiosMemoryControllerInformation] structure pub struct ModuleHandleIterator<'a> { data: &'a SMBiosMemoryControllerInformation<'a>, current_index: usize, current_entry: u8, number_of_handles: u8, } impl<'a> ModuleHandleIterator<'a> { const MODULE_HANDLES_OFFSET: usize = 0x0Fusize; /// Creates an instance of the memory module handle iterator. pub fn new(data: &'a SMBiosMemoryControllerInformation<'a>) -> Self { ModuleHandleIterator { data: data, current_index: Self::MODULE_HANDLES_OFFSET, current_entry: 0, number_of_handles: data.number_of_associated_memory_slots().unwrap_or(0), } } fn reset(&mut self) { self.current_index = Self::MODULE_HANDLES_OFFSET; self.current_entry = 0; } } impl<'a> IntoIterator for &'a ModuleHandleIterator<'a> { type Item = Handle; type IntoIter = ModuleHandleIterator<'a>; fn into_iter(self) -> Self::IntoIter { ModuleHandleIterator { data: self.data, current_index: ModuleHandleIterator::MODULE_HANDLES_OFFSET, current_entry: 0, number_of_handles: self.data.number_of_associated_memory_slots().unwrap_or(0), } } } impl<'a> Iterator for ModuleHandleIterator<'a> { type Item = Handle; fn next(&mut self) -> Option { if self.current_entry == self.number_of_handles { self.reset(); return None; } match self.data.parts().get_field_handle(self.current_index) { Some(current_handle) => { self.current_index = self.current_index + Handle::SIZE; self.current_entry += 1; Some(current_handle) } None => { self.reset(); None } } } } impl<'a> fmt::Debug for ModuleHandleIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().entries(self.into_iter()).finish() } } impl<'a> Serialize for ModuleHandleIterator<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let handles: Vec = self.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(handles.len()))?; for e in handles { seq.serialize_element(&e)?; } seq.end() } } /// # Memory Module Error Correcting Capabilities Iterator /// /// Iterates over the memory module error correcting capabilities /// contained within the [SMBiosMemoryControllerInformation] structure pub struct ErrorCapabilitiesIterator<'a> { data: &'a SMBiosMemoryControllerInformation<'a>, start_index: usize, current_index: usize, current_entry: u8, number_of_items: u8, } impl<'a> ErrorCapabilitiesIterator<'a> { /// Creates an instance of the memory module error correcting capabilities iterator. pub fn new(data: &'a SMBiosMemoryControllerInformation<'a>) -> Self { let number_of_items = data.number_of_associated_memory_slots().unwrap_or(0); let start_index = number_of_items as usize * Handle::SIZE + ModuleHandleIterator::MODULE_HANDLES_OFFSET; ErrorCapabilitiesIterator { data, start_index, current_index: start_index, current_entry: 0, number_of_items, } } fn reset(&mut self) { self.current_index = self.start_index; self.current_entry = 0; } } impl<'a> IntoIterator for &'a ErrorCapabilitiesIterator<'a> { type Item = ErrorCorrectingCapabilities; type IntoIter = ErrorCapabilitiesIterator<'a>; fn into_iter(self) -> Self::IntoIter { ErrorCapabilitiesIterator { data: self.data, start_index: self.start_index, current_index: self.start_index, current_entry: 0, number_of_items: self.number_of_items, } } } impl<'a> Iterator for ErrorCapabilitiesIterator<'a> { type Item = ErrorCorrectingCapabilities; fn next(&mut self) -> Option { if self.current_entry == self.number_of_items { self.reset(); return None; } match self.data.parts().get_field_byte(self.current_index) { Some(current_item) => { self.current_index = self.current_index + ErrorCorrectingCapabilities::SIZE; self.current_entry += 1; Some(ErrorCorrectingCapabilities::from(current_item)) } None => { self.reset(); None } } } } impl<'a> fmt::Debug for ErrorCapabilitiesIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().entries(self.into_iter()).finish() } } impl<'a> Serialize for ErrorCapabilitiesIterator<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let capabilities: Vec = self.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(capabilities.len()))?; for e in capabilities { seq.serialize_element(&e)?; } seq.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type5 = vec![ 5u8, 0x15, 0x3F, 0x00, // header 0x04, // error detecting Parity8Bit 0b1000, // error correcting SingleBitErrorCorrecting 0x03, // interleave OneWay 0x04, // interleave TwoWay 0x02, // size 0b10000, 0x00, // speeds NS50 (offsets 0x9-0xA) 0b1000, 0x00, // types FastPageMode (offsets 0xB-0xC) 0b10, // voltage Volts3dot3 0x02, // slots 0x0A, 0x00, // handle 0x000A (offsets 0xF-0x10) 0x0B, 0x00, // handle 0x000B (offsets 0x11-0x12) 0b1000, // error correcting 1, SingleBitErrorCorrecting 0b10000, // error correcting 2, DoubleBitErrorCorrecting 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type5); let test_struct = SMBiosMemoryControllerInformation::new(&parts); assert_eq!( *test_struct.error_detecting_method().unwrap(), ErrorDetectingMethod::Parity8Bit ); let error_correcting = test_struct.error_correcting_capability().unwrap(); assert!(error_correcting.single_bit_error_correcting()); assert_eq!( *test_struct.supported_interleave().unwrap(), InterleaveSupport::OneWay ); assert_eq!( *test_struct.current_interleave().unwrap(), InterleaveSupport::TwoWay ); assert_eq!(test_struct.maximum_memory_module_size(), Some(2)); assert!(test_struct.supported_speeds().unwrap().ns50()); assert!(test_struct .supported_memory_types() .unwrap() .fast_page_mode()); assert!(test_struct.memory_module_voltage().unwrap().volts_3_3()); assert_eq!(test_struct.number_of_associated_memory_slots(), Some(2)); let mut iterator = test_struct .error_correcting_capabilities_iterator() .into_iter(); let first = iterator.next().unwrap(); assert!(first.single_bit_error_correcting()); let second = iterator.next().unwrap(); assert!(second.double_bit_error_correcting()); } } smbios-lib-0.9.2/src/structs/types/memory_device.rs000064400000000000000000001410661046102023000205430ustar 00000000000000use crate::core::{strings::*, Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # Memory Device (Type 17) /// /// This structure describes a single memory device that is part of a larger [super::SMBiosPhysicalMemoryArray] (Type 16) structure. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.7.0 (DSP0134) /// Document Date: 2023-07-21 pub struct SMBiosMemoryDevice<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosMemoryDevice<'a> { const STRUCT_TYPE: u8 = 17u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosMemoryDevice<'a> { /// Handle, or instance number, associated with the /// [super::SMBiosPhysicalMemoryArray] to which this device belongs pub fn physical_memory_array_handle(&self) -> Option { self.parts.get_field_handle(0x04) } /// Handle, or instance number, associated with any /// error that was previously detected for the device /// If the system does not provide the error information /// structure, the field contains FFFEh; otherwise, the /// field contains either FFFFh (if no error was /// detected) or the handle of the error-information /// structure ([super::SMBiosMemoryErrorInformation32] or /// [super::SMBiosMemoryErrorInformation64]). pub fn memory_error_information_handle(&self) -> Option { self.parts.get_field_handle(0x06) } /// Total width, in bits, of this memory device, including /// any check or error-correction bits /// If there are no error-correction bits, this value /// should be equal to Data Width. If the width is /// unknown, the field is set to FFFFh. pub fn total_width(&self) -> Option { self.parts.get_field_word(0x08) } /// Data width, in bits, of this memory device /// A Data Width of 0 and a Total Width of 8 indicates /// that the device is being used solely to provide 8 /// error-correction bits. If the width is unknown, the /// field is set to FFFFh. pub fn data_width(&self) -> Option { self.parts.get_field_word(0x0A) } /// Size of the memory device pub fn size(&self) -> Option { self.parts .get_field_word(0x0C) .map(|raw| MemorySize::from(raw)) } /// Implementation form factor for this memory device pub fn form_factor(&self) -> Option { self.parts .get_field_byte(0x0E) .map(|raw| MemoryFormFactorData::from(raw)) } /// Identifies when the Memory Device is one of a set /// of Memory Devices that must be populated with all /// devices of the same type and size, and the set to /// which this device belongs /// A value of 0 indicates that the device is not part of a /// set; a value of FFh indicates that the attribute is /// unknown. /// NOTE: A Device Set number must be unique within the /// context of the Memory Array containing this Memory /// Device. pub fn device_set(&self) -> Option { self.parts.get_field_byte(0x0F) } /// Identifies the physically-labeled socket or board position where /// the memory device is located /// EXAMPLE: “SIMM 3” pub fn device_locator(&self) -> SMBiosString { self.parts.get_field_string(0x10) } /// Identifies the physically labeled bank where the memory device is located /// EXAMPLE: “Bank 0” or “A” pub fn bank_locator(&self) -> SMBiosString { self.parts.get_field_string(0x11) } /// Type of memory used in this device pub fn memory_type(&self) -> Option { self.parts .get_field_byte(0x12) .map(|raw| MemoryDeviceTypeData::from(raw)) } /// Additional detail on the memory device type pub fn type_detail(&self) -> Option { self.parts .get_field_word(0x13) .map(|raw| MemoryTypeDetails::from(raw)) } /// The maximum capable speed of the /// device, in megatransfers per second (MT/s). pub fn speed(&self) -> Option { self.parts .get_field_word(0x15) .map(|raw| MemorySpeed::from(raw)) } /// The manufacturer of this memory device pub fn manufacturer(&self) -> SMBiosString { self.parts.get_field_string(0x17) } /// The serial number of this memory device. /// This value is set by the manufacturer and normally /// is not changeable. pub fn serial_number(&self) -> SMBiosString { self.parts.get_field_string(0x18) } /// The asset tag of this memory device pub fn asset_tag(&self) -> SMBiosString { self.parts.get_field_string(0x19) } /// The part number of this memory device. /// This value is set by the manufacturer and normally /// is not changeable. pub fn part_number(&self) -> SMBiosString { self.parts.get_field_string(0x1A) } /// Bits 7-4: reserved /// Bits 3-0: rank /// Value=0 for unknown rank information pub fn attributes(&self) -> Option { self.parts.get_field_byte(0x1B) } /// Extended size of the memory device in MB (complements /// the Size field at offset 0Ch) pub fn extended_size(&self) -> Option { self.parts .get_field_dword(0x1C) .map(|raw| MemorySizeExtended::from(raw)) } /// Identifies the configured speed of the memory /// device, in megatransfers per second (MT/s). See /// 7.18.4 for details. /// 0000h = the speed is unknown /// FFFFh = the speed is 65,535 MT/s or greater, /// and the actual speed is stored in the Extended /// Configured Memory Speed field pub fn configured_memory_speed(&self) -> Option { self.parts .get_field_word(0x20) .map(|raw| MemorySpeed::from(raw)) } /// Minimum operating voltage for this device, in /// millivolts /// If the value is 0, the voltage is unknown. pub fn minimum_voltage(&self) -> Option { self.parts.get_field_word(0x22) } /// Maximum operating voltage for this device, in /// millivolts /// If the value is 0, the voltage is unknown. pub fn maximum_voltage(&self) -> Option { self.parts.get_field_word(0x24) } /// Configured voltage for this device, in millivolts /// If the value is 0, the voltage is unknown. pub fn configured_voltage(&self) -> Option { self.parts.get_field_word(0x26) } /// Memory technology type for this memory device. pub fn memory_technology(&self) -> Option { self.parts .get_field_byte(0x28) .map(|raw| MemoryDeviceTechnologyData::from(raw)) } /// The operating modes supported by this memory device. pub fn memory_operating_mode_capability(&self) -> Option { self.parts .get_field_word(0x29) .map(|raw| MemoryOperatingModeCapabilities::from(raw)) } /// The firmware version of this memory device. pub fn firmware_version(&self) -> SMBiosString { self.parts.get_field_string(0x2B) } /// The two-byte module manufacturer ID found in the SPD of this memory device; LSB first. pub fn module_manufacturer_id(&self) -> Option { self.parts.get_field_word(0x2C) } /// The two-byte module product ID found in the SPD of this memory device; LSB first. pub fn module_product_id(&self) -> Option { self.parts.get_field_word(0x2E) } /// The two-byte memory subsystem controller manufacturer ID found in the SPD of this memory device; LSB first. pub fn memory_subsystem_controller_manufacturer_id(&self) -> Option { self.parts.get_field_word(0x30) } /// The two-byte memory subsystem controller product ID found in the SPD of this memory device; LSB first. pub fn memory_subsystem_controller_product_id(&self) -> Option { self.parts.get_field_word(0x32) } /// Size of the Non-volatile portion of the memory /// device in Bytes, if any. /// /// If the value is 0, there is no /// non-volatile portion. pub fn non_volatile_size(&self) -> Option { self.parts .get_field_qword(0x34) .map(|raw| MemoryIndicatedSize::from(raw)) } /// Size of the Volatile portion of the memory device in /// Bytes, if any. /// /// If the value is 0, there is no Volatile /// portion. pub fn volatile_size(&self) -> Option { self.parts .get_field_qword(0x3C) .map(|raw| MemoryIndicatedSize::from(raw)) } /// Size of the Cache portion of the memory device in /// Bytes, if any. /// /// If the value is 0, there is no Cache /// portion. pub fn cache_size(&self) -> Option { self.parts .get_field_qword(0x44) .map(|raw| MemoryIndicatedSize::from(raw)) } /// Size of the Logical memory device in Bytes. pub fn logical_size(&self) -> Option { self.parts .get_field_qword(0x4C) .map(|raw| MemoryIndicatedSize::from(raw)) } /// Extended speed of the memory device /// (complements the Speed field at offset 15h). /// Identifies the maximum capable speed of the /// device, in megatransfers per second (MT/s). pub fn extended_speed(&self) -> Option { self.parts .get_field_dword(0x54) .map(|raw| MemorySpeedExtended::from(raw)) } /// Extended configured memory speed of the memory /// device (complements the 'configured_memory_speed' /// field at offset 20h). /// /// Identifies the configured /// speed of the memory device, in megatransfers per /// second (MT/s) /// /// The 'extended_speed' and 'extended_configured_memory_speed' fields are intended to represent /// memory devices that operate faster than 65,535 MT/s, which cannot be described using the /// Speed or Configured Memory Speed fields. These fields are only meaningful if the value /// in the Speed or Configured Memory Speed fields are FFFFh. For compatibility with older /// SMBIOS parsers, memory devices slower than 65,535 MT/s should represent their speed /// using the Speed and Configured Memory Speed fields, leaving the Extended Speed and /// Extended Configured Memory Speed fields set to 0. /// /// Bit 31 is reserved for future use and must be set to 0 /// Bits 30:0 represent the speed or configured memory speed of the device in MT/s. pub fn extended_configured_memory_speed(&self) -> Option { self.parts .get_field_dword(0x58) .map(|raw| MemorySpeedExtended::from(raw)) } /// The two-byte PMIC0 manufacturer ID found in the /// SPD of this memory device; LSB first. /// /// The PMIC0 Manufacturer ID indicates the manufacturer of the PMIC0 on memory device. This field shall /// be set to the value of the SPD PMIC 0 Manufacturer ID Code. A value of 0000h indicates the PMIC0 /// Manufacturer ID is unknown. /// /// NOTE The location (byte addresses) of the SPD PMIC 0 Manufacturer ID Code may vary and is defined /// by the memory type/technology SPD Standard. For example, for RDIMM DDR5, this field will have the /// first byte correspond to the value in byte 198 and the second byte corresponds to the value in byte 199. /// If SPD doesn't contain Register Revision Number, this field shall be set to 0000h pub fn pmic0_manufacturer_id(&self) -> Option { self.parts.get_field_word(0x5C) } /// The PMIC 0 Revision Number found in the SPD of /// this memory device. /// /// The PMIC0 Revision Number indicates the revision of the PMIC0 on memory device. This field shall be /// set to the value of the SPD PMIC 0 Revision Number. A value of FF00h indicates the PMIC0 Revision /// Number is unknown. /// /// NOTE The location (byte addresses) of the SPD PMIC 0 Revision Number may vary and is defined by the /// memory type/technology SPD Standard. For example, for RDIMM DDR5, this field will have the first byte /// correspond to the value in byte 201 and the second byte shall be set to 00h. If SPD doesn't contain /// Register Revision Number, this field shall be set to FF00h. pub fn pmic0_revision_number(&self) -> Option { self.parts.get_field_word(0x5E) } /// The two-byte RCD manufacturer ID found in the /// SPD of this memory device; LSB first. /// /// The RCD Manufacturer ID indicates the manufacturer of the RCD on memory device. This field shall be /// set to the value of the SPD Registering Clock Driver Manufacturer ID Code. A value of 0000h indicates /// the RCD Manufacturer ID is unknown. /// /// NOTE The location (byte addresses) of the SPD Registering Clock Driver Manufacturer ID Code may /// vary and is defined by the memory type/technology SPD Standard. For example, for RDIMM DDR5, this /// field will have the first byte correspond to the value in byte 240 and the second byte corresponds to the /// value in byte 241. If SPD doesn't contain Register Revision Number, this field shall be set to 0000h. pub fn rcd_manufacturer_id(&self) -> Option { self.parts.get_field_word(0x60) } /// The RCD 0 Revision Number found in the SPD of /// this memory device. /// /// The RCD Revision Number indicates the revision of the RCD on memory device. This field shall be set to /// the value of the SPD Register Revision Number. A value of FF00h indicates the RCD Revision Number is /// unknown. /// /// NOTE The location (byte addresses) of the SPD Register Revision Number may vary and is defined by /// the memory type/technology SPD Standard. For example, for RDIMM DDR5, this field will have the first /// byte correspond to the value in byte 243 and the second byte shall be set to 00h. If SPD doesn't contain /// Register Revision Number, this field shall be set to FF00h pub fn rcd_revision_number(&self) -> Option { self.parts.get_field_word(0x62) } } impl fmt::Debug for SMBiosMemoryDevice<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field( "physical_memory_array_handle", &self.physical_memory_array_handle(), ) .field( "memory_error_information_handle", &self.memory_error_information_handle(), ) .field("total_width", &self.total_width()) .field("data_width", &self.data_width()) .field("size", &self.size()) .field("form_factor", &self.form_factor()) .field("device_set", &self.device_set()) .field("device_locator", &self.device_locator()) .field("bank_locator", &self.bank_locator()) .field("memory_type", &self.memory_type()) .field("type_detail", &self.type_detail()) .field("speed", &self.speed()) .field("manufacturer", &self.manufacturer()) .field("serial_number", &self.serial_number()) .field("asset_tag", &self.asset_tag()) .field("part_number", &self.part_number()) .field("attributes", &self.attributes()) .field("extended_size", &self.extended_size()) .field("configured_memory_speed", &self.configured_memory_speed()) .field("minimum_voltage", &self.minimum_voltage()) .field("maximum_voltage", &self.maximum_voltage()) .field("configured_voltage", &self.configured_voltage()) .field("memory_technology", &self.memory_technology()) .field( "memory_operating_mode_capability", &self.memory_operating_mode_capability(), ) .field("firmware_version", &self.firmware_version()) .field("module_manufacturer_id", &self.module_manufacturer_id()) .field("module_product_id", &self.module_product_id()) .field( "memory_subsystem_controller_manufacturer_id", &self.memory_subsystem_controller_manufacturer_id(), ) .field( "memory_subsystem_controller_product_id", &self.memory_subsystem_controller_product_id(), ) .field("non_volatile_size", &self.non_volatile_size()) .field("volatile_size", &self.volatile_size()) .field("cache_size", &self.cache_size()) .field("logical_size", &self.logical_size()) .field("extended_speed", &self.extended_speed()) .field( "extended_configured_memory_speed", &self.extended_configured_memory_speed(), ) .field("pmic0_manufacturer_id", &self.pmic0_manufacturer_id()) .field("pmic0_revision_number", &self.pmic0_revision_number()) .field("rcd_manufacturer_id", &self.rcd_manufacturer_id()) .field("rcd_revision_number", &self.rcd_revision_number()) .finish() } } impl Serialize for SMBiosMemoryDevice<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosMemoryDevice", 36)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field( "physical_memory_array_handle", &self.physical_memory_array_handle(), )?; state.serialize_field( "memory_error_information_handle", &self.memory_error_information_handle(), )?; state.serialize_field("total_width", &self.total_width())?; state.serialize_field("data_width", &self.data_width())?; state.serialize_field("size", &self.size())?; state.serialize_field("form_factor", &self.form_factor())?; state.serialize_field("device_set", &self.device_set())?; state.serialize_field("device_locator", &self.device_locator())?; state.serialize_field("bank_locator", &self.bank_locator())?; state.serialize_field("memory_type", &self.memory_type())?; state.serialize_field("type_detail", &self.type_detail())?; state.serialize_field("speed", &self.speed())?; state.serialize_field("manufacturer", &self.manufacturer())?; state.serialize_field("serial_number", &self.serial_number())?; state.serialize_field("asset_tag", &self.asset_tag())?; state.serialize_field("part_number", &self.part_number())?; state.serialize_field("attributes", &self.attributes())?; state.serialize_field("extended_size", &self.extended_size())?; state.serialize_field("configured_memory_speed", &self.configured_memory_speed())?; state.serialize_field("minimum_voltage", &self.minimum_voltage())?; state.serialize_field("maximum_voltage", &self.maximum_voltage())?; state.serialize_field("configured_voltage", &self.configured_voltage())?; state.serialize_field("memory_technology", &self.memory_technology())?; state.serialize_field( "memory_operating_mode_capability", &self.memory_operating_mode_capability(), )?; state.serialize_field("firmware_version", &self.firmware_version())?; state.serialize_field("module_manufacturer_id", &self.module_manufacturer_id())?; state.serialize_field("module_product_id", &self.module_product_id())?; state.serialize_field( "memory_subsystem_controller_manufacturer_id", &self.memory_subsystem_controller_manufacturer_id(), )?; state.serialize_field( "memory_subsystem_controller_product_id", &self.memory_subsystem_controller_product_id(), )?; state.serialize_field("non_volatile_size", &self.non_volatile_size())?; state.serialize_field("volatile_size", &self.volatile_size())?; state.serialize_field("cache_size", &self.cache_size())?; state.serialize_field("logical_size", &self.logical_size())?; state.serialize_field("extended_speed", &self.extended_speed())?; state.serialize_field( "extended_configured_memory_speed", &self.extended_configured_memory_speed(), )?; state.serialize_field("pmic0_manufacturer_id", &self.pmic0_manufacturer_id())?; state.serialize_field("pmic0_revision_number", &self.pmic0_revision_number())?; state.serialize_field("rcd_manufacturer_id", &self.rcd_manufacturer_id())?; state.serialize_field("rcd_revision_number", &self.rcd_revision_number())?; state.end() } } /// # Memory Device - Type Data #[derive(PartialEq, Eq)] pub struct MemoryDeviceTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [MemoryDeviceType] value pub value: MemoryDeviceType, } impl fmt::Debug for MemoryDeviceTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for MemoryDeviceTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryDeviceTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for MemoryDeviceTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { MemoryDeviceType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for MemoryDeviceTypeData { type Target = MemoryDeviceType; fn deref(&self) -> &Self::Target { &self.value } } /// # Memory Device -Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemoryDeviceType { /// Other Other, /// Unknown Unknown, /// DRAM Dram, /// EDRAM Edram, /// VRAM Vram, /// SRAM Sram, /// RAM Ram, /// ROM Rom, /// FLASH Flash, /// EEPROM Eeprom, /// FEPROM Feprom, /// EPROM Eprom, /// CDRAM Cdram, /// 3DRAM ThreeDram, /// SDRAM Sdram, /// SGRAM Sgram, /// RDRAM Rdram, /// DDR Ddr, /// DDR2 Ddr2, /// DDR2 FB-DIMM Ddr2Fbdimm, /// DDR3 Ddr3, /// FBD2 Fbd2, /// DDR4 Ddr4, /// LPDDR Lpddr, /// LPDDR2 Lpddr2, /// LPDDR3 Lpddr3, /// LPDDR4 Lpddr4, /// Logical non-volatile device LogicalNonVolatileDevice, /// HBM (High Bandwidth Memory) Hbm, /// HBM2 (High Bandwidth Memory Generation 2) Hbm2, /// DDR5 Ddr5, /// LPDDR5 Lpddr5, /// HBM3 Hbm3, /// A value unknown to this standard, check the raw value None, } impl From for MemoryDeviceTypeData { fn from(raw: u8) -> Self { MemoryDeviceTypeData { value: match raw { 0x01 => MemoryDeviceType::Other, 0x02 => MemoryDeviceType::Unknown, 0x03 => MemoryDeviceType::Dram, 0x04 => MemoryDeviceType::Edram, 0x05 => MemoryDeviceType::Vram, 0x06 => MemoryDeviceType::Sram, 0x07 => MemoryDeviceType::Ram, 0x08 => MemoryDeviceType::Rom, 0x09 => MemoryDeviceType::Flash, 0x0A => MemoryDeviceType::Eeprom, 0x0B => MemoryDeviceType::Feprom, 0x0C => MemoryDeviceType::Eprom, 0x0D => MemoryDeviceType::Cdram, 0x0E => MemoryDeviceType::ThreeDram, 0x0F => MemoryDeviceType::Sdram, 0x10 => MemoryDeviceType::Sgram, 0x11 => MemoryDeviceType::Rdram, 0x12 => MemoryDeviceType::Ddr, 0x13 => MemoryDeviceType::Ddr2, 0x14 => MemoryDeviceType::Ddr2Fbdimm, 0x18 => MemoryDeviceType::Ddr3, 0x19 => MemoryDeviceType::Fbd2, 0x1A => MemoryDeviceType::Ddr4, 0x1B => MemoryDeviceType::Lpddr, 0x1C => MemoryDeviceType::Lpddr2, 0x1D => MemoryDeviceType::Lpddr3, 0x1E => MemoryDeviceType::Lpddr4, 0x1F => MemoryDeviceType::LogicalNonVolatileDevice, 0x20 => MemoryDeviceType::Hbm, 0x21 => MemoryDeviceType::Hbm2, 0x22 => MemoryDeviceType::Ddr5, 0x23 => MemoryDeviceType::Lpddr5, 0x24 => MemoryDeviceType::Hbm3, _ => MemoryDeviceType::None, }, raw, } } } /// # Memory Device — Form Factor Data pub struct MemoryFormFactorData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [MemoryFormFactor] value pub value: MemoryFormFactor, } impl fmt::Debug for MemoryFormFactorData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for MemoryFormFactorData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryFormFactorData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for MemoryFormFactorData { type Target = MemoryFormFactor; fn deref(&self) -> &Self::Target { &self.value } } /// # Memory Device — Form Factor #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemoryFormFactor { /// Other Other, /// Unknown Unknown, /// SIMM Simm, /// SIP Sip, /// Chip Chip, /// DIP Dip, /// ZIP Zip, /// Proprietary Card ProprietaryCard, /// DIMM Dimm, /// TSOP Tsop, /// Row of chips RowOfChips, /// RIMM Rimm, /// SODIMM Sodimm, /// SRIMM Srimm, /// FB-DIMM Fbdimm, /// Die Die, /// A value unknown to this standard, check the raw value None, } impl From for MemoryFormFactorData { fn from(raw: u8) -> Self { MemoryFormFactorData { value: match raw { 0x01 => MemoryFormFactor::Other, 0x02 => MemoryFormFactor::Unknown, 0x03 => MemoryFormFactor::Simm, 0x04 => MemoryFormFactor::Sip, 0x05 => MemoryFormFactor::Chip, 0x06 => MemoryFormFactor::Dip, 0x07 => MemoryFormFactor::Zip, 0x08 => MemoryFormFactor::ProprietaryCard, 0x09 => MemoryFormFactor::Dimm, 0x0A => MemoryFormFactor::Tsop, 0x0B => MemoryFormFactor::RowOfChips, 0x0C => MemoryFormFactor::Rimm, 0x0D => MemoryFormFactor::Sodimm, 0x0E => MemoryFormFactor::Srimm, 0x0F => MemoryFormFactor::Fbdimm, 0x10 => MemoryFormFactor::Die, _ => MemoryFormFactor::None, }, raw, } } } /// # Memory Device — Type Detail #[derive(PartialEq, Eq)] pub struct MemoryTypeDetails { /// Raw value pub raw: u16, } impl Deref for MemoryTypeDetails { type Target = u16; fn deref(&self) -> &Self::Target { &self.raw } } impl From for MemoryTypeDetails { fn from(raw: u16) -> Self { MemoryTypeDetails { raw } } } impl MemoryTypeDetails { /// Bit 1 Other pub fn other(&self) -> bool { self.raw & 0x0002 == 0x0002 } /// Bit 2 Unknown pub fn unknown(&self) -> bool { self.raw & 0x0004 == 0x0004 } /// Bit 3 Fast-paged pub fn fast_paged(&self) -> bool { self.raw & 0x0008 == 0x0008 } /// Bit 4 Static column pub fn static_column(&self) -> bool { self.raw & 0x0010 == 0x0010 } /// Bit 5 Pseudo-static pub fn pseudo_static(&self) -> bool { self.raw & 0x0020 == 0x0020 } /// Bit 6 RAMBUS pub fn ram_bus(&self) -> bool { self.raw & 0x0040 == 0x0040 } /// Bit 7 Synchronous pub fn synchronous(&self) -> bool { self.raw & 0x0080 == 0x0080 } /// Bit 8 CMOS pub fn cmos(&self) -> bool { self.raw & 0x0100 == 0x0100 } /// Bit 9 EDO pub fn edo(&self) -> bool { self.raw & 0x0200 == 0x0200 } /// Bit 10 Window DRAM pub fn window_dram(&self) -> bool { self.raw & 0x0400 == 0x0400 } /// Bit 11 Cache DRAM pub fn cache_dram(&self) -> bool { self.raw & 0x0800 == 0x0800 } /// Bit 12 Non-volatile pub fn non_volatile(&self) -> bool { self.raw & 0x1000 == 0x1000 } /// Bit 13 Registered (Buffered) pub fn registered(&self) -> bool { self.raw & 0x2000 == 0x2000 } /// Bit 14 Unbuffered (Unregistered) pub fn unbuffered(&self) -> bool { self.raw & 0x4000 == 0x4000 } /// Bit 15 LRDIMM pub fn lrdimm(&self) -> bool { self.raw & 0x8000 == 0x8000 } } impl fmt::Debug for MemoryTypeDetails { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("other", &self.other()) .field("unknown", &self.unknown()) .field("fast_paged", &self.fast_paged()) .field("static_column", &self.static_column()) .field("pseudo_static", &self.pseudo_static()) .field("ram_bus", &self.ram_bus()) .field("synchronous", &self.synchronous()) .field("cmos", &self.cmos()) .field("edo", &self.edo()) .field("window_dram", &self.window_dram()) .field("cache_dram", &self.cache_dram()) .field("non_volatile", &self.non_volatile()) .field("registered", &self.registered()) .field("unbuffered", &self.unbuffered()) .field("lrdimm", &self.lrdimm()) .finish() } } impl Serialize for MemoryTypeDetails { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryTypeDetails", 16)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("other", &self.other())?; state.serialize_field("unknown", &self.unknown())?; state.serialize_field("fast_paged", &self.fast_paged())?; state.serialize_field("static_column", &self.static_column())?; state.serialize_field("pseudo_static", &self.pseudo_static())?; state.serialize_field("ram_bus", &self.ram_bus())?; state.serialize_field("synchronous", &self.synchronous())?; state.serialize_field("cmos", &self.cmos())?; state.serialize_field("edo", &self.edo())?; state.serialize_field("window_dram", &self.window_dram())?; state.serialize_field("cache_dram", &self.cache_dram())?; state.serialize_field("non_volatile", &self.non_volatile())?; state.serialize_field("registered", &self.registered())?; state.serialize_field("unbuffered", &self.unbuffered())?; state.serialize_field("lrdimm", &self.lrdimm())?; state.end() } } /// # Memory Device — Memory Technology Data pub struct MemoryDeviceTechnologyData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [MemoryDeviceTechnology] value pub value: MemoryDeviceTechnology, } impl fmt::Debug for MemoryDeviceTechnologyData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for MemoryDeviceTechnologyData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryDeviceTechnologyData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for MemoryDeviceTechnologyData { type Target = MemoryDeviceTechnology; fn deref(&self) -> &Self::Target { &self.value } } /// # Memory Device — Memory Technology #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemoryDeviceTechnology { /// Other Other, /// Unknown Unknown, /// DRAM Dram, /// NVDIMM-N NvdimmN, /// NVDIMM-F NvdimmF, /// NVDIMM-P NvdimmP, /// Intel® Optane™ persistent memory IntelOptaneDcPersistentMemory, /// A value unknown to this standard, check the raw value None, } impl From for MemoryDeviceTechnologyData { fn from(raw: u8) -> Self { MemoryDeviceTechnologyData { value: match raw { 0x01 => MemoryDeviceTechnology::Other, 0x02 => MemoryDeviceTechnology::Unknown, 0x03 => MemoryDeviceTechnology::Dram, 0x04 => MemoryDeviceTechnology::NvdimmN, 0x05 => MemoryDeviceTechnology::NvdimmF, 0x06 => MemoryDeviceTechnology::NvdimmP, 0x07 => MemoryDeviceTechnology::IntelOptaneDcPersistentMemory, _ => MemoryDeviceTechnology::None, }, raw, } } } /// # Memory Device — Memory Operating Mode Capability #[derive(PartialEq, Eq)] pub struct MemoryOperatingModeCapabilities { /// Raw value pub raw: u16, } impl Deref for MemoryOperatingModeCapabilities { type Target = u16; fn deref(&self) -> &Self::Target { &self.raw } } impl From for MemoryOperatingModeCapabilities { fn from(raw: u16) -> Self { MemoryOperatingModeCapabilities { raw } } } impl MemoryOperatingModeCapabilities { /// Other pub fn other(&self) -> bool { self.raw & 0x0002 == 0x0002 } /// Unknown pub fn unknown(&self) -> bool { self.raw & 0x0004 == 0x0004 } /// Volatile memory pub fn volatile_memory(&self) -> bool { self.raw & 0x0008 == 0x0008 } /// Byte-accessible persistent memory pub fn byte_accessible_persistent_memory(&self) -> bool { self.raw & 0x0010 == 0x0010 } /// Block-accessible persistent memory pub fn block_accessible_persistent_memory(&self) -> bool { self.raw & 0x0020 == 0x0020 } } impl fmt::Debug for MemoryOperatingModeCapabilities { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("other", &self.other()) .field("unknown", &self.unknown()) .field("volatile_memory", &self.volatile_memory()) .field( "byte_accessible_persistent_memory", &self.byte_accessible_persistent_memory(), ) .field( "block_accessible_persistent_memory", &self.block_accessible_persistent_memory(), ) .finish() } } impl Serialize for MemoryOperatingModeCapabilities { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryOperatingModeCapabilities", 6)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("other", &self.other())?; state.serialize_field("unknown", &self.unknown())?; state.serialize_field("volatile_memory", &self.volatile_memory())?; state.serialize_field( "byte_accessible_persistent_memory", &self.byte_accessible_persistent_memory(), )?; state.serialize_field( "block_accessible_persistent_memory", &self.block_accessible_persistent_memory(), )?; state.end() } } /// # Speed of Memory #[derive(Serialize, Debug)] pub enum MemorySpeed { /// Memory Speed is Unknown Unknown, /// The speed is 65,535 MT/s or greater, and the actual speed is stored in the 'extended_speed' field SeeExtendedSpeed, /// The maximum capable speed of the device, in megatransfers per second (MT/s) MTs(u16), } impl From for MemorySpeed { fn from(raw: u16) -> Self { match raw { 0 => MemorySpeed::Unknown, 0xFFFF => MemorySpeed::SeeExtendedSpeed, _ => MemorySpeed::MTs(raw), } } } /// # Extended Speed of Memory #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemorySpeedExtended { /// Speed of memory in megatransfers per second (MT/s) MTs(u32), /// See the _speed_ field. /// /// For compatibility with older SMBIOS parsers, memory devices slower than 65,535 MT/s should represent their speed /// using the Speed and Configured Memory Speed fields, leaving the Extended Speed and /// Extended Configured Memory Speed fields set to 0. SeeSpeed, } /// Bit 31 is reserved for future use and must be set to 0 /// Bits 30:0 represent the speed or configured memory speed of the device in MT/s. impl From for MemorySpeedExtended { fn from(raw: u32) -> Self { let bits_30_to_0 = raw & 0x7FFF_FFFF; match bits_30_to_0 { 0 => MemorySpeedExtended::SeeSpeed, _ => MemorySpeedExtended::MTs(bits_30_to_0), } } } /// # Size of Memory #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemorySize { /// No Memory Device Installed in the Socket NotInstalled, /// Memory Size is Unknown Unknown, /// The actual size is stored in the Extended Size field SeeExtendedSize, /// Size of Memory (KB) Kilobytes(u16), /// Size of Memory (MB) Megabytes(u16), } /// If the value is 0, no memory device is installed in the /// socket; if the size is unknown, the field value is /// FFFFh. If the size is 32 GB-1 MB or greater, the /// field value is 7FFFh and the actual size is stored in /// the Extended Size field. /// The granularity in which the value is specified /// depends on the setting of the most-significant bit (bit /// 15). If the bit is 0, the value is specified in megabyte /// units; if the bit is 1, the value is specified in kilobyte /// units. For example, the value 8100h identifies a /// 256 KB memory device and 0100h identifies a /// 256 MB memory device. impl From for MemorySize { fn from(raw: u16) -> Self { match raw { 0 => MemorySize::NotInstalled, 0xFFFF => MemorySize::Unknown, 0x7FFF => MemorySize::SeeExtendedSize, _ => match raw & 0x8000 { 0x8000 => MemorySize::Kilobytes(raw & 0x7FFF), _ => MemorySize::Megabytes(raw), }, } } } /// # Extended Size of Memory #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemorySizeExtended { /// Size of Memory (MB) Megabytes(u32), /// See the _size_ field. /// /// For compatibility with older SMBIOS parsers, memory devices smaller than (32 GB - 1 MB) /// should be represented using their size in the Size field, leaving the Extended Size field set to 0. SeeSize, } /// Bit 31 is reserved for future use and must be set to 0. /// Bits 30:0 represent the size of the memory device in megabytes. impl From for MemorySizeExtended { fn from(raw: u32) -> Self { let bits_30_to_0 = raw & 0x7FFF_FFFF; match bits_30_to_0 { 0 => MemorySizeExtended::SeeSize, _ => MemorySizeExtended::Megabytes(bits_30_to_0), } } } /// # Size of Memory in Bytes #[derive(Serialize, Debug)] pub enum MemoryIndicatedSize { /// Memory Size is Unknown Unknown, /// Size of Memory (bytes) Bytes(u64), } impl From for MemoryIndicatedSize { fn from(raw: u64) -> Self { match raw { 0xFFFFFFFFFFFFFFFF => MemoryIndicatedSize::Unknown, _ => MemoryIndicatedSize::Bytes(raw), } } } #[cfg(test)] mod tests { use super::*; #[test] fn test() { // Memory Device structure is sensitive to BIOS specification versions // and prone to bugs. Therefore, it is important to test different // structure versions. // // Length of the structure: // 15h for version 2.1, // 1Bh for version 2.3, // 1Ch for version 2.6, // 22h for version 2.7, // 28h for version 2.8, // 54h for version 3.2, // 5Ch for version 3.3 and later // Memory Device structure version 2.8 (does not contain _memory_technology()_ field and beyond) let struct_type17 = vec![ 0x11, 0x28, 0x40, 0x00, 0x3E, 0x00, 0xFE, 0xFF, 0x48, 0x00, 0x40, 0x00, 0x00, 0x20, 0x09, 0x00, 0x01, 0x02, 0x1A, 0x80, 0x00, 0x6A, 0x0A, 0x03, 0x04, 0x05, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x0A, 0xB0, 0x04, 0xB0, 0x04, 0xB0, 0x04, 0x43, 0x50, 0x55, 0x31, 0x5F, 0x44, 0x49, 0x4D, 0x4D, 0x5F, 0x31, 0x00, 0x4E, 0x4F, 0x44, 0x45, 0x20, 0x31, 0x00, 0x48, 0x79, 0x6E, 0x69, 0x78, 0x00, 0x37, 0x32, 0x30, 0x39, 0x31, 0x30, 0x30, 0x33, 0x00, 0x20, 0x00, 0x48, 0x4D, 0x41, 0x38, 0x31, 0x47, 0x52, 0x37, 0x41, 0x46, 0x52, 0x38, 0x4E, 0x2D, 0x56, 0x4B, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type17); let test_struct = SMBiosMemoryDevice::new(&parts); assert_eq!(test_struct.physical_memory_array_handle(), Some(Handle(62))); assert_eq!( test_struct.memory_error_information_handle(), Some(Handle(65534)) ); assert_eq!(test_struct.total_width(), Some(72)); assert_eq!(test_struct.data_width(), Some(64)); match test_struct.size().unwrap() { MemorySize::Megabytes(size) => assert_eq!(size, 8192), _ => panic!("incorrect size"), } assert_eq!(*test_struct.form_factor().unwrap(), MemoryFormFactor::Dimm); assert_eq!(test_struct.device_set(), Some(0)); assert_eq!( test_struct.device_locator().to_string(), "CPU1_DIMM_1".to_string() ); assert_eq!(test_struct.bank_locator().to_string(), "NODE 1".to_string()); assert_eq!( test_struct.memory_type(), Some(MemoryDeviceTypeData::from(26)) ); assert_eq!( test_struct.type_detail(), Some(MemoryTypeDetails::from(128)) ); match test_struct.speed().unwrap() { MemorySpeed::MTs(speed) => assert_eq!(speed, 2666), MemorySpeed::Unknown => panic!("expected speed"), MemorySpeed::SeeExtendedSpeed => panic!("expected speed"), } assert_eq!(test_struct.manufacturer().to_string(), "Hynix".to_string()); assert_eq!( test_struct.serial_number().to_string(), "72091003".to_string() ); assert_eq!(test_struct.asset_tag().to_string(), " ".to_string()); assert_eq!( test_struct.part_number().to_string(), "HMA81GR7AFR8N-VK ".to_string() ); assert_eq!(test_struct.attributes(), Some(1)); assert_eq!( test_struct.extended_size(), Some(MemorySizeExtended::SeeSize) ); match test_struct.configured_memory_speed().unwrap() { MemorySpeed::MTs(speed) => assert_eq!(speed, 2666), MemorySpeed::Unknown => panic!("expected speed"), MemorySpeed::SeeExtendedSpeed => panic!("expected speed"), } assert_eq!(test_struct.minimum_voltage(), Some(1200)); assert_eq!(test_struct.maximum_voltage(), Some(1200)); assert_eq!(test_struct.configured_voltage(), Some(1200)); // version 2.8 does not contain _memory_technology()_ field and fields beyond assert!(test_struct.memory_technology().is_none()); // 3.3 structure let struct_type17 = vec![ 0x11, 0x5C, 0x40, 0x00, 0x3E, 0x00, 0xFE, 0xFF, 0x48, 0x00, 0x40, 0x00, 0x00, 0x20, 0x09, 0x00, 0x01, 0x02, 0x1A, 0x80, 0x00, 0x6A, 0x0A, 0x03, 0x04, 0x05, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x0A, 0xB0, 0x04, 0xB0, 0x04, 0xB0, 0x04, 0x07, // MemoryDeviceTechnology::IntelOptaneDcPersistentMemory 0x20, 0x00, // MemoryOperatingModeCapabilities block_accessible_persistent_memory 0x07, // firmware version "8" 0x00, 0x00, // module_manufacturer_id 0x00, 0x00, // module_product_id 0x00, 0x00, // memory_subsystem_controller_manufacturer_id 0x00, 0x00, // memory_subsystem_controller_product_id 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // non_volatile_size 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // volatile_size 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // cache_size 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // logical_size 0x04, 0x03, 0x02, 0x01, // extended_speed 0x08, 0x07, 0x06, 0x05, // extended_configured_memory_speed 0x43, 0x50, 0x55, 0x31, 0x5F, 0x44, 0x49, 0x4D, 0x4D, 0x5F, 0x31, 0x00, 0x4E, 0x4F, 0x44, 0x45, 0x20, 0x31, 0x00, 0x48, 0x79, 0x6E, 0x69, 0x78, 0x00, 0x37, 0x32, 0x30, 0x39, 0x31, 0x30, 0x30, 0x33, 0x00, 0x20, 0x00, 0x48, 0x4D, 0x41, 0x38, 0x31, 0x47, 0x52, 0x37, 0x41, 0x46, 0x52, 0x38, 0x4E, 0x2D, 0x56, 0x4B, 0x20, 0x20, 0x20, 0x20, 0x00, 0x38, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type17); let test_struct = SMBiosMemoryDevice::new(&parts); assert_eq!( *test_struct.memory_technology().unwrap(), MemoryDeviceTechnology::IntelOptaneDcPersistentMemory ); assert!(test_struct .memory_operating_mode_capability() .unwrap() .block_accessible_persistent_memory()); assert_eq!(test_struct.firmware_version().to_string(), "8".to_string()); assert_eq!(test_struct.module_manufacturer_id(), Some(0)); assert_eq!(test_struct.module_product_id(), Some(0)); assert_eq!( test_struct.memory_subsystem_controller_manufacturer_id(), Some(0) ); assert_eq!( test_struct.memory_subsystem_controller_product_id(), Some(0) ); match test_struct.non_volatile_size().unwrap() { MemoryIndicatedSize::Unknown => (), MemoryIndicatedSize::Bytes(_) => panic!("expected unknown"), } match test_struct.volatile_size().unwrap() { MemoryIndicatedSize::Unknown => (), MemoryIndicatedSize::Bytes(_) => panic!("expected unknown"), } match test_struct.cache_size().unwrap() { MemoryIndicatedSize::Unknown => (), MemoryIndicatedSize::Bytes(_) => panic!("expected unknown"), } match test_struct.logical_size().unwrap() { MemoryIndicatedSize::Unknown => (), MemoryIndicatedSize::Bytes(_) => panic!("expected unknown"), } assert_eq!( test_struct.extended_speed(), Some(MemorySpeedExtended::MTs(0x01020304)) ); assert_eq!( test_struct.extended_configured_memory_speed(), Some(MemorySpeedExtended::MTs(0x05060708)) ); } } smbios-lib-0.9.2/src/structs/types/memory_device_mapped_address.rs000064400000000000000000000211401046102023000235640ustar 00000000000000use crate::core::{Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Memory Device Mapped Address (Type 20) /// /// This structure maps memory address space usually to a device-level granularity. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosMemoryDeviceMappedAddress<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosMemoryDeviceMappedAddress<'a> { const STRUCT_TYPE: u8 = 20u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosMemoryDeviceMappedAddress<'a> { /// Physical address, in kilobytes, of a range of /// memory mapped to the referenced [super::SMBiosMemoryDevice] /// When the field value is FFFF FFFFh the actual /// address is stored in the Extended Starting /// Address field. When this field contains a valid /// address, Ending Address must also contain a /// valid address. When this field contains FFFF /// FFFFh, Ending Address must also contain FFFF /// FFFFh. pub fn starting_address(&self) -> Option { self.parts.get_field_dword(0x4) } /// Physical ending address of the last kilobyte of a /// range of addresses mapped to the referenced /// [super::SMBiosMemoryDevice] /// When the field value is FFFF FFFFh the actual /// address is stored in the Extended Ending Address /// field. When this field contains a valid address, /// Starting Address must also contain a valid /// address. pub fn ending_address(&self) -> Option { self.parts.get_field_dword(0x8) } /// Handle, or instance number, associated with the /// [super::SMBiosMemoryDevice] structure to which this address /// range is mapped /// Multiple address ranges can be mapped to a /// single [super::SMBiosMemoryDevice] pub fn memory_device_handle(&self) -> Option { self.parts.get_field_handle(0xC) } /// Handle, or instance number, associated with the /// Memory Array Mapped Address structure to which /// this device address range is mapped /// Multiple address ranges can be mapped to a /// single [super::SMBiosMemoryArrayMappedAddress]. pub fn memory_array_mapped_address_handle(&self) -> Option { self.parts.get_field_handle(0xE) } /// Position of the referenced [super::SMBiosMemoryDevice] in a row /// of the address partition /// For example, if two 8-bit devices form a 16-bit row, /// this field’s value is either 1 or 2. /// The value 0 is reserved. If the position is /// unknown, the field contains FFh. pub fn partition_row_position(&self) -> Option { self.parts.get_field_byte(0x10) } /// Position of the referenced [super::SMBiosMemoryDevice] in an /// interleave /// The value 0 indicates non-interleaved, 1 indicates /// first interleave position, 2 the second interleave /// position, and so on. If the position is unknown, the /// field contains FFh. /// EXAMPLES: In a 2:1 interleave, the value 1 indicates /// the device in the ”even” position. In a 4:1 interleave, the /// value 1 indicates the first of four possible positions. pub fn interleave_position(&self) -> Option { self.parts.get_field_byte(0x11) } /// Maximum number of consecutive rows from the /// referenced [super::SMBiosMemoryDevice] that are accessed in a /// single interleaved transfer /// If the device is not part of an interleave, the field /// contains 0; if the interleave configuration is /// unknown, the value is FFh. /// EXAMPLES: If a device transfers two rows each time it /// is read, its Interleaved Data Depth is set to 2. If that /// device is 2:1 interleaved and in Interleave Position 1, the /// rows mapped to that device are 1, 2, 5, 6, 9, 10, etc. pub fn interleaved_data_depth(&self) -> Option { self.parts.get_field_byte(0x12) } /// Physical address, in bytes, of a range of memory /// mapped to the referenced [super::SMBiosMemoryDevice] /// This field is valid when Starting Address contains /// the value FFFF FFFFh. If Starting Address /// contains a value other than FFFF FFFFh, this field /// contains zeros. When this field contains a valid /// address, Extended Ending Address must also /// contain a valid address. pub fn extended_starting_address(&self) -> Option { self.parts.get_field_qword(0x13) } /// Physical ending address, in bytes, of the last of a /// range of addresses mapped to the referenced /// [super::SMBiosMemoryDevice] /// This field is valid when both Starting Address and /// Ending Address contain the value FFFF FFFFh. If /// Ending Address contains a value other than FFFF /// FFFFh, this field contains zeros. When this field /// contains a valid address, Extended Starting /// Address must also contain a valid address pub fn extended_ending_address(&self) -> Option { self.parts.get_field_qword(0x1B) } } impl fmt::Debug for SMBiosMemoryDeviceMappedAddress<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("starting_address", &self.starting_address()) .field("ending_address", &self.ending_address()) .field("memory_device_handle", &self.memory_device_handle()) .field( "memory_array_mapped_address_handle", &self.memory_array_mapped_address_handle(), ) .field("partition_row_position", &self.partition_row_position()) .field("interleave_position", &self.interleave_position()) .field("interleaved_data_depth", &self.interleaved_data_depth()) .field( "extended_starting_address", &self.extended_starting_address(), ) .field("extended_ending_address", &self.extended_ending_address()) .finish() } } impl Serialize for SMBiosMemoryDeviceMappedAddress<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosMemoryDeviceMappedAddress", 10)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("starting_address", &self.starting_address())?; state.serialize_field("ending_address", &self.ending_address())?; state.serialize_field("memory_device_handle", &self.memory_device_handle())?; state.serialize_field( "memory_array_mapped_address_handle", &self.memory_array_mapped_address_handle(), )?; state.serialize_field("partition_row_position", &self.partition_row_position())?; state.serialize_field("interleave_position", &self.interleave_position())?; state.serialize_field("interleaved_data_depth", &self.interleaved_data_depth())?; state.serialize_field( "extended_starting_address", &self.extended_starting_address(), )?; state.serialize_field("extended_ending_address", &self.extended_ending_address())?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type20 = vec![ 0x14, 0x23, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x40, 0x00, 0x3F, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type20); let test_struct = SMBiosMemoryDeviceMappedAddress::new(&parts); assert_eq!(test_struct.starting_address(), Some(0)); assert_eq!(test_struct.ending_address(), Some(8388607)); assert_eq!(*test_struct.memory_device_handle().unwrap(), 64); assert_eq!( *test_struct.memory_array_mapped_address_handle().unwrap(), 63 ); assert_eq!(test_struct.partition_row_position(), Some(1)); assert_eq!(test_struct.interleave_position(), Some(1)); assert_eq!(test_struct.interleaved_data_depth(), Some(2)); assert_eq!(test_struct.extended_starting_address(), Some(0)); assert_eq!(test_struct.extended_ending_address(), Some(0)); } } smbios-lib-0.9.2/src/structs/types/memory_error_information_32.rs000064400000000000000000000312321046102023000233370ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # 32-Bit Memory Error Information (Type 18) /// /// This structure identifies the specifics of an error that might be detected within a [super::SMBiosPhysicalMemoryArray]. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosMemoryErrorInformation32<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosMemoryErrorInformation32<'a> { const STRUCT_TYPE: u8 = 18u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosMemoryErrorInformation32<'a> { /// Type of error that is associated with the current /// status reported for the memory array or device pub fn error_type(&self) -> Option { self.parts .get_field_byte(0x04) .map(|raw| MemoryErrorTypeData::from(raw)) } /// Granularity (for example, device versus Partition) /// to which the error can be resolved pub fn error_granularity(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| MemoryErrorGranularityData::from(raw)) } /// Memory access operation that caused the error pub fn error_operation(&self) -> Option { self.parts .get_field_byte(0x06) .map(|raw| MemoryErrorOperationData::from(raw)) } /// Vendor-specific ECC syndrome or CRC data /// associated with the erroneous access /// If the value is unknown, this field contains 0000 /// 0000h. pub fn vendor_syndrome(&self) -> Option { self.parts.get_field_dword(0x07) } /// 32-bit physical address of the error based on the /// addressing of the bus to which the memory array /// is connected /// If the address is unknown, this field contains /// 8000 0000h. pub fn memory_array_error_address(&self) -> Option { self.parts.get_field_dword(0x0B) } /// 32-bit physical address of the error relative to the /// start of the failing memory device, in bytes /// If the address is unknown, this field contains /// 8000 0000h. pub fn device_error_address(&self) -> Option { self.parts.get_field_dword(0x0F) } /// Range, in bytes, within which the error can be /// determined, when an error address is given /// If the range is unknown, this field contains 8000 /// 0000h. pub fn error_resolution(&self) -> Option { self.parts.get_field_dword(0x13) } } impl fmt::Debug for SMBiosMemoryErrorInformation32<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("error_type", &self.error_type()) .field("error_granularity", &self.error_granularity()) .field("error_operation", &self.error_operation()) .field("vendor_syndrome", &self.vendor_syndrome()) .field( "memory_array_error_address", &self.memory_array_error_address(), ) .field("device_error_address", &self.device_error_address()) .field("error_resolution", &self.error_resolution()) .finish() } } impl Serialize for SMBiosMemoryErrorInformation32<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosMemoryErrorInformation32", 8)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("error_type", &self.error_type())?; state.serialize_field("error_granularity", &self.error_granularity())?; state.serialize_field("error_operation", &self.error_operation())?; state.serialize_field("vendor_syndrome", &self.vendor_syndrome())?; state.serialize_field( "memory_array_error_address", &self.memory_array_error_address(), )?; state.serialize_field("device_error_address", &self.device_error_address())?; state.serialize_field("error_resolution", &self.error_resolution())?; state.end() } } /// # Memory Error - Error Type Data pub struct MemoryErrorTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [MemoryErrorType] value pub value: MemoryErrorType, } impl fmt::Debug for MemoryErrorTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for MemoryErrorTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryErrorTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for MemoryErrorTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { MemoryErrorType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for MemoryErrorTypeData { type Target = MemoryErrorType; fn deref(&self) -> &Self::Target { &self.value } } /// # Memory Error - Error Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemoryErrorType { /// Other Other, /// Unknown Unknown, /// OK OK, /// Bad read BadRead, /// Parity error ParityError, /// Single-bit error SingleBitError, /// Double-bit error DoubleBitError, /// Multi-bit error MultiBitError, /// Nibble error NibbleError, /// Checksum error ChecksumError, /// CRC error CrcError, /// Corrected single-bit error CorrectedSingleBitError, /// Corrected error CorrectedError, /// Uncorrectable error UncorrectableError, /// A value unknown to this standard, check the raw value None, } impl From for MemoryErrorTypeData { fn from(raw: u8) -> Self { MemoryErrorTypeData { value: match raw { 0x01 => MemoryErrorType::Other, 0x02 => MemoryErrorType::Unknown, 0x03 => MemoryErrorType::OK, 0x04 => MemoryErrorType::BadRead, 0x05 => MemoryErrorType::ParityError, 0x06 => MemoryErrorType::SingleBitError, 0x07 => MemoryErrorType::DoubleBitError, 0x08 => MemoryErrorType::MultiBitError, 0x09 => MemoryErrorType::NibbleError, 0x0A => MemoryErrorType::ChecksumError, 0x0B => MemoryErrorType::CrcError, 0x0C => MemoryErrorType::CorrectedSingleBitError, 0x0D => MemoryErrorType::CorrectedError, 0x0E => MemoryErrorType::UncorrectableError, _ => MemoryErrorType::None, }, raw, } } } /// # Memory Error - Error Granularity Data pub struct MemoryErrorGranularityData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [MemoryErrorGranularity] value pub value: MemoryErrorGranularity, } impl fmt::Debug for MemoryErrorGranularityData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for MemoryErrorGranularityData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryErrorGranularityData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for MemoryErrorGranularityData { type Target = MemoryErrorGranularity; fn deref(&self) -> &Self::Target { &self.value } } /// # Memory Error - Error Granularity #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemoryErrorGranularity { /// Other Other, /// Unknown Unknown, /// Device level DeviceLevel, /// Memory partition level MemoryPartitionLevel, /// A value unknown to this standard, check the raw value None, } impl From for MemoryErrorGranularityData { fn from(raw: u8) -> Self { MemoryErrorGranularityData { value: match raw { 0x01 => MemoryErrorGranularity::Other, 0x02 => MemoryErrorGranularity::Unknown, 0x03 => MemoryErrorGranularity::DeviceLevel, 0x04 => MemoryErrorGranularity::MemoryPartitionLevel, _ => MemoryErrorGranularity::None, }, raw, } } } /// # Memory Error - Error Operation Data pub struct MemoryErrorOperationData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [MemoryErrorOperation] value pub value: MemoryErrorOperation, } impl fmt::Debug for MemoryErrorOperationData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for MemoryErrorOperationData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryErrorOperationData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for MemoryErrorOperationData { type Target = MemoryErrorOperation; fn deref(&self) -> &Self::Target { &self.value } } /// # Memory Error - Error Operation #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemoryErrorOperation { /// Other Other, /// Unknown Unknown, /// Read Read, /// Write Write, /// Partial write PartialWrite, /// A value unknown to this standard, check the raw value None, } impl From for MemoryErrorOperationData { fn from(raw: u8) -> Self { MemoryErrorOperationData { value: match raw { 0x01 => MemoryErrorOperation::Other, 0x02 => MemoryErrorOperation::Unknown, 0x03 => MemoryErrorOperation::Read, 0x04 => MemoryErrorOperation::Write, 0x05 => MemoryErrorOperation::PartialWrite, _ => MemoryErrorOperation::None, }, raw, } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type18 = vec![ 0x12, 0x17, 0x50, 0x00, 0x03, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type18); let test_struct = SMBiosMemoryErrorInformation32::new(&parts); assert_eq!(*test_struct.error_type().unwrap(), MemoryErrorType::OK); assert_eq!( *test_struct.error_granularity().unwrap(), MemoryErrorGranularity::Unknown ); assert_eq!( *test_struct.error_operation().unwrap(), MemoryErrorOperation::Unknown ); assert_eq!(test_struct.vendor_syndrome(), Some(0)); assert_eq!(test_struct.memory_array_error_address(), Some(0x8000_0000)); assert_eq!(test_struct.device_error_address(), Some(0x8000_0000)); assert_eq!(test_struct.error_resolution(), Some(0x8000_0000)); } } smbios-lib-0.9.2/src/structs/types/memory_error_information_64.rs000064400000000000000000000135621046102023000233520ustar 00000000000000use crate::{ MemoryErrorGranularityData, MemoryErrorOperationData, MemoryErrorTypeData, SMBiosStruct, UndefinedStruct, }; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # 64-Bit Memory Error Information (Type 33) /// /// This structure describes an error within a [super::SMBiosPhysicalMemoryArray], when the error address is above 4G (0xFFFFFFFF). /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosMemoryErrorInformation64<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosMemoryErrorInformation64<'a> { const STRUCT_TYPE: u8 = 33u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosMemoryErrorInformation64<'a> { /// Type of error that is associated with the current /// status reported for the memory array or device pub fn error_type(&self) -> Option { self.parts .get_field_byte(0x04) .map(|raw| MemoryErrorTypeData::from(raw)) } /// Granularity (for example, device versus Partition) /// to which the error can be resolved pub fn error_granularity(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| MemoryErrorGranularityData::from(raw)) } /// Memory access operation that caused the error pub fn error_operation(&self) -> Option { self.parts .get_field_byte(0x06) .map(|raw| MemoryErrorOperationData::from(raw)) } /// Vendor-specific ECC syndrome or CRC data /// associated with the erroneous access /// /// If the value is unknown, this field contains 0000 /// 0000h. pub fn vendor_syndrome(&self) -> Option { self.parts.get_field_dword(0x07) } /// 64-bit physical address of the error based on the /// addressing of the bus to which the memory array is /// connected /// /// If the address is unknown, this field contains 8000 0000 /// 0000 0000h. pub fn memory_array_error_address(&self) -> Option { self.parts.get_field_qword(0x0B) } /// 64-bit physical address of the error relative to the start of /// the failing memory device, in bytes /// /// If the address is unknown, this field contains 8000 0000 /// 0000 0000h. pub fn device_error_address(&self) -> Option { self.parts.get_field_qword(0x13) } /// Range, in bytes, within which the error can be determined, /// when an error address is given /// /// If the range is unknown, this field contains 8000 0000h. pub fn error_resolution(&self) -> Option { self.parts.get_field_dword(0x1B) } } impl fmt::Debug for SMBiosMemoryErrorInformation64<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("error_type", &self.error_type()) .field("error_granularity", &self.error_granularity()) .field("error_operation", &self.error_operation()) .field("vendor_syndrome", &self.vendor_syndrome()) .field( "memory_array_error_address", &self.memory_array_error_address(), ) .field("device_error_address", &self.device_error_address()) .field("error_resolution", &self.error_resolution()) .finish() } } impl Serialize for SMBiosMemoryErrorInformation64<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosMemoryErrorInformation64", 8)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("error_type", &self.error_type())?; state.serialize_field("error_granularity", &self.error_granularity())?; state.serialize_field("error_operation", &self.error_operation())?; state.serialize_field("vendor_syndrome", &self.vendor_syndrome())?; state.serialize_field( "memory_array_error_address", &self.memory_array_error_address(), )?; state.serialize_field("device_error_address", &self.device_error_address())?; state.serialize_field("error_resolution", &self.error_resolution())?; state.end() } } #[cfg(test)] mod tests { use super::*; use crate::{ MemoryErrorGranularity, MemoryErrorOperation, MemoryErrorType, SMBiosStruct, UndefinedStruct, }; #[test] fn unit_test() { let struct_type33 = vec![ 0x21, 0x1F, 0x50, 0x00, 0x03, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type33); let test_struct = SMBiosMemoryErrorInformation64::new(&parts); assert_eq!(*test_struct.error_type().unwrap(), MemoryErrorType::OK); assert_eq!( *test_struct.error_granularity().unwrap(), MemoryErrorGranularity::Unknown ); assert_eq!( *test_struct.error_operation().unwrap(), MemoryErrorOperation::Unknown ); assert_eq!(test_struct.vendor_syndrome(), Some(0)); assert_eq!( test_struct.memory_array_error_address(), Some(0x8000_0000_0000_0000) ); assert_eq!( test_struct.device_error_address(), Some(0x8000_0000_0000_0000) ); assert_eq!(test_struct.error_resolution(), Some(0x8000_0000)); } } smbios-lib-0.9.2/src/structs/types/memory_module_information.rs000064400000000000000000000121201046102023000231620ustar 00000000000000use crate::core::{strings::*, UndefinedStruct}; use crate::{MemoryTypes, SMBiosStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Memory Module Information (Type 6, Obsolete) /// /// One Memory Module Information structure is included for each memory-module socket in the system. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosMemoryModuleInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosMemoryModuleInformation<'a> { const STRUCT_TYPE: u8 = 6u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosMemoryModuleInformation<'a> { /// Socket reference designation /// /// EXAMPLE: ‘J202’,0 pub fn socket_designation(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Each nibble indicates a bank (RAS#) connection; 0xF /// means no connection. /// /// EXAMPLE: If banks 1 & 3 (RAS# 1 & 3) were connected to a /// SIMM socket the byte for that socket would be 13h. If only bank 2 /// (RAS 2) were connected, the byte for that socket would be 2Fh. pub fn bank_connections(&self) -> Option { self.parts.get_field_byte(0x05) } /// Speed of the memory module, in ns (for example, 70d for /// a 70ns module) /// /// If the speed is unknown, the field is set to 0. pub fn current_speed(&self) -> Option { self.parts.get_field_byte(0x06) } /// Bit field for the current memory type pub fn current_memory_type(&self) -> Option { self.parts .get_field_word(0x07) .map(|raw| MemoryTypes::from(raw)) } /// Installed size pub fn installed_size(&self) -> Option { self.parts.get_field_byte(0x09) } /// Enabled size pub fn enabled_size(&self) -> Option { self.parts.get_field_byte(0x0A) } /// Bit fields error status pub fn error_status(&self) -> Option { self.parts.get_field_byte(0x0B) } } impl fmt::Debug for SMBiosMemoryModuleInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("socket_designation", &self.socket_designation()) .field("bank_connections", &self.bank_connections()) .field("current_speed", &self.current_speed()) .field("current_memory_type", &self.current_memory_type()) .field("installed_size", &self.installed_size()) .field("enabled_size", &self.enabled_size()) .field("error_status", &self.error_status()) .finish() } } impl Serialize for SMBiosMemoryModuleInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosMemoryModuleInformation", 8)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("socket_designation", &self.socket_designation())?; state.serialize_field("bank_connections", &self.bank_connections())?; state.serialize_field("current_speed", &self.current_speed())?; state.serialize_field("current_memory_type", &self.current_memory_type())?; state.serialize_field("installed_size", &self.installed_size())?; state.serialize_field("enabled_size", &self.enabled_size())?; state.serialize_field("error_status", &self.error_status())?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type6 = vec![ 6, // type 6 0x0C, // length 0x0F, 0x00, // handle 0x01, // Reference Designation string #1 0x01, // Socket connected to RAS-0 and RAS-1 0b00000010, // Current speed is Unknown, since can’t read SIMM IDs 0xA4, 0x00, // Current SIMM must be standard parity 0x7D, // Installed size indeterminable (no SIMM IDs) 0x83, // Enabled size is double-bank 8MB (2**3) 0, // No errors 0x41, 0x31, 0x00, // "A1" String #1: Reference Designator 0x00, ]; let parts = UndefinedStruct::new(&struct_type6); let test_struct = SMBiosMemoryModuleInformation::new(&parts); assert_eq!( test_struct.socket_designation().to_string(), "A1".to_string() ); assert_eq!(test_struct.bank_connections(), Some(0x01)); assert_eq!(test_struct.current_speed(), Some(0b00000010)); let memory_types = test_struct.current_memory_type().unwrap(); assert!(memory_types.standard()); assert!(memory_types.simm()); assert_eq!(test_struct.installed_size(), Some(0x7D)); assert_eq!(test_struct.enabled_size(), Some(0x83)); } } smbios-lib-0.9.2/src/structs/types/mod.rs000064400000000000000000000062101046102023000164620ustar 00000000000000//! Standard structures. //! //! Contains implementations for all standard structures found in //! the DMTF SMBIOS specification. mod unknown; pub use unknown::*; mod bios_information; pub use bios_information::*; mod additional_information; pub use additional_information::*; mod baseboard_information; pub use baseboard_information::*; mod bios_language_information; pub use bios_language_information::*; mod bis_entry_point; pub use bis_entry_point::*; mod built_in_pointing_device; pub use built_in_pointing_device::*; mod cache_information; pub use cache_information::*; mod cooling_device; pub use cooling_device::*; mod electrical_current_probe; pub use electrical_current_probe::*; mod end_of_table; pub use end_of_table::*; mod group_associations; pub use group_associations::*; mod hardware_security; pub use hardware_security::*; mod inactive; pub use inactive::*; mod ipmi_device_information; pub use ipmi_device_information::*; mod management_controller_host_interface; pub use management_controller_host_interface::*; mod management_device; pub use management_device::*; mod management_device_component; pub use management_device_component::*; mod management_device_threshold_data; pub use management_device_threshold_data::*; mod memory_array_mapped_address; pub use memory_array_mapped_address::*; mod memory_channel; pub use memory_channel::*; mod memory_controller_information; pub use memory_controller_information::*; mod memory_device; pub use memory_device::*; mod memory_device_mapped_address; pub use memory_device_mapped_address::*; mod memory_error_information_32; pub use memory_error_information_32::*; mod memory_error_information_64; pub use memory_error_information_64::*; mod memory_module_information; pub use memory_module_information::*; mod oem_strings; pub use oem_strings::*; mod on_board_device_information; pub use on_board_device_information::*; mod onboard_devices_extended_information; pub use onboard_devices_extended_information::*; mod out_of_band_remote_access; pub use out_of_band_remote_access::*; mod physical_memory_array; pub use physical_memory_array::*; mod portable_battery; pub use portable_battery::*; mod port_connector_information; pub use port_connector_information::*; mod processor_additional_information; pub use processor_additional_information::*; mod processor_information; pub use processor_information::*; mod system_boot_information; pub use system_boot_information::*; mod system_chassis_information; pub use system_chassis_information::*; mod system_configuration_options; pub use system_configuration_options::*; mod system_event_log; pub use system_event_log::*; mod system_information; pub use system_information::*; mod system_power_controls; pub use system_power_controls::*; mod system_power_supply; pub use system_power_supply::*; mod system_reset; pub use system_reset::*; mod system_slot; pub use system_slot::*; mod temperature_probe; pub use temperature_probe::*; mod tpm_device; pub use tpm_device::*; mod voltage_probe; pub use voltage_probe::*; mod firmware_inventory_information; pub use firmware_inventory_information::*; mod string_property; pub use string_property::*; smbios-lib-0.9.2/src/structs/types/oem_strings.rs000064400000000000000000000065151046102023000202440ustar 00000000000000use crate::{SMBiosStringSet, SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # OEM Strings (Type 11) /// /// This structure contains free-form strings defined by the OEM. Examples of this are /// part numbers for system reference documents, contact information for the manufacturer, etc. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosOemStrings<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosOemStrings<'a> { const STRUCT_TYPE: u8 = 11u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosOemStrings<'a> { /// Number of strings pub fn count(&self) -> Option { self.parts.get_field_byte(0x04) } /// Iterable collection of OEM strings pub fn oem_strings(&self) -> &SMBiosStringSet { &self.parts.strings } } impl fmt::Debug for SMBiosOemStrings<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("count", &self.count()) .field("oem_strings", &self.oem_strings()) .finish() } } impl Serialize for SMBiosOemStrings<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosOemStrings", 3)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("count", &self.count())?; state.serialize_field("oem_strings", &self.oem_strings())?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type6 = vec![ 0x0B, 0x05, 0x04, 0x00, 0x03, 0x41, 0x42, 0x53, 0x20, 0x37, 0x30, 0x2F, 0x37, 0x31, 0x20, 0x36, 0x30, 0x20, 0x36, 0x31, 0x20, 0x36, 0x32, 0x20, 0x36, 0x33, 0x3B, 0x00, 0x46, 0x42, 0x59, 0x54, 0x45, 0x23, 0x32, 0x55, 0x33, 0x45, 0x33, 0x58, 0x34, 0x37, 0x36, 0x4A, 0x36, 0x53, 0x36, 0x62, 0x37, 0x42, 0x37, 0x48, 0x37, 0x4D, 0x37, 0x51, 0x37, 0x54, 0x37, 0x57, 0x37, 0x61, 0x37, 0x6A, 0x37, 0x6D, 0x61, 0x33, 0x61, 0x70, 0x61, 0x71, 0x61, 0x75, 0x62, 0x37, 0x2E, 0x51, 0x33, 0x3B, 0x00, 0x42, 0x55, 0x49, 0x4C, 0x44, 0x49, 0x44, 0x23, 0x31, 0x33, 0x57, 0x57, 0x43, 0x44, 0x43, 0x38, 0x36, 0x30, 0x31, 0x23, 0x53, 0x41, 0x42, 0x41, 0x23, 0x44, 0x41, 0x42, 0x41, 0x3B, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type6); let test_struct = SMBiosOemStrings::new(&parts); assert_eq!(test_struct.count(), Some(0x03)); let mut iter = test_struct.oem_strings().into_iter(); assert_eq!( iter.next().unwrap().ok(), Some("ABS 70/71 60 61 62 63;".to_string()) ); assert_eq!( iter.next().unwrap().ok(), Some("FBYTE#2U3E3X476J6S6b7B7H7M7Q7T7W7a7j7ma3apaqaub7.Q3;".to_string()) ); assert_eq!( iter.next().unwrap().ok(), Some("BUILDID#13WWCDC8601#SABA#DABA;".to_string()) ); } } smbios-lib-0.9.2/src/structs/types/on_board_device_information.rs000064400000000000000000000261201046102023000234140ustar 00000000000000use crate::core::{strings::*, Header, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # On Board Devices Information (Type 10, Obsolete) /// /// The information in this structure defines the attributes of devices that are onboard /// (soldered onto) a system element, usually the baseboard. In general, an entry in this table implies that the /// BIOS has some level of control over the enabling of the associated device for use by the system. /// /// NOTE This structure is obsolete starting with version 2.6 of this specification; the [super::SMBiosOnboardDevicesExtendedInformation] /// (Type 41) structure should be used instead. BIOS providers can choose to implement /// both types to allow existing SMBIOS browsers to properly display the system’s onboard devices information. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.5.0 (DSP0134) /// Document Date: 2021-09-15 pub struct SMBiosOnBoardDeviceInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosOnBoardDeviceInformation<'a> { const STRUCT_TYPE: u8 = 10u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosOnBoardDeviceInformation<'a> { /// The number of [OnBoardDevice] entries pub fn number_of_devices(&self) -> usize { let struct_length = self.parts().header.length() as usize; (struct_length - Header::SIZE) / OnBoardDevice::SIZE } /// Iterates over the [OnBoardDevice] entries pub fn onboard_device_iterator(&'a self) -> OnBoardDeviceIterator<'a> { OnBoardDeviceIterator::new(self) } } impl fmt::Debug for SMBiosOnBoardDeviceInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("number_of_devices", &self.number_of_devices()) .field("onboard_device_iterator", &self.onboard_device_iterator()) .finish() } } impl Serialize for SMBiosOnBoardDeviceInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosOnBoardDeviceInformation", 3)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("number_of_devices", &self.number_of_devices())?; state.serialize_field("onboard_device_iterator", &self.onboard_device_iterator())?; state.end() } } /// # On Board Device entry within [SMBiosOnBoardDeviceInformation] pub struct OnBoardDevice<'a> { onboard_device_information: &'a SMBiosOnBoardDeviceInformation<'a>, entry_offset: usize, } impl<'a> OnBoardDevice<'a> { /// Size in bytes for this structure /// /// This structure is composed of: /// _device_type_ (byte) at offset 0, /// and _description_ (byte) at offset 1 /// for a total size of two bytes. const SIZE: usize = 2; fn new( onboard_device_information: &'a SMBiosOnBoardDeviceInformation<'a>, entry_offset: usize, ) -> Self { Self { onboard_device_information, entry_offset, } } /// Device type pub fn device_type(&self) -> Option { self.onboard_device_information .parts() .get_field_byte(self.entry_offset) .map(|raw| OnBoardDeviceType::from(raw)) } /// Device description pub fn description(&self) -> SMBiosString { self.onboard_device_information .parts() .get_field_string(self.entry_offset + 1) } } impl fmt::Debug for OnBoardDevice<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("device_type", &self.device_type()) .field("description", &self.description()) .finish() } } impl Serialize for OnBoardDevice<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("OnBoardDevice", 2)?; state.serialize_field("device_type", &self.device_type())?; state.serialize_field("description", &self.description())?; state.end() } } /// # On Board Device Type pub struct OnBoardDeviceType { /// Raw value pub raw: u8, } impl OnBoardDeviceType { /// One of the onboard device types pub fn type_of_device(&self) -> TypeOfDevice { let result = self.raw & 0x7F; match result { 0x01 => TypeOfDevice::Other, 0x02 => TypeOfDevice::Unknown, 0x03 => TypeOfDevice::Video, 0x04 => TypeOfDevice::ScsiController, 0x05 => TypeOfDevice::Ethernet, 0x06 => TypeOfDevice::TokenRing, 0x07 => TypeOfDevice::Sound, 0x08 => TypeOfDevice::PataController, 0x09 => TypeOfDevice::SataController, 0x0A => TypeOfDevice::SasController, 0x0B => TypeOfDevice::WirelessLan, 0x0C => TypeOfDevice::Bluetooth, 0x0D => TypeOfDevice::Wwan, 0x0E => TypeOfDevice::Emmc, 0x0F => TypeOfDevice::NvmeController, 0x10 => TypeOfDevice::UfsController, _ => TypeOfDevice::None, } } /// Enabled/disabled device status pub fn status(&self) -> DeviceStatus { if self.raw & 0x80 == 0x80 { DeviceStatus::Enabled } else { DeviceStatus::Disabled } } } impl From for OnBoardDeviceType { fn from(raw: u8) -> Self { OnBoardDeviceType { raw } } } impl fmt::Debug for OnBoardDeviceType { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("raw", &self.raw) .field("type_of_device", &self.type_of_device()) .field("status", &self.status()) .finish() } } impl Serialize for OnBoardDeviceType { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("OnBoardDeviceType", 3)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("type_of_device", &self.type_of_device())?; state.serialize_field("status", &self.status())?; state.end() } } /// # Onboard Device Types #[derive(Serialize, Debug, PartialEq, Eq)] pub enum TypeOfDevice { /// Other Other, /// Unknown Unknown, /// Video Video, /// SCSI Controller ScsiController, /// Ethernet Ethernet, /// Token Ring TokenRing, /// Sound Sound, /// PATA Controller PataController, /// SATA Controller SataController, /// SAS Controller SasController, /// Wireless LAN WirelessLan, /// Bluetooth Bluetooth, /// WWAN Wwan, /// eMMC (embedded Milti-Media Controller) Emmc, /// NVMe Controller NvmeController, /// UFS Controller UfsController, /// A value unknown to this standard, check the raw value None, } /// # Enabled/Disabled Device Status #[derive(Serialize, Debug, PartialEq, Eq)] pub enum DeviceStatus { /// Device is enabled Enabled, /// Device is disabled Disabled, } /// # On-board Device Itereator for [OnBoardDevice]s contained within [SMBiosOnBoardDeviceInformation] pub struct OnBoardDeviceIterator<'a> { data: &'a SMBiosOnBoardDeviceInformation<'a>, current_index: usize, current_entry: usize, number_of_entries: usize, } impl<'a> OnBoardDeviceIterator<'a> { const DEVICES_OFFSET: usize = 4usize; fn new(data: &'a SMBiosOnBoardDeviceInformation<'a>) -> Self { OnBoardDeviceIterator { data: data, current_index: Self::DEVICES_OFFSET, current_entry: 0, number_of_entries: data.number_of_devices(), } } fn reset(&mut self) { self.current_index = Self::DEVICES_OFFSET; self.current_entry = 0; } } impl<'a> IntoIterator for &'a OnBoardDeviceIterator<'a> { type Item = OnBoardDevice<'a>; type IntoIter = OnBoardDeviceIterator<'a>; fn into_iter(self) -> Self::IntoIter { OnBoardDeviceIterator { data: self.data, current_index: OnBoardDeviceIterator::DEVICES_OFFSET, current_entry: 0, number_of_entries: self.data.number_of_devices(), } } } impl<'a> Iterator for OnBoardDeviceIterator<'a> { type Item = OnBoardDevice<'a>; fn next(&mut self) -> Option { if self.current_entry == self.number_of_entries { self.reset(); return None; } let next_index = self.current_index + OnBoardDevice::SIZE; match self .data .parts() .get_field_data(self.current_index, next_index) { Some(_) => { let result = OnBoardDevice::new(self.data, self.current_index); self.current_index = next_index; self.current_entry = self.current_entry + 1; Some(result) } None => { self.reset(); None } } } } impl<'a> fmt::Debug for OnBoardDeviceIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().entries(self.into_iter()).finish() } } impl<'a> Serialize for OnBoardDeviceIterator<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let devices: Vec> = self.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(devices.len()))?; for e in devices { seq.serialize_element(&e)?; } seq.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type10 = vec![ 0x0A, 0x06, 0x21, 0x00, 0x83, 0x01, 0x20, 0x20, 0x20, 0x54, 0x6F, 0x20, 0x42, 0x65, 0x20, 0x46, 0x69, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x42, 0x79, 0x20, 0x4F, 0x2E, 0x45, 0x2E, 0x4D, 0x2E, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type10); let test_struct = SMBiosOnBoardDeviceInformation::new(&parts); println!("{:?}", test_struct); assert_eq!(test_struct.number_of_devices(), 1); let mut iterator = test_struct.onboard_device_iterator().into_iter(); let item = iterator.next().unwrap(); assert_eq!( item.description().to_string(), " To Be Filled By O.E.M.".to_string() ); let device_type = item.device_type().unwrap(); assert_eq!(device_type.type_of_device(), TypeOfDevice::Video); assert_eq!(device_type.status(), DeviceStatus::Enabled); assert!(iterator.next().is_none()); } } smbios-lib-0.9.2/src/structs/types/onboard_devices_extended_information.rs000064400000000000000000000136201046102023000253210ustar 00000000000000use super::system_slot::{BusNumber, DeviceFunctionNumber, SegmentGroupNumber}; use crate::core::{strings::*, UndefinedStruct}; use crate::{OnBoardDeviceType, SMBiosStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Onboard Devices Extended Information (Type 41) /// /// The information in this structure defines the attributes of devices that are onboard (soldered onto) a /// system element, usually the baseboard. /// /// In general, an entry in this table implies that the BIOS has some level of control over the enablement of /// the associated device for use by the system. /// /// To describe multi-function devices, use one type 41 structure per function, and one type 14 (Group /// Association) structure referencing all the function handles. /// /// NOTE: This structure replaces Onboard Device Information (Type 10) starting with version 2.6 of this specification. /// BIOS providers can choose to implement both types to allow existing SMBIOS browsers to properly display /// the system’s onboard devices information. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.5.0 (DSP0134) /// Document Date: 2021-09-15 pub struct SMBiosOnboardDevicesExtendedInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosOnboardDevicesExtendedInformation<'a> { const STRUCT_TYPE: u8 = 41u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosOnboardDevicesExtendedInformation<'a> { /// The onboard device reference designation pub fn reference_designation(&self) -> SMBiosString { self.parts.get_field_string(0x4) } /// Device type bit field and enum pub fn device_type(&self) -> Option { self.parts .get_field_byte(0x5) .map(|raw| OnBoardDeviceType::from(raw)) } /// Device type instance pub fn device_type_instance(&self) -> Option { self.parts.get_field_byte(0x6) } /// Segment group number pub fn segment_group_number(&self) -> Option { self.parts .get_field_word(0x7) .map(|raw| SegmentGroupNumber::from(raw)) } /// Bus number pub fn bus_number(&self) -> Option { self.parts .get_field_byte(0x9) .map(|raw| BusNumber::from(raw)) } /// Device/Function number pub fn device_function_number(&self) -> Option { self.parts .get_field_byte(0xA) .map(|raw| DeviceFunctionNumber::from(raw)) } } impl fmt::Debug for SMBiosOnboardDevicesExtendedInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::< SMBiosOnboardDevicesExtendedInformation<'_>, >()) .field("header", &self.parts.header) .field("reference_designation", &self.reference_designation()) .field("device_type", &self.device_type()) .field("device_type_instance", &self.device_type_instance()) .field("segment_group_number", &self.segment_group_number()) .field("bus_number", &self.bus_number()) .field("device_function_number", &self.device_function_number()) .finish() } } impl Serialize for SMBiosOnboardDevicesExtendedInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosOnboardDevicesExtendedInformation", 7)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("reference_designation", &self.reference_designation())?; state.serialize_field("device_type", &self.device_type())?; state.serialize_field("device_type_instance", &self.device_type_instance())?; state.serialize_field("segment_group_number", &self.segment_group_number())?; state.serialize_field("bus_number", &self.bus_number())?; state.serialize_field("device_function_number", &self.device_function_number())?; state.end() } } #[cfg(test)] mod tests { use super::*; use crate::{DeviceStatus, SMBiosStruct, TypeOfDevice, UndefinedStruct}; #[test] fn unit_test() { let struct_type41 = vec![ 0x29, 0x0B, 0x3B, 0x00, 0x01, 0x85, 0x01, 0x00, 0x00, 0x00, 0xFE, 0x69, 0x32, 0x31, 0x39, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type41); let test_struct = SMBiosOnboardDevicesExtendedInformation::new(&parts); assert_eq!( test_struct.reference_designation().to_string(), "i219".to_string() ); let device_type = test_struct.device_type().unwrap(); assert_eq!(device_type.type_of_device(), TypeOfDevice::Ethernet); assert_eq!(device_type.status(), DeviceStatus::Enabled); assert_eq!(test_struct.device_type_instance(), Some(1)); match test_struct.segment_group_number().unwrap() { SegmentGroupNumber::SingleSegment => (), SegmentGroupNumber::NotApplicable => panic!("expected SingleSegment"), SegmentGroupNumber::Number(_) => panic!("expected SingleSegment"), } match test_struct.bus_number().unwrap() { BusNumber::Number(number) => assert_eq!(number, 0), BusNumber::NotApplicable => panic!("expected Number"), } // At offset 0x0A is the value 0xFE which is the device/function value. // The 8 bits are 0b11111 (0n31) and 0b110 (0n6) match test_struct.device_function_number().unwrap() { DeviceFunctionNumber::Number { device, function } => { assert_eq!(device, 31); assert_eq!(function, 6); } _ => panic!("expected device and function values"), } } } smbios-lib-0.9.2/src/structs/types/out_of_band_remote_access.rs000064400000000000000000000117361046102023000230670ustar 00000000000000use crate::SMBiosStruct; use crate::{strings::*, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::{fmt, ops::Deref}; /// # Out-of-Band Remote Access (Type 30) /// /// This structure describes the attributes and policy settings of a hardware facility that may be used to gain /// remote access to a hardware system when the operating system is not available due to power-down /// status, hardware failures, or boot failures. /// /// NOTE: This structure type was added in version 2.2 of this specification. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosOutOfBandRemoteAccess<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosOutOfBandRemoteAccess<'a> { const STRUCT_TYPE: u8 = 30u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosOutOfBandRemoteAccess<'a> { /// The manufacturer of the out-of-band access facility pub fn manufacturer_name(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Current remote-access connections (bit field) pub fn connections(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| Connections::from(raw)) } } /// # Connections #[derive(PartialEq, Eq)] pub struct Connections { /// Raw value pub raw: u8, } impl Deref for Connections { type Target = u8; fn deref(&self) -> &Self::Target { &self.raw } } impl From for Connections { fn from(raw: u8) -> Self { Connections { raw } } } impl Connections { /// Inbound Connection Enabled (Bit 0) /// /// Identifies whether (1) or not (0) the facility is /// allowed to initiate outbound connections to receive /// incoming connections for the purpose of remote /// operations or problem management pub fn inbound_connection_enabled(&self) -> bool { self.raw & 0x01 == 0x01 } /// Outbound Connection Enabled (Bit 1) /// /// Identifies whether (1) or not (0) the facility is /// allowed to initiate outbound connections to contact /// an alert management facility when critical conditions /// occur pub fn outbound_connection_enabled(&self) -> bool { self.raw & 0x02 == 0x02 } } impl fmt::Debug for Connections { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field( "inbound_connection_enabled", &self.inbound_connection_enabled(), ) .field( "outbound_connection_enabled", &self.outbound_connection_enabled(), ) .finish() } } impl Serialize for Connections { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("Connections", 3)?; state.serialize_field("raw", &self.raw)?; state.serialize_field( "inbound_connection_enabled", &self.inbound_connection_enabled(), )?; state.serialize_field( "outbound_connection_enabled", &self.outbound_connection_enabled(), )?; state.end() } } impl fmt::Debug for SMBiosOutOfBandRemoteAccess<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("manufacturer_name", &self.manufacturer_name()) .field("connections", &self.connections()) .finish() } } impl Serialize for SMBiosOutOfBandRemoteAccess<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosOutOfBandRemoteAccess", 3)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("manufacturer_name", &self.manufacturer_name())?; state.serialize_field("connections", &self.connections())?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type41 = vec![ 30, 0x06, 0x3B, 0x00, 0x01, 0x03, 0x69, 0x6A, 0x6B, 0x6C, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type41); let test_struct = SMBiosOutOfBandRemoteAccess::new(&parts); assert_eq!( test_struct.manufacturer_name().to_string(), "ijkl".to_string() ); let connections = test_struct.connections().unwrap(); assert!(connections.inbound_connection_enabled()); assert!(connections.outbound_connection_enabled()); assert_eq!(connections.raw, 0x03); } } smbios-lib-0.9.2/src/structs/types/physical_memory_array.rs000064400000000000000000000353541046102023000223200ustar 00000000000000use crate::core::{Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::{fmt, ops::Deref}; /// # Physical Memory Array (Type 16) /// /// This structure describes a collection of memory devices that operate together to form a memory address space. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosPhysicalMemoryArray<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosPhysicalMemoryArray<'a> { const STRUCT_TYPE: u8 = 16u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosPhysicalMemoryArray<'a> { /// Physical location of the Memory Array, whether on /// the system board or an add-in board pub fn location(&self) -> Option { self.parts .get_field_byte(0x04) .map(|raw| MemoryArrayLocationData::from(raw)) } /// Function for which the array is used pub fn usage(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| MemoryArrayUseData::from(raw)) } /// Primary hardware error correction or detection /// method supported by this memory array pub fn memory_error_correction(&self) -> Option { self.parts .get_field_byte(0x06) .map(|raw| MemoryArrayErrorCorrectionData::from(raw)) } /// Maximum memory capacity, in kilobytes, for this array /// /// If the capacity is not represented in this field, then /// the 'extended_maximum_capacity' field should be used. /// /// Values 2 TB (8000 0000h) or greater must be represented /// in the Extended Maximum Capacity field. pub fn maximum_capacity(&self) -> Option { self.parts .get_field_dword(0x07) .map(|raw| MaximumMemoryCapacity::from(raw)) } /// Handle, or instance number, associated with any /// error that was previously detected for the array /// /// If the system does not provide the error /// information structure, the field contains FFFEh; /// otherwise, the field contains either FFFFh (if no /// error was detected) or the handle of the errorinformation structure. pub fn memory_error_information_handle(&self) -> Option { self.parts.get_field_handle(0x0B) } /// Number of slots or sockets available for [super::SMBiosMemoryDevice]s in this array /// /// This value represents the number of [super::SMBiosMemoryDevice] /// structures that compose this Memory /// Array. Each [super::SMBiosMemoryDevice] has a reference to /// the "owning" Memory Array. pub fn number_of_memory_devices(&self) -> Option { self.parts.get_field_word(0x0D) } /// Maximum memory capacity, in bytes, for this array /// /// This field is only valid when the Maximum /// Capacity field contains 8000 0000h. When /// Maximum Capacity contains a value that is not /// 8000 0000h, Extended Maximum Capacity must /// contain zeros. pub fn extended_maximum_capacity(&self) -> Option { self.parts.get_field_qword(0x0F) } } impl fmt::Debug for SMBiosPhysicalMemoryArray<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("location", &self.location()) .field("usage", &self.usage()) .field("memory_error_correction", &self.memory_error_correction()) .field("maximum_capacity", &self.maximum_capacity()) .field( "memory_error_information_handle", &self.memory_error_information_handle(), ) .field("number_of_memory_devices", &self.number_of_memory_devices()) .field( "extended_maximum_capacity", &self.extended_maximum_capacity(), ) .finish() } } impl Serialize for SMBiosPhysicalMemoryArray<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosPhysicalMemoryArray", 8)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("location", &self.location())?; state.serialize_field("usage", &self.usage())?; state.serialize_field("memory_error_correction", &self.memory_error_correction())?; state.serialize_field("maximum_capacity", &self.maximum_capacity())?; state.serialize_field( "memory_error_information_handle", &self.memory_error_information_handle(), )?; state.serialize_field("number_of_memory_devices", &self.number_of_memory_devices())?; state.serialize_field( "extended_maximum_capacity", &self.extended_maximum_capacity(), )?; state.end() } } /// # Memory Array - Location Data pub struct MemoryArrayLocationData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [MemoryArrayLocation] value pub value: MemoryArrayLocation, } impl fmt::Debug for MemoryArrayLocationData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for MemoryArrayLocationData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryArrayLocationData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for MemoryArrayLocationData { type Target = MemoryArrayLocation; fn deref(&self) -> &Self::Target { &self.value } } /// # Memory Array - Location #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemoryArrayLocation { /// Other Other = 0x01, /// Unknown Unknown = 0x02, /// System board or motherboard SystemBoardOrMotherboard = 0x03, /// ISA add-on card IsaAddOnCard = 0x04, /// EISA add-on card EisaAddOnCard = 0x05, /// PCI add-on card PciAddOnCard = 0x06, /// MCA add-on card McaAddOnCard = 0x07, /// PCMCIA add-on card PcmciaAddOnCard = 0x08, /// Proprietary add-on card ProprietaryAddOnCard = 0x09, /// NuBus NuBus = 0x0A, /// PC-98/C20 add-on card PC98C20AddOnCard = 0xA0, /// PC-98/C24 add-on card PC98C24AddOnCard = 0xA1, /// PC-98/E add-on card PC98EAddOnCard = 0xA2, /// PC-98/Local bus add-on card PC98LocalBusAddOnCard = 0xA3, /// CXL add-on card CxlFlexbus10AddOnCard = 0xA4, /// A value unknown to this standard, check the raw value None, } impl From for MemoryArrayLocationData { fn from(raw: u8) -> Self { MemoryArrayLocationData { value: match raw { 0x01 => MemoryArrayLocation::Other, 0x02 => MemoryArrayLocation::Unknown, 0x03 => MemoryArrayLocation::SystemBoardOrMotherboard, 0x04 => MemoryArrayLocation::IsaAddOnCard, 0x05 => MemoryArrayLocation::EisaAddOnCard, 0x06 => MemoryArrayLocation::PciAddOnCard, 0x07 => MemoryArrayLocation::McaAddOnCard, 0x08 => MemoryArrayLocation::PcmciaAddOnCard, 0x09 => MemoryArrayLocation::ProprietaryAddOnCard, 0x0A => MemoryArrayLocation::NuBus, 0xA0 => MemoryArrayLocation::PC98C20AddOnCard, 0xA1 => MemoryArrayLocation::PC98C24AddOnCard, 0xA2 => MemoryArrayLocation::PC98EAddOnCard, 0xA3 => MemoryArrayLocation::PC98LocalBusAddOnCard, 0xA4 => MemoryArrayLocation::CxlFlexbus10AddOnCard, _ => MemoryArrayLocation::None, }, raw, } } } /// # Memory Array - Use Data pub struct MemoryArrayUseData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [MemoryArrayUse] value pub value: MemoryArrayUse, } impl fmt::Debug for MemoryArrayUseData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for MemoryArrayUseData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryArrayUseData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for MemoryArrayUseData { type Target = MemoryArrayUse; fn deref(&self) -> &Self::Target { &self.value } } /// # Memory Array - Use #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemoryArrayUse { /// Other Other, /// Unknown Unknown, /// System memory SystemMemory, /// Video memory VideoMemory, /// Flash memory FlashMemory, /// Non-volatile RAM NonVolatileRam, /// Cache memory CacheMemory, /// A value unknown to this standard, check the raw value None, } impl From for MemoryArrayUseData { fn from(raw: u8) -> Self { MemoryArrayUseData { value: match raw { 0x01 => MemoryArrayUse::Other, 0x02 => MemoryArrayUse::Unknown, 0x03 => MemoryArrayUse::SystemMemory, 0x04 => MemoryArrayUse::VideoMemory, 0x05 => MemoryArrayUse::FlashMemory, 0x06 => MemoryArrayUse::NonVolatileRam, 0x07 => MemoryArrayUse::CacheMemory, _ => MemoryArrayUse::None, }, raw, } } } /// # Memory Array - Error Correction Types Data pub struct MemoryArrayErrorCorrectionData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [MemoryArrayErrorCorrection] value pub value: MemoryArrayErrorCorrection, } impl fmt::Debug for MemoryArrayErrorCorrectionData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for MemoryArrayErrorCorrectionData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("MemoryArrayErrorCorrectionData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for MemoryArrayErrorCorrectionData { type Target = MemoryArrayErrorCorrection; fn deref(&self) -> &Self::Target { &self.value } } /// # Memory Array - Error Correction Types #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MemoryArrayErrorCorrection { /// Other Other, /// Unknown Unknown, /// No Error Correction NoCorrection, /// Parity Parity, /// Single-bit ECC SingleBitEcc, /// Multi-bit ECC MultiBitEcc, /// CRC Crc, /// A value unknown to this standard, check the raw value None, } impl From for MemoryArrayErrorCorrectionData { fn from(raw: u8) -> Self { MemoryArrayErrorCorrectionData { value: match raw { 0x01 => MemoryArrayErrorCorrection::Other, 0x02 => MemoryArrayErrorCorrection::Unknown, 0x03 => MemoryArrayErrorCorrection::NoCorrection, 0x04 => MemoryArrayErrorCorrection::Parity, 0x05 => MemoryArrayErrorCorrection::SingleBitEcc, 0x06 => MemoryArrayErrorCorrection::MultiBitEcc, 0x07 => MemoryArrayErrorCorrection::Crc, _ => MemoryArrayErrorCorrection::None, }, raw, } } } /// # Maximum memory capacity, in kilobytes, for this array #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MaximumMemoryCapacity { /// Maximum memory capacity in Kilobytes Kilobytes(u32), /// Use `extended_maximum_capacity` to retrieve the maximum capacity SeeExtendedMaximumCapacity, } impl From for MaximumMemoryCapacity { fn from(raw: u32) -> Self { match raw { 0x8000_0000 => MaximumMemoryCapacity::SeeExtendedMaximumCapacity, _ => MaximumMemoryCapacity::Kilobytes(raw), } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type16 = vec![ 0x10, 0x17, 0x3E, 0x00, 0x03, 0x03, 0x05, 0x00, 0x00, 0x00, 0x60, 0xFE, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type16); let test_struct = SMBiosPhysicalMemoryArray::new(&parts); assert_eq!( *test_struct.location().unwrap(), MemoryArrayLocation::SystemBoardOrMotherboard ); assert_eq!(*test_struct.usage().unwrap(), MemoryArrayUse::SystemMemory); assert_eq!( *test_struct.memory_error_correction().unwrap(), MemoryArrayErrorCorrection::SingleBitEcc ); match test_struct.maximum_capacity().unwrap() { MaximumMemoryCapacity::Kilobytes(kb) => assert_eq!(kb, 0x6000_0000), MaximumMemoryCapacity::SeeExtendedMaximumCapacity => panic!("expected kb"), } assert_eq!( test_struct.memory_error_information_handle(), Some(Handle(65534)) ); assert_eq!(test_struct.number_of_memory_devices(), Some(4)); assert_eq!(test_struct.extended_maximum_capacity(), Some(0)); } } smbios-lib-0.9.2/src/structs/types/port_connector_information.rs000064400000000000000000000422331046102023000233530ustar 00000000000000use crate::core::{strings::*, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::{fmt, ops::Deref}; /// # Port Connector Information (Type 8) /// /// The information in this structure defines the attributes of a system port connector /// (for example, parallel, serial, keyboard, or mouse ports). The port’s type and connector information are /// provided. One structure is present for each port provided by the system. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosPortConnectorInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosPortConnectorInformation<'a> { const STRUCT_TYPE: u8 = 8u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosPortConnectorInformation<'a> { /// Internal reference designator, that is, /// internal to the system enclosure /// /// EXAMPLE: "J101" pub fn internal_reference_designator(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Internal connector type pub fn internal_connector_type(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| PortInformationConnectorTypeData::from(raw)) } /// External reference designation, /// external to the system enclosure /// /// EXAMPLE: "COM A" pub fn external_reference_designator(&self) -> SMBiosString { self.parts.get_field_string(0x06) } /// External connector type pub fn external_connector_type(&self) -> Option { self.parts .get_field_byte(0x07) .map(|raw| PortInformationConnectorTypeData::from(raw)) } /// Describes the function of the port pub fn port_type(&self) -> Option { self.parts .get_field_byte(0x08) .map(|raw| PortInformationPortTypeData::from(raw)) } } impl fmt::Debug for SMBiosPortConnectorInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field( "internal_reference_designator", &self.internal_reference_designator(), ) .field("internal_connector_type", &self.internal_connector_type()) .field( "external_reference_designator", &self.external_reference_designator(), ) .field("external_connector_type", &self.external_connector_type()) .field("port_type", &self.port_type()) .finish() } } impl Serialize for SMBiosPortConnectorInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosPortConnectorInformation", 6)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field( "internal_reference_designator", &self.internal_reference_designator(), )?; state.serialize_field("internal_connector_type", &self.internal_connector_type())?; state.serialize_field( "external_reference_designator", &self.external_reference_designator(), )?; state.serialize_field("external_connector_type", &self.external_connector_type())?; state.serialize_field("port_type", &self.port_type())?; state.end() } } /// # Port Information - Connector Types Data pub struct PortInformationConnectorTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [PortInformationConnectorType] value pub value: PortInformationConnectorType, } impl fmt::Debug for PortInformationConnectorTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for PortInformationConnectorTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("PortInformationConnectorTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for PortInformationConnectorTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { PortInformationConnectorType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for PortInformationConnectorTypeData { type Target = PortInformationConnectorType; fn deref(&self) -> &Self::Target { &self.value } } /// # Port Information - Connector Types #[derive(Serialize, Debug, PartialEq, Eq)] pub enum PortInformationConnectorType { /// There is No Connector NoConnector, /// Centronics Centronics, /// Mini Centronics MiniCentronics, /// Proprietary Proprietary, /// DB-25 pin male DB25PinMale, /// DB-25 pin female DB25PinFemale, /// DB-15 pin male DB15PinMale, /// DB-15 pin female DB15PinFemale, /// DB-9 pin male DB9PinMale, /// DB-9 pin female DB8PinFemale, /// RJ-11 RJ11, /// RJ-45 RJ45, /// 50-pin MiniSCSI MiniScsi50Pin, /// Mini-DIN MiniDin, /// Micro-DIN MicroDin, /// PS/2 Ps2, /// Infrared Infrared, /// HP-HIL HpHil, /// Access Bus (USB) AccessBusUsb, /// SSA SCSI SsaScsi, /// Circular DIN-8 male CircularDin8Male, /// Circular DIN-8 female CircularDin8Female, /// On Board IDE OnBoardIde, /// On Board Floppy OnBoardFloppy, /// 9-pin Dual Inline (pin 10 cut) DualInline9Pin, /// 25-pin Dual Inline (pin 26 cut) DualInline25Pin, /// 50-pin Dual Inline DualInline50Pin, /// 68-pin Dual Inline DualInline68Pin, /// On Board Sound Input from CD-ROM OnBoardSoundInputCDRom, /// Mini-Centronics Type-14 MiniCentronicsType14, /// Mini-Centronics Type-26 MiniCentronicsTyp26, /// Mini-jack (headphones) MiniJackHeadphones, /// BNC Bnc, /// 1394 Port1394, /// SAS/SATA Plug Receptacle SasSataPlugReceptacle, /// USB Type-C Receptacle UsbTypeCReceptacle, /// PC-98 PC98, /// PC-98Hireso PC98Hireso, /// PC-H98 PCH88, /// PC-98Note PC98Note, /// PC-98Full PC98Full, /// Other – Use Reference Designator Strings to supply information. Other, /// A value unknown to this standard, check the raw value None, } impl From for PortInformationConnectorTypeData { fn from(raw: u8) -> Self { PortInformationConnectorTypeData { value: match raw { 0x00 => PortInformationConnectorType::NoConnector, 0x01 => PortInformationConnectorType::Centronics, 0x02 => PortInformationConnectorType::MiniCentronics, 0x03 => PortInformationConnectorType::Proprietary, 0x04 => PortInformationConnectorType::DB25PinMale, 0x05 => PortInformationConnectorType::DB25PinFemale, 0x06 => PortInformationConnectorType::DB15PinMale, 0x07 => PortInformationConnectorType::DB15PinFemale, 0x08 => PortInformationConnectorType::DB9PinMale, 0x09 => PortInformationConnectorType::DB8PinFemale, 0x0A => PortInformationConnectorType::RJ11, 0x0B => PortInformationConnectorType::RJ45, 0x0C => PortInformationConnectorType::MiniScsi50Pin, 0x0D => PortInformationConnectorType::MiniDin, 0x0E => PortInformationConnectorType::MicroDin, 0x0F => PortInformationConnectorType::Ps2, 0x10 => PortInformationConnectorType::Infrared, 0x11 => PortInformationConnectorType::HpHil, 0x12 => PortInformationConnectorType::AccessBusUsb, 0x13 => PortInformationConnectorType::SsaScsi, 0x14 => PortInformationConnectorType::CircularDin8Male, 0x15 => PortInformationConnectorType::CircularDin8Female, 0x16 => PortInformationConnectorType::OnBoardIde, 0x17 => PortInformationConnectorType::OnBoardFloppy, 0x18 => PortInformationConnectorType::DualInline9Pin, 0x19 => PortInformationConnectorType::DualInline25Pin, 0x1A => PortInformationConnectorType::DualInline50Pin, 0x1B => PortInformationConnectorType::DualInline68Pin, 0x1C => PortInformationConnectorType::OnBoardSoundInputCDRom, 0x1D => PortInformationConnectorType::MiniCentronicsType14, 0x1E => PortInformationConnectorType::MiniCentronicsTyp26, 0x1F => PortInformationConnectorType::MiniJackHeadphones, 0x20 => PortInformationConnectorType::Bnc, 0x21 => PortInformationConnectorType::Port1394, 0x22 => PortInformationConnectorType::SasSataPlugReceptacle, 0x23 => PortInformationConnectorType::UsbTypeCReceptacle, 0xA0 => PortInformationConnectorType::PC98, 0xA1 => PortInformationConnectorType::PC98Hireso, 0xA2 => PortInformationConnectorType::PCH88, 0xA3 => PortInformationConnectorType::PC98Note, 0xA4 => PortInformationConnectorType::PC98Full, 0xFF => PortInformationConnectorType::Other, _ => PortInformationConnectorType::None, }, raw, } } } /// # Port Types Data pub struct PortInformationPortTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [PortInformationPortType] value pub value: PortInformationPortType, } impl fmt::Debug for PortInformationPortTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for PortInformationPortTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("PortInformationPortTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for PortInformationPortTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { PortInformationPortType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for PortInformationPortTypeData { type Target = PortInformationPortType; fn deref(&self) -> &Self::Target { &self.value } } /// # Port Types #[derive(Serialize, Debug, PartialEq, Eq)] pub enum PortInformationPortType { /// No Port NoPort, /// Parallel Port XT/AT Compatible ParallelPortXTATCompatible, /// Parallel Port PS/2 ParallelPortPS2, /// Parallel Port ECP ParallelPortEcp, /// Parallel Port EPP ParallelPortEpp, /// Parallel Port ECP/EPP ParallelPortEcpEpp, /// Serial Port XT/AT Compatible SerialPortXTATCompatible, /// Serial Port 16450 Compatible SerialPort16450Compatible, /// Serial Port 16550 Compatible SerialPort16550Compatible, /// Serial Port 16550A Compatible SerialPort16550ACompatible, /// SCSI Port ScsiPort, /// MIDI Port MidiPort, /// Joy Stick Port JoyStickPort, /// Keyboard Port KeyboardPort, /// Mouse Port MousePort, /// SSA SCSI SsaScsi, /// USB Usb, /// FireWire (IEEE P1394) Firewire, /// PCMCIA Type I2 PcmciaTypeI, /// PCMCIA Type II PcmcialTypeII, /// PCMCIA Type III PcmciaTypeIii, /// Cardbus Cardbus, /// Access Bus Port AccessBusPort, /// SCSI II ScsiII, /// SCSI Wide ScsiWide, /// PC-98 PC98, /// PC-98-Hireso PC98Hireso, /// PC-H98 PCH98, /// Video Port VideoPort, /// Audio Port AudioPort, /// Modem Port ModemPort, /// Network Port NetworkPort, /// SATA Sata, /// SAS Sas, /// MFDP (Multi-Function Display Port) Mfdp, /// Thunderbolt Thunderbolt, /// 8251 Compatible Port8251Compatible, /// 8251 FIFO Compatible Port8251FifoCompatible, /// Other Other, /// A value unknown to this standard, check the raw value None, } impl From for PortInformationPortTypeData { fn from(raw: u8) -> Self { PortInformationPortTypeData { value: match raw { 0x00 => PortInformationPortType::NoPort, 0x01 => PortInformationPortType::ParallelPortXTATCompatible, 0x02 => PortInformationPortType::ParallelPortPS2, 0x03 => PortInformationPortType::ParallelPortEcp, 0x04 => PortInformationPortType::ParallelPortEpp, 0x05 => PortInformationPortType::ParallelPortEcpEpp, 0x06 => PortInformationPortType::SerialPortXTATCompatible, 0x07 => PortInformationPortType::SerialPort16450Compatible, 0x08 => PortInformationPortType::SerialPort16550Compatible, 0x09 => PortInformationPortType::SerialPort16550ACompatible, 0x0A => PortInformationPortType::ScsiPort, 0x0B => PortInformationPortType::MidiPort, 0x0C => PortInformationPortType::JoyStickPort, 0x0D => PortInformationPortType::KeyboardPort, 0x0E => PortInformationPortType::MousePort, 0x0F => PortInformationPortType::SsaScsi, 0x10 => PortInformationPortType::Usb, 0x11 => PortInformationPortType::Firewire, 0x12 => PortInformationPortType::PcmciaTypeI, 0x13 => PortInformationPortType::PcmcialTypeII, 0x14 => PortInformationPortType::PcmciaTypeIii, 0x15 => PortInformationPortType::Cardbus, 0x16 => PortInformationPortType::AccessBusPort, 0x17 => PortInformationPortType::ScsiII, 0x18 => PortInformationPortType::ScsiWide, 0x19 => PortInformationPortType::PC98, 0x1A => PortInformationPortType::PC98Hireso, 0x1B => PortInformationPortType::PCH98, 0x1C => PortInformationPortType::VideoPort, 0x1D => PortInformationPortType::AudioPort, 0x1E => PortInformationPortType::ModemPort, 0x1F => PortInformationPortType::NetworkPort, 0x20 => PortInformationPortType::Sata, 0x21 => PortInformationPortType::Sas, 0x22 => PortInformationPortType::Mfdp, 0x23 => PortInformationPortType::Thunderbolt, 0xA0 => PortInformationPortType::Port8251Compatible, 0xA1 => PortInformationPortType::Port8251FifoCompatible, 0xFF => PortInformationPortType::Other, _ => PortInformationPortType::None, }, raw, } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type8 = vec![ 0x08, 0x09, 0x04, 0x00, 0x01, 0x00, 0x02, 0x0F, 0x0E, 0x4A, 0x31, 0x41, 0x31, 0x00, 0x50, 0x53, 0x32, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type8); let test_struct = SMBiosPortConnectorInformation::new(&parts); assert_eq!( test_struct.internal_reference_designator().to_string(), "J1A1".to_string() ); assert_eq!( *test_struct.internal_connector_type().unwrap(), PortInformationConnectorType::NoConnector ); assert_eq!( test_struct.external_reference_designator().to_string(), "PS2Mouse".to_string() ); assert_eq!( *test_struct.external_connector_type().unwrap(), PortInformationConnectorType::Ps2 ); assert_eq!( *test_struct.port_type().unwrap(), PortInformationPortType::MousePort ); } } smbios-lib-0.9.2/src/structs/types/portable_battery.rs000064400000000000000000000346271046102023000212620ustar 00000000000000use crate::core::{strings::*, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # Portable Battery (Type 22) /// /// This structure describes the attributes of the portable battery or batteries for the system. The structure /// contains the static attributes for the group. Each structure describes a single battery pack’s attributes. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosPortableBattery<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosPortableBattery<'a> { const STRUCT_TYPE: u8 = 22u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosPortableBattery<'a> { /// Identifies the location of the battery pub fn location(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Names the company that manufactured the battery pub fn manufacturer(&self) -> SMBiosString { self.parts.get_field_string(0x05) } /// The date on which the battery was manufactured. /// /// Version 2.2+ implementations that use a Smart /// Battery set this field to 0 (no string) to indicate /// that the SBDS Manufacture Date field contains /// the information. pub fn manufacture_date(&self) -> SMBiosString { self.parts.get_field_string(0x06) } /// The serial number for the battery /// /// Version 2.2+ implementations that use a Smart /// Battery set this field to 0 (no string) to indicate /// that the SBDS Serial Number field contains the /// information. pub fn serial_number(&self) -> SMBiosString { self.parts.get_field_string(0x07) } /// Names the battery device /// /// EXAMPLE: "DR-36" pub fn device_name(&self) -> SMBiosString { self.parts.get_field_string(0x08) } /// Identifies the battery chemistry /// /// Version 2.2+ implementations that use a Smart /// Battery set this field to 02h (Unknown) to /// indicate that the SBDS Device Chemistry field /// contains the information. pub fn device_chemistry(&self) -> Option { self.parts .get_field_byte(0x09) .map(|raw| PortableBatteryDeviceChemistryData::from(raw)) } /// Design capacity of the battery in mWatt-hours /// /// If the value is unknown, the field contains 0. /// /// For version 2.2+ implementations, this value is /// multiplied by the 'design_capacity_multiplier' to /// produce the actual value. pub fn design_capacity(&self) -> Option { self.parts .get_field_word(0x0A) .map(|raw| PortableBatteryDesignCapacity::from(raw)) } /// Design voltage of the battery in mVolts /// /// If the value is unknown, the field contains 0. pub fn design_voltage(&self) -> Option { self.parts .get_field_word(0x0C) .map(|raw| PortableBatteryDesignVoltage::from(raw)) } /// Contains the Smart Battery Data Specification version number /// supported by this battery /// /// If the battery does not support the function, no /// string is supplied. pub fn sbds_version_number(&self) -> SMBiosString { self.parts.get_field_string(0x0E) } /// Maximum error (as a percentage in the range 0 /// to 100) in the Watt-hour data reported by the /// battery, indicating an upper bound on how much /// additional energy the battery might have above /// the energy it reports having /// /// If the value is unknown, the field contains FFh. pub fn maximum_error_in_battery_data(&self) -> Option { self.parts.get_field_byte(0x0F) } /// 16-bit value that identifies the battery’s serial /// number /// /// This value, when combined with the /// Manufacturer, Device Name, and Manufacture /// Date, uniquely identifies the battery. The Serial /// Number field must be set to 0 (no string) for this /// field to be valid. pub fn sbds_serial_number(&self) -> Option { self.parts.get_field_word(0x10) } /// Date the cell pack was manufactured, in packed /// format pub fn sbds_manufacture_date(&self) -> Option { self.parts.get_field_word(0x12) } /// Number of the string that identifies the battery /// chemistry (for example, “PbAc”) /// The Device Chemistry field must be set to 02h /// (Unknown) for this field to be valid. pub fn sbds_device_chemistry(&self) -> SMBiosString { self.parts.get_field_string(0x14) } /// Multiplication factor of the Design Capacity /// value, which assures that the mWatt hours value /// does not overflow for SBDS implementations /// /// The multiplier default is 1, SBDS /// implementations use the value 10 to correspond /// to the data as returned from the SBDS Function /// 18h. pub fn design_capacity_multiplier(&self) -> Option { self.parts.get_field_byte(0x15) } /// Contains OEM- or BIOS vendor-specific /// information pub fn oem_specific(&self) -> Option { self.parts.get_field_dword(0x16) } } impl fmt::Debug for SMBiosPortableBattery<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("location", &self.location()) .field("manufacturer", &self.manufacturer()) .field("manufacture_date", &self.manufacture_date()) .field("serial_number", &self.serial_number()) .field("device_name", &self.device_name()) .field("device_chemistry", &self.device_chemistry()) .field("design_capacity", &self.design_capacity()) .field("design_voltage", &self.design_voltage()) .field("sbds_version_number", &self.sbds_version_number()) .field( "maximum_error_in_battery_data", &self.maximum_error_in_battery_data(), ) .field("sbds_serial_number", &self.sbds_serial_number()) .field("sbds_manufacture_date", &self.sbds_manufacture_date()) .field("sbds_device_chemistry", &self.sbds_device_chemistry()) .field( "design_capacity_multiplier", &self.design_capacity_multiplier(), ) .field("oem_specific", &self.oem_specific()) .finish() } } impl Serialize for SMBiosPortableBattery<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosPortableBattery", 16)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("location", &self.location())?; state.serialize_field("manufacturer", &self.manufacturer())?; state.serialize_field("manufacture_date", &self.manufacture_date())?; state.serialize_field("serial_number", &self.serial_number())?; state.serialize_field("device_name", &self.device_name())?; state.serialize_field("device_chemistry", &self.device_chemistry())?; state.serialize_field("design_capacity", &self.design_capacity())?; state.serialize_field("design_voltage", &self.design_voltage())?; state.serialize_field("sbds_version_number", &self.sbds_version_number())?; state.serialize_field( "maximum_error_in_battery_data", &self.maximum_error_in_battery_data(), )?; state.serialize_field("sbds_serial_number", &self.sbds_serial_number())?; state.serialize_field("sbds_manufacture_date", &self.sbds_manufacture_date())?; state.serialize_field("sbds_device_chemistry", &self.sbds_device_chemistry())?; state.serialize_field( "design_capacity_multiplier", &self.design_capacity_multiplier(), )?; state.serialize_field("oem_specific", &self.oem_specific())?; state.end() } } /// # Portable Battery - Device Chemistry Data pub struct PortableBatteryDeviceChemistryData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [PortableBatteryDeviceChemistry] value pub value: PortableBatteryDeviceChemistry, } impl fmt::Debug for PortableBatteryDeviceChemistryData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for PortableBatteryDeviceChemistryData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("PortableBatteryDeviceChemistryData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for PortableBatteryDeviceChemistryData { type Target = PortableBatteryDeviceChemistry; fn deref(&self) -> &Self::Target { &self.value } } /// # Portable Battery - Device Chemistry #[derive(Serialize, Debug, PartialEq, Eq)] pub enum PortableBatteryDeviceChemistry { /// Other Other, /// Unknown /// /// Version 2.2+ implementations that use a Smart Battery /// set this field to 02h (Unknown) to indicate that the /// 'sbds_device_chemistry' field contains the information. Unknown, /// Lead Acid LeadAcid, /// Nickel Cadmium NickelCadmium, /// Nickel metal hydride NickelMetalHydride, /// Lithium-ion LithiumIon, /// Zinc air ZincAir, /// Lithium Polymer LithiumPolymer, /// A value unknown to this standard, check the raw value None, } impl From for PortableBatteryDeviceChemistryData { fn from(raw: u8) -> Self { PortableBatteryDeviceChemistryData { value: match raw { 0x01 => PortableBatteryDeviceChemistry::Other, 0x02 => PortableBatteryDeviceChemistry::Unknown, 0x03 => PortableBatteryDeviceChemistry::LeadAcid, 0x04 => PortableBatteryDeviceChemistry::NickelCadmium, 0x05 => PortableBatteryDeviceChemistry::NickelMetalHydride, 0x06 => PortableBatteryDeviceChemistry::LithiumIon, 0x07 => PortableBatteryDeviceChemistry::ZincAir, 0x08 => PortableBatteryDeviceChemistry::LithiumPolymer, _ => PortableBatteryDeviceChemistry::None, }, raw, } } } /// # Portable Battery - Design Capacity #[derive(Serialize, Debug, PartialEq, Eq)] pub enum PortableBatteryDesignCapacity { /// Design capacity of the battery in mWatt-hours /// /// For version 2.2+ implementations, this value is /// multiplied by the 'design_capacity_multiplier' to /// produce the actual value. MilliWattHours(u16), /// Design capacity of the battery in mWatt-hours is unknown. Unknown, } impl From for PortableBatteryDesignCapacity { fn from(raw: u16) -> Self { match raw { 0 => PortableBatteryDesignCapacity::Unknown, _ => PortableBatteryDesignCapacity::MilliWattHours(raw), } } } /// # Portable Battery - Design Voltage #[derive(Serialize, Debug, PartialEq, Eq)] pub enum PortableBatteryDesignVoltage { /// Design voltage of the battery in mVolts. MilliVolts(u16), /// Design voltage of the battery in mVolts is unknown. Unknown, } impl From for PortableBatteryDesignVoltage { fn from(raw: u16) -> Self { match raw { 0 => PortableBatteryDesignVoltage::Unknown, _ => PortableBatteryDesignVoltage::MilliVolts(raw), } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type22 = vec![ 0x16, 0x1A, 0x2E, 0x00, 0x01, 0x02, 0x00, 0x00, 0x03, 0x02, 0xFB, 0x11, 0xD0, 0x39, 0x04, 0xFF, 0xC7, 0x02, 0x7A, 0x42, 0x05, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x52, 0x65, 0x61, 0x72, 0x00, 0x53, 0x4D, 0x50, 0x00, 0x34, 0x35, 0x4E, 0x31, 0x30, 0x37, 0x31, 0x00, 0x30, 0x33, 0x2E, 0x30, 0x31, 0x00, 0x4C, 0x69, 0x50, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type22); let test_struct = SMBiosPortableBattery::new(&parts); assert_eq!(test_struct.location().to_string(), "Rear".to_string()); assert_eq!(test_struct.manufacturer().to_string(), "SMP".to_string()); assert_eq!(test_struct.manufacture_date().to_string(), "".to_string()); assert_eq!(test_struct.serial_number().to_string(), "".to_string()); assert_eq!(test_struct.device_name().to_string(), "45N1071".to_string()); assert_eq!( *test_struct.device_chemistry().unwrap(), PortableBatteryDeviceChemistry::Unknown ); match test_struct.design_capacity().unwrap() { PortableBatteryDesignCapacity::MilliWattHours(mwh) => assert_eq!(mwh, 4603), PortableBatteryDesignCapacity::Unknown => panic!("expected a value in mWH"), } match test_struct.design_voltage().unwrap() { PortableBatteryDesignVoltage::MilliVolts(mv) => assert_eq!(mv, 14800), PortableBatteryDesignVoltage::Unknown => panic!("expected a value in mWH"), } assert_eq!( test_struct.sbds_version_number().to_string(), "03.01".to_string() ); assert_eq!(test_struct.maximum_error_in_battery_data(), Some(255)); assert_eq!(test_struct.sbds_serial_number(), Some(711)); assert_eq!(test_struct.sbds_manufacture_date(), Some(17018)); assert_eq!( test_struct.sbds_device_chemistry().to_string(), "LiP".to_string() ); assert_eq!(test_struct.design_capacity_multiplier(), Some(10)); assert_eq!(test_struct.oem_specific(), Some(0)); } } smbios-lib-0.9.2/src/structs/types/processor_additional_information.rs000064400000000000000000000241221046102023000245210ustar 00000000000000use crate::core::{Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # Processor Additional Information (Type 44) /// /// The information in this structure defines the processor additional information in case SMBIOS type 4 [super::SMBiosProcessorInformation] is /// not sufficient to describe processor characteristics. The SMBIOS type 44 structure has a reference /// handle field to link back to the related SMBIOS type 4 structure. There may be multiple SMBIOS type 44 /// structures linked to the same SMBIOS type 4 structure. For example, when cores are not identical in a /// processor, SMBIOS type 44 structures describe different core-specific information. /// /// SMBIOS type 44 defines the standard header for the processor-specific block, while the /// contents of processor-specific data are maintained by processor architecture workgroups or vendors in /// separate documents. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.7.0 (DSP0134) /// Document Date: 2023-07-21 pub struct SMBiosProcessorAdditionalInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosProcessorAdditionalInformation<'a> { const STRUCT_TYPE: u8 = 44u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosProcessorAdditionalInformation<'a> { /// Offset of the ProcessorSpecificBlock field. const PROCESSOR_SPECIFIC_BLOCK_OFFSET: usize = 0x06usize; /// Handle, or instance number, associated with the /// [super::SMBiosProcessorInformation] structure (SMBIOS type 4) which the /// Processor Additional Information structure describes. pub fn referenced_handle(&self) -> Option { self.parts.get_field_handle(0x04) } /// Processor-Specific Block pub fn processor_specific_block(&self) -> Option> { ProcessorSpecificBlock::new(self) } } impl fmt::Debug for SMBiosProcessorAdditionalInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::< SMBiosProcessorAdditionalInformation<'_>, >()) .field("header", &self.parts.header) .field("referenced_handle", &self.referenced_handle()) .field("processor_specific_block", &self.processor_specific_block()) .finish() } } impl Serialize for SMBiosProcessorAdditionalInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosProcessorAdditionalInformation", 3)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("referenced_handle", &self.referenced_handle())?; state.serialize_field("processor_specific_block", &self.processor_specific_block())?; state.end() } } /// # Processor Specific Block contained within [SMBiosProcessorAdditionalInformation] pub struct ProcessorSpecificBlock<'a> { /// Raw byte slice for this processor specific block pub raw: &'a [u8], } impl<'a> ProcessorSpecificBlock<'a> { /// 'block_length' offset const BLOCK_LENGTH_OFFSET: usize = 0x00usize; /// 'processor_type' offset const PROCESSOR_TYPE_OFFSET: usize = 0x01usize; /// 'processor_specific_data' offset const PROCESSOR_SPECIFIC_DATA_OFFSET: usize = 0x02usize; fn new(additional_information: &'a SMBiosProcessorAdditionalInformation<'a>) -> Option { additional_information .parts() .get_field_byte( SMBiosProcessorAdditionalInformation::PROCESSOR_SPECIFIC_BLOCK_OFFSET + Self::BLOCK_LENGTH_OFFSET, ) .and_then(|block_length| { additional_information .parts() .get_field_data( SMBiosProcessorAdditionalInformation::PROCESSOR_SPECIFIC_BLOCK_OFFSET + Self::BLOCK_LENGTH_OFFSET, block_length as usize + SMBiosProcessorAdditionalInformation::PROCESSOR_SPECIFIC_BLOCK_OFFSET + Self::PROCESSOR_SPECIFIC_DATA_OFFSET, ) .map(|raw| Self { raw }) }) } /// Length of 'processor_specific_data' pub fn block_length(&self) -> u8 { self.raw[Self::BLOCK_LENGTH_OFFSET] } /// The processor architecture delineated by this 'ProcessorSpecificBlock'. pub fn processor_type(&self) -> ProcessorArchitectureTypeData { ProcessorArchitectureTypeData::from(self.raw[Self::PROCESSOR_TYPE_OFFSET]) } /// Offset of the field within the structure referenced by the /// _Referenced Handle_ for which additional information is provided pub fn processor_specific_data(&self) -> &'a [u8] { &self.raw[Self::PROCESSOR_SPECIFIC_DATA_OFFSET..] } } impl fmt::Debug for ProcessorSpecificBlock<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("block_length", &self.block_length()) .field("processor_type", &self.processor_type()) .field("processor_specific_data", &self.processor_specific_data()) .finish() } } impl Serialize for ProcessorSpecificBlock<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ProcessorSpecificBlock", 3)?; state.serialize_field("block_length", &self.block_length())?; state.serialize_field("processor_type", &self.processor_type())?; state.serialize_field("processor_specific_data", &self.processor_specific_data())?; state.end() } } /// # Processor Architecture Types Data pub struct ProcessorArchitectureTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [ProcessorArchitectureType] value pub value: ProcessorArchitectureType, } impl fmt::Debug for ProcessorArchitectureTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for ProcessorArchitectureTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ProcessorArchitectureTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for ProcessorArchitectureTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { ProcessorArchitectureType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for ProcessorArchitectureTypeData { type Target = ProcessorArchitectureType; fn deref(&self) -> &Self::Target { &self.value } } /// # Processor Architecture Types #[derive(Serialize, Debug, PartialEq, Eq)] pub enum ProcessorArchitectureType { /// IA32 (x86) IA32, /// x64 (x86-64, Intel64, AMD64, EM64T) X64, /// Intel® Itanium® architecture IntelItanium, /// 32-bit ARM (Aarch32) Arm32Bit, /// 64-bit ARM (Aarch64) Arm64Bit, /// 32-bit RISC-V (RV32) RiscV32Bit, /// 64-bit RISC-V (RV64) RiscV64Bit, /// 128-bit RISC-V (RV128) RiscV128Bit, /// 32-bit LoongArch (LoongArch32) LoongArch32, /// 64-bit LoongArch (LoongArch64) LoongArch64, /// A value unknown to this standard, check the raw value None, } impl From for ProcessorArchitectureTypeData { fn from(raw: u8) -> Self { ProcessorArchitectureTypeData { value: match raw { 0x01 => ProcessorArchitectureType::IA32, 0x02 => ProcessorArchitectureType::X64, 0x03 => ProcessorArchitectureType::IntelItanium, 0x04 => ProcessorArchitectureType::Arm32Bit, 0x05 => ProcessorArchitectureType::Arm64Bit, 0x06 => ProcessorArchitectureType::RiscV32Bit, 0x07 => ProcessorArchitectureType::RiscV64Bit, 0x08 => ProcessorArchitectureType::RiscV128Bit, 0x09 => ProcessorArchitectureType::LoongArch32, 0x10 => ProcessorArchitectureType::LoongArch64, _ => ProcessorArchitectureType::None, }, raw, } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let block_length = 3u8; let processor_type = 0x07u8; // RiscV64Bit let struct_type44 = vec![ 44u8, 6 + block_length + 2, 0x2E, 0x00, // header 0x08, 0x09, // referenced handle block_length, processor_type, 0x03, 0x02, 0x01, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type44); let test_struct = SMBiosProcessorAdditionalInformation::new(&parts); assert_eq!(*test_struct.referenced_handle().unwrap(), 0x0908); let processor_specific_block = test_struct.processor_specific_block().unwrap(); assert_eq!(processor_specific_block.block_length(), 3); assert_eq!( *processor_specific_block.processor_type(), ProcessorArchitectureType::RiscV64Bit ); assert_eq!( processor_specific_block.processor_specific_data(), &[0x03, 0x02, 0x01] ); } } smbios-lib-0.9.2/src/structs/types/processor_information.rs000064400000000000000000002253251046102023000223410ustar 00000000000000use crate::core::{strings::*, Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::convert::TryInto; use std::fmt; use std::ops::Deref; /// # Processor Information (Type 4) /// /// The information in this structure defines the attributes of a single processor; a separate /// structure instance is provided for each system processor socket/slot. For example, a system with an /// IntelDX2™ processor would have a single structure instance while a system with an IntelSX2™ processor /// would have a structure to describe the main CPU and a second structure to describe the 80487 co1021 processor. /// /// NOTE One structure is provided for each processor instance in a system. For example, a system that supports up /// to two processors includes two Processor Information structures — even if only one processor is currently /// installed. Software that interprets the SMBIOS information can count the Processor Information structures to /// determine the maximum possible configuration of the system. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.7.0 (DSP0134) /// Document Date: 2023-07-21 pub struct SMBiosProcessorInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosProcessorInformation<'a> { const STRUCT_TYPE: u8 = 4u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosProcessorInformation<'a> { /// Socket reference designation /// /// EXAMPLE: "J202" pub fn socket_designation(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Processor type pub fn processor_type(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| ProcessorTypeData::from(raw)) } /// Processor family pub fn processor_family(&self) -> Option { self.parts .get_field_byte(0x06) .map(|raw| ProcessorFamilyData::from(raw)) } /// Processor manufacturer pub fn processor_manufacturer(&self) -> SMBiosString { self.parts.get_field_string(0x07) } /// Raw processor identification data pub fn processor_id(&self) -> Option<&[u8; 8]> { // Note: There are two more levels to the design of ProcessorId to consider. // 1. These 8 bytes can represent one of 4 classes of processor (see 7.5.3) // perhaps return an enum with 4 variants. // 2. Per variant the data represents specific Id information which can be // accomodated in specific representative structures. self.parts .get_field_data(0x08, 0x10) .map(|raw| raw.try_into().expect("incorrect length")) } /// Processor version pub fn processor_version(&self) -> SMBiosString { self.parts.get_field_string(0x10) } /// Voltage pub fn voltage(&self) -> Option { self.parts .get_field_byte(0x11) .map(|raw| ProcessorVoltage::from(raw)) } /// External clock frequency, in MHz /// /// If the value is unknown, the field is set to 0. pub fn external_clock(&self) -> Option { self.parts .get_field_word(0x12) .map(|raw| ProcessorExternalClock::from(raw)) } /// Maximum processor speed (in MHz) supported /// by the system for this processor socket /// /// 0E9h is for a 233 MHz processor. /// /// NOTE: This field identifies a capability for the system, /// not the processor itself. pub fn max_speed(&self) -> Option { self.parts .get_field_word(0x14) .map(|raw| ProcessorSpeed::from(raw)) } /// Current speed /// /// Same format as Max Speed /// /// NOTE: This field identifies the processor's speed at /// system boot; the processor may support /// more than one speed. pub fn current_speed(&self) -> Option { self.parts .get_field_word(0x16) .map(|raw| ProcessorSpeed::from(raw)) } /// Status bit field pub fn status(&self) -> Option { self.parts .get_field_byte(0x18) .map(|raw| ProcessorStatus::from(raw)) } /// Processor upgrade pub fn processor_upgrade(&self) -> Option { self.parts .get_field_byte(0x19) .map(|raw| ProcessorUpgradeData::from(raw)) } /// Handle of a [super::SMBiosCacheInformation] structure that /// defines the attributes of the primary (Level 1) /// cache for this processor /// /// For version 2.1 and version 2.2 /// implementations, the value is 0FFFFh if the /// processor has no L1 cache. For version 2.3 and /// later implementations, the value is 0FFFFh if /// the Cache Information structure is not provided. pub fn l1cache_handle(&self) -> Option { self.parts.get_field_handle(0x1A) } /// Handle of a [super::SMBiosCacheInformation] structure that /// defines the attributes of the primary (Level 2) /// cache for this processor /// /// For version 2.1 and version 2.2 /// implementations, the value is 0FFFFh if the /// processor has no L2 cache. For version 2.3 and /// later implementations, the value is 0FFFFh if /// the Cache Information structure is not provided. pub fn l2cache_handle(&self) -> Option { self.parts.get_field_handle(0x1C) } /// Handle of a [super::SMBiosCacheInformation] structure that /// defines the attributes of the primary (Level 3) /// cache for this processor /// /// For version 2.1 and version 2.2 /// implementations, the value is 0FFFFh if the /// processor has no L3 cache. For version 2.3 and /// later implementations, the value is 0FFFFh if /// the Cache Information structure is not provided. pub fn l3cache_handle(&self) -> Option { self.parts.get_field_handle(0x1E) } /// The serial number of this processor /// /// This value is set by the manufacturer and /// normally not changeable. pub fn serial_number(&self) -> SMBiosString { self.parts.get_field_string(0x20) } /// The asset tag of this processor pub fn asset_tag(&self) -> SMBiosString { self.parts.get_field_string(0x21) } /// The part number of this processor /// /// This value is set by the manufacturer and /// normally not changeable. pub fn part_number(&self) -> SMBiosString { self.parts.get_field_string(0x22) } /// Number of cores per processor socket /// /// For core counts of 256 or greater, the /// 'core_count_2' field is set to the number of cores. pub fn core_count(&self) -> Option { self.parts .get_field_byte(0x23) .map(|raw| CoreCount::from(raw)) } /// Number of enabled cores per processor socket /// /// For core counts of 256 or greater, the /// 'cores_enabled_2' field is set to the number of enabled /// cores. pub fn cores_enabled(&self) -> Option { self.parts .get_field_byte(0x24) .map(|raw| CoresEnabled::from(raw)) } /// Number of threads per processor socket /// /// For thread counts of 256 or greater, /// 'thread_count_2' field is set to the number of /// threads. pub fn thread_count(&self) -> Option { self.parts .get_field_byte(0x25) .map(|raw| ThreadCount::from(raw)) } /// Defines which functions the processor supports pub fn processor_characteristics(&self) -> Option { self.parts .get_field_word(0x26) .map(|raw| ProcessorCharacteristics::from(raw)) } /// Processor family 2 pub fn processor_family_2(&self) -> Option { self.parts .get_field_word(0x28) .map(|raw| ProcessorFamilyData2::from(raw)) } /// Number of Cores per processor socket. /// /// Supports core counts >255. If this field is /// present, it holds the core count for the /// processor socket. 'core_count' will also hold the /// core count, except for core counts that are 256 /// or greater. In that case, 'core_count' shall be set /// to 'CoreCount::SeeCoreCount2' and 'core_count_2' will hold the count. pub fn core_count_2(&self) -> Option { self.parts .get_field_word(0x2A) .map(|raw| CoreCount2::from(raw)) } /// Number of enabled cores per processor socket. /// /// Supports core enabled counts >255. If this field /// is present, it holds the core enabled count for /// the processor socket. 'cores_enabled' will also /// hold the core enabled count, except for core /// counts that are 256 or greater. In that case, /// 'cores_enabled' shall be set to 'CoresEnabled::SeeCoresEnabled2' /// and 'cores_enabled_2' will hold the count. pub fn cores_enabled_2(&self) -> Option { self.parts .get_field_word(0x2C) .map(|raw| CoresEnabled2::from(raw)) } /// Number of threads per processor socket. /// /// Supports thread counts >255. If this field is /// present, it holds the thread count for the /// processor socket. 'thread_count' will also hold /// the thread count, except for thread counts that /// are 256 or greater. In that case, 'thread_count' /// shall be set to 'ThreadCount::SeeThreadCount2' /// and 'thread_count_2' will hold the count. pub fn thread_count_2(&self) -> Option { self.parts .get_field_word(0x2E) .map(|raw| ThreadCount2::from(raw)) } /// Number of threads the BIOS has enabled and available for operating /// system use. /// /// For example, if the BIOS detects a dual-core processor with two threads /// supported in each core /// • And it leaves both threads enabled, it reports a value of 4. /// • And it disables multi-threading support, it reports a value of 2. pub fn thread_enabled(&self) -> Option { self.parts .get_field_word(0x30) .map(|raw| ThreadEnabled::from(raw)) } } impl fmt::Debug for SMBiosProcessorInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("socket_designation", &self.socket_designation()) .field("processor_type", &self.processor_type()) .field("processor_family", &self.processor_family()) .field("processor_manufacturer", &self.processor_manufacturer()) .field("processor_id", &self.processor_id()) .field("processor_version", &self.processor_version()) .field("voltage", &self.voltage()) .field("external_clock", &self.external_clock()) .field("max_speed", &self.max_speed()) .field("current_speed", &self.current_speed()) .field("status", &self.status()) .field("processor_upgrade", &self.processor_upgrade()) .field("l1cache_handle", &self.l1cache_handle()) .field("l2cache_handle", &self.l2cache_handle()) .field("l3cache_handle", &self.l3cache_handle()) .field("serial_number", &self.serial_number()) .field("asset_tag", &self.asset_tag()) .field("part_number", &self.part_number()) .field("core_count", &self.core_count()) .field("cores_enabled", &self.cores_enabled()) .field("thread_count", &self.thread_count()) .field( "processor_characteristics", &self.processor_characteristics(), ) .field("processor_family_2", &self.processor_family_2()) .field("core_count_2", &self.core_count_2()) .field("cores_enabled_2", &self.cores_enabled_2()) .field("thread_count_2", &self.thread_count_2()) .field("thread_enabled", &self.thread_enabled()) .finish() } } impl Serialize for SMBiosProcessorInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosProcessorInformation", 27)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("socket_designation", &self.socket_designation())?; state.serialize_field("processor_type", &self.processor_type())?; state.serialize_field("processor_family", &self.processor_family())?; state.serialize_field("processor_manufacturer", &self.processor_manufacturer())?; state.serialize_field("processor_id", &self.processor_id())?; state.serialize_field("processor_version", &self.processor_version())?; state.serialize_field("voltage", &self.voltage())?; state.serialize_field("external_clock", &self.external_clock())?; state.serialize_field("max_speed", &self.max_speed())?; state.serialize_field("current_speed", &self.current_speed())?; state.serialize_field("status", &self.status())?; state.serialize_field("processor_upgrade", &self.processor_upgrade())?; state.serialize_field("l1cache_handle", &self.l1cache_handle())?; state.serialize_field("l2cache_handle", &self.l2cache_handle())?; state.serialize_field("l3cache_handle", &self.l3cache_handle())?; state.serialize_field("serial_number", &self.serial_number())?; state.serialize_field("asset_tag", &self.asset_tag())?; state.serialize_field("part_number", &self.part_number())?; state.serialize_field("core_count", &self.core_count())?; state.serialize_field("cores_enabled", &self.cores_enabled())?; state.serialize_field("thread_count", &self.thread_count())?; state.serialize_field( "processor_characteristics", &self.processor_characteristics(), )?; state.serialize_field("processor_family_2", &self.processor_family_2())?; state.serialize_field("core_count_2", &self.core_count_2())?; state.serialize_field("cores_enabled_2", &self.cores_enabled_2())?; state.serialize_field("thread_count_2", &self.thread_count_2())?; state.serialize_field("thread_enabled", &self.thread_enabled())?; state.end() } } /// # Processor Type Data pub struct ProcessorTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [ProcessorType] value pub value: ProcessorType, } impl fmt::Debug for ProcessorTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for ProcessorTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ProcessorTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for ProcessorTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { ProcessorType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for ProcessorTypeData { type Target = ProcessorType; fn deref(&self) -> &Self::Target { &self.value } } /// # Processor Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum ProcessorType { /// Other Other, /// Unknown Unknown, /// Central Processor CentralProcessor, /// Math Processor MathProcessor, /// DSP Processor DspProcessor, /// Video Processor VideoProcessor, /// A value unknown to this standard, check the raw value None, } impl From for ProcessorTypeData { fn from(raw: u8) -> Self { ProcessorTypeData { value: match raw { 0x01 => ProcessorType::Other, 0x02 => ProcessorType::Unknown, 0x03 => ProcessorType::CentralProcessor, 0x04 => ProcessorType::MathProcessor, 0x05 => ProcessorType::DspProcessor, 0x06 => ProcessorType::VideoProcessor, _ => ProcessorType::None, }, raw, } } } /// # Processor Family Data pub struct ProcessorFamilyData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [ProcessorFamily] value pub value: ProcessorFamily, } impl fmt::Debug for ProcessorFamilyData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for ProcessorFamilyData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ProcessorFamilyData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for ProcessorFamilyData { /// Displays ProcessorFamily either by name or as a hex value if the name for the value is unknown. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { ProcessorFamily::None => write!(f, "{:#X}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for ProcessorFamilyData { type Target = ProcessorFamily; fn deref(&self) -> &Self::Target { &self.value } } impl From for ProcessorFamilyData { fn from(raw: u8) -> Self { ProcessorFamilyData { value: ProcessorFamily::from(raw as u16), raw, } } } /// # Processor Family Data #2 pub struct ProcessorFamilyData2 { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u16, /// The contained [ProcessorFamily] value pub value: ProcessorFamily, } impl fmt::Debug for ProcessorFamilyData2 { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for ProcessorFamilyData2 { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ProcessorFamilyData2", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for ProcessorFamilyData2 { /// Displays ProcessorFamily either by name or as a hex value if the name for the value is unknown. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { ProcessorFamily::None => write!(f, "{:#X}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for ProcessorFamilyData2 { type Target = ProcessorFamily; fn deref(&self) -> &Self::Target { &self.value } } impl From for ProcessorFamilyData2 { fn from(raw: u16) -> Self { ProcessorFamilyData2 { value: ProcessorFamily::from(raw), raw, } } } /// # Processor Family #[derive(Serialize, Debug, PartialEq, Eq)] pub enum ProcessorFamily { /// Other Other, /// Unknown Unknown, /// 8086 I8086, /// 80286 I80286, /// Intel386™ processor Intel386Processor, /// Intel486™ processor Intel486Processor, /// 8087 I8087, /// 80287 I80287, /// 80387 I80387, /// 80487 I80487, /// Intel® Pentium® processor IntelPentiumProcessor, /// Pentium® Pro processor PentiumProProcessor, /// Pentium® II processor PentiumIIProcessor, /// Pentium® processor with MMX™ technology PentiumprocessorwithMMXtechnology, /// Intel® Celeron® processor IntelCeleronProcessor, /// Pentium® II Xeon™ processor PentiumIIXeonProcessor, /// Pentium® III processor PentiumIIIProcessor, /// M1 Family M1Family, /// M2 Family M2Family, /// Intel® Celeron® M processor IntelCeleronMProcessor, /// Intel® Pentium® 4 HT processor IntelPentium4HTProcessor, /// AMD Duron™ Processor Family AMDDuronProcessorFamily, /// K5 Family K5Family, /// K6 Family K6Family, /// K6-2 K62, /// K6-3 K63, /// AMD Athlon™ Processor Family AMDAthlonProcessorFamily, /// AMD29000 Family AMD29000Family, /// K6-2+ K62Plus, /// Power PC Family PowerPCFamily, /// Power PC 601 PowerPC601, /// Power PC 603 PowerPC603, /// Power PC 603+ PowerPC603Plus, /// Power PC 604 PowerPC604, /// Power PC 620 PowerPC620, /// Power PC x704 PowerPCx704, /// Power PC 750 PowerPC750, /// Intel® Core™ Duo processor IntelCoreDuoProcessor, /// Intel® Core™ Duo mobile processor IntelCoreDuomobileProcessor, /// Intel® Core™ Solo mobile processor IntelCoreSolomobileProcessor, /// Intel® Atom™ processor IntelAtomProcessor, /// Intel® Core™ M processor IntelCoreMProcessor, /// Intel(R) Core(TM) m3 processor IntelCorem3Processor, /// Intel(R) Core(TM) m5 processor IntelCorem5Processor, /// Intel(R) Core(TM) m7 processor IntelCorem7Processor, /// Alpha Family AlphaFamily, /// Alpha 21064 Alpha21064, /// Alpha 21066 Alpha21066, /// Alpha 21164 Alpha21164, /// Alpha 21164PC Alpha21164PC, /// Alpha 21164a Alpha21164a, /// Alpha 21264 Alpha21264, /// Alpha 21364 Alpha21364, /// AMD Turion™ II Ultra Dual-Core Mobile M Processor Family AMDTurionIIUltraDualCoreMobileMProcessorFamily, /// AMD Turion™ II Dual-Core Mobile M Processor Family AMDTurionIIDualCoreMobileMProcessorFamily, /// AMD Athlon™ II Dual-Core M Processor Family AMDAthlonIIDualCoreMProcessorFamily, /// AMD Opteron™ 6100 Series Processor AMDOpteron6100SeriesProcessor, /// AMD Opteron™ 4100 Series Processor AMDOpteron4100SeriesProcessor, /// AMD Opteron™ 6200 Series Processor AMDOpteron6200SeriesProcessor, /// AMD Opteron™ 4200 Series Processor AMDOpteron4200SeriesProcessor, /// AMD FX™ Series Processor AMDFXSeriesProcessor, /// MIPS Family MIPSFamily, /// MIPS R4000 MIPSR4000, /// MIPS R4200 MIPSR4200, /// MIPS R4400 MIPSR4400, /// MIPS R4600 MIPSR4600, /// MIPS R10000 MIPSR10000, /// AMD C-Series Processor AMDCSeriesProcessor, /// AMD E-Series Processor AMDESeriesProcessor, /// AMD A-Series Processor AMDASeriesProcessor, /// AMD G-Series Processor AMDGSeriesProcessor, /// AMD Z-Series Processor AMDZSeriesProcessor, /// AMD R-Series Processor AMDRSeriesProcessor, /// AMD Opteron™ 4300 Series Processor AMDOpteron4300SeriesProcessor, /// AMD Opteron™ 6300 Series Processor AMDOpteron6300SeriesProcessor, /// AMD Opteron™ 3300 Series Processor AMDOpteron3300SeriesProcessor, /// AMD FirePro™ Series Processor AMDFireProSeriesProcessor, /// SPARC Family SPARCFamily, /// SuperSPARC SuperSPARC, /// microSPARC II MicroSparcii, /// microSPARC IIep MicroSparciiep, /// UltraSPARC UltraSPARC, /// UltraSPARC II UltraSPARCII, /// UltraSPARC Iii UltraSPARCIii, /// UltraSPARC III UltraSPARCIII, /// UltraSPARC IIIi UltraSPARCIIIi, /// 68040 Family M68040Family, /// 68xxx M68xxx, /// 68000 M68000, /// 68010 M68010, /// 68020 M68020, /// 68030 M68030, /// AMD Athlon(TM) X4 Quad-Core Processor Family AMDAthlonX4QuadCoreProcessorFamily, /// AMD Opteron(TM) X1000 Series Processor AMDOpteronX1000SeriesProcessor, /// AMD Opteron(TM) X2000 Series APU AMDOpteronX2000SeriesAPU, /// AMD Opteron(TM) A-Series Processor AMDOpteronASeriesProcessor, /// AMD Opteron(TM) X3000 Series APU AMDOpteronX3000SeriesAPU, /// AMD Zen Processor Family AMDZenProcessorFamily, /// Hobbit Family HobbitFamily, /// Crusoe™ TM5000 Family CrusoeTM5000Family, /// Crusoe™ TM3000 Family CrusoeTM3000Family, /// Efficeon™ TM8000 Family EfficeonTM8000Family, /// Weitek Weitek, /// Itanium™ processor Itaniumprocessor, /// AMD Athlon™ 64 Processor Family AMDAthlon64ProcessorFamily, /// AMD Opteron™ Processor Family AMDOpteronProcessorFamily, /// AMD Sempron™ Processor Family AMDSempronProcessorFamily, /// AMD Turion™ 64 Mobile Technology AMDTurion64MobileTechnology, /// Dual-Core AMD Opteron™ Processor Family DualCoreAMDOpteronProcessorFamily, /// AMD Athlon™ 64 X2 Dual-Core Processor Family AMDAthlon64X2DualCoreProcessorFamily, /// AMD Turion™ 64 X2 Mobile Technology AMDTurion64X2MobileTechnology, /// Quad-Core AMD Opteron™ Processor Family QuadCoreAMDOpteronProcessorFamily, /// Third-Generation AMD Opteron™ Processor Family ThirdGenerationAMDOpteronProcessorFamily, /// AMD Phenom™ FX Quad-Core Processor Family AMDPhenomFXQuadCoreProcessorFamily, /// AMD Phenom™ X4 Quad-Core Processor Family AMDPhenomX4QuadCoreProcessorFamily, /// AMD Phenom™ X2 Dual-Core Processor Family AMDPhenomX2DualCoreProcessorFamily, /// AMD Athlon™ X2 Dual-Core Processor Family AMDAthlonX2DualCoreProcessorFamily, /// PA-RISC Family PARISCFamily, /// PA-RISC 8500 PARISC8500, /// PA-RISC 8000 PARISC8000, /// PA-RISC 7300LC PARISC7300LC, /// PA-RISC 7200 PARISC7200, /// PA-RISC 7100LC PARISC7100LC, /// PA-RISC 7100 PARISC7100, /// V30 Family V30Family, /// Quad-Core Intel® Xeon® processor 3200 Series QuadCoreIntelXeonProcessor3200Series, /// Dual-Core Intel® Xeon® processor 3000 Series DualCoreIntelXeonProcessor3000Series, /// Quad-Core Intel® Xeon® processor 5300 Series QuadCoreIntelXeonProcessor5300Series, /// Dual-Core Intel® Xeon® processor 5100 Series DualCoreIntelXeonProcessor5100Series, /// Dual-Core Intel® Xeon® processor 5000 Series DualCoreIntelXeonProcessor5000Series, /// Dual-Core Intel® Xeon® processor LV DualCoreIntelXeonProcessorLV, /// Dual-Core Intel® Xeon® processor ULV DualCoreIntelXeonProcessorULV, /// Dual-Core Intel® Xeon® processor 7100 Series DualCoreIntelXeonProcessor7100Series, /// Quad-Core Intel® Xeon® processor 5400 Series QuadCoreIntelXeonProcessor5400Series, /// Quad-Core Intel® Xeon® processor QuadCoreIntelXeonProcessor, /// Dual-Core Intel® Xeon® processor 5200 Series DualCoreIntelXeonProcessor5200Series, /// Dual-Core Intel® Xeon® processor 7200 Series DualCoreIntelXeonProcessor7200Series, /// Quad-Core Intel® Xeon® processor 7300 Series QuadCoreIntelXeonProcessor7300Series, /// Quad-Core Intel® Xeon® processor 7400 Series QuadCoreIntelXeonProcessor7400Series, /// Multi-Core Intel® Xeon® processor 7400 Series MultiCoreIntelXeonProcessor7400Series, /// Pentium® III Xeon™ processor PentiumIIIXeonProcessor, /// Pentium® III Processor with Intel® SpeedStep™ Technology PentiumIIIProcessorwithIntelSpeedStepTechnology, /// Pentium® 4 Processor Pentium4Processor, /// Intel® Xeon® processor IntelXeonProcessor, /// AS400 Family AS400Family, /// Intel® Xeon™ processor MP IntelXeonProcessorMP, /// AMD Athlon™ XP Processor Family AMDAthlonXPProcessorFamily, /// AMD Athlon™ MP Processor Family AMDAthlonMPProcessorFamily, /// Intel® Itanium® 2 processor IntelItanium2Processor, /// Intel® Pentium® M processor IntelPentiumMProcessor, /// Intel® Celeron® D processor IntelCeleronDProcessor, /// Intel® Pentium® D processor IntelPentiumDProcessor, /// Intel® Pentium® Processor Extreme Edition IntelPentiumProcessorExtremeEdition, /// Intel® Core™ Solo Processor IntelCoreSoloProcessor, /// Intel® Core™ 2 Duo Processor IntelCore2DuoProcessor, /// Intel® Core™ 2 Solo processor IntelCore2SoloProcessor, /// Intel® Core™ 2 Extreme processor IntelCore2ExtremeProcessor, /// Intel® Core™ 2 Quad processor IntelCore2QuadProcessor, /// Intel® Core™ 2 Extreme mobile processor IntelCore2ExtremeMobileProcessor, /// Intel® Core™ 2 Duo mobile processor IntelCore2DuoMobileProcessor, /// Intel® Core™ 2 Solo mobile processor IntelCore2SoloMobileProcessor, /// Intel® Core™ i7 processor IntelCorei7Processor, /// Dual-Core Intel® Celeron® processor DualCoreIntelCeleronProcessor, /// IBM390 Family IBM390Family, /// G4 G4, /// G5 G5, /// ESA/390 G6 ESA390G6, /// z/Architecture base ZArchitecturebase, /// Intel® Core™ i5 processor IntelCorei5processor, /// Intel® Core™ i3 processor IntelCorei3processor, /// Intel® Core™ i9 processor IntelCorei9processor, /// VIA C7™-M Processor Family VIAC7MProcessorFamily, /// VIA C7™-D Processor Family VIAC7DProcessorFamily, /// VIA C7™ Processor Family VIAC7ProcessorFamily, /// VIA Eden™ Processor Family VIAEdenProcessorFamily, /// Multi-Core Intel® Xeon® processor MultiCoreIntelXeonProcessor, /// Dual-Core Intel® Xeon® processor 3xxx Series DualCoreIntelXeonProcessor3xxxSeries, /// Quad-Core Intel® Xeon® processor 3xxx Series QuadCoreIntelXeonProcessor3xxxSeries, /// VIA Nano™ Processor Family VIANanoProcessorFamily, /// Dual-Core Intel® Xeon® processor 5xxx Series DualCoreIntelXeonProcessor5xxxSeries, /// Quad-Core Intel® Xeon® processor 5xxx Series QuadCoreIntelXeonProcessor5xxxSeries, /// Dual-Core Intel® Xeon® processor 7xxx Series DualCoreIntelXeonProcessor7xxxSeries, /// Quad-Core Intel® Xeon® processor 7xxx Series QuadCoreIntelXeonProcessor7xxxSeries, /// Multi-Core Intel® Xeon® processor 7xxx Series MultiCoreIntelXeonProcessor7xxxSeries, /// Multi-Core Intel® Xeon® processor 3400 Series MultiCoreIntelXeonProcessor3400Series, /// AMD Opteron™ 3000 Series Processor AMDOpteron3000SeriesProcessor, /// AMD Sempron™ II Processor AMDSempronIIProcessor, /// Embedded AMD Opteron™ Quad-Core Processor Family EmbeddedAMDOpteronQuadCoreProcessorFamily, /// AMD Phenom™ Triple-Core Processor Family AMDPhenomTripleCoreProcessorFamily, /// AMD Turion™ Ultra Dual-Core Mobile Processor Family AMDTurionUltraDualCoreMobileProcessorFamily, /// AMD Turion™ Dual-Core Mobile Processor Family AMDTurionDualCoreMobileProcessorFamily, /// AMD Athlon™ Dual-Core Processor Family AMDAthlonDualCoreProcessorFamily, /// AMD Sempron™ SI Processor Family AMDSempronSIProcessorFamily, /// AMD Phenom™ II Processor Family AMDPhenomIIProcessorFamily, /// AMD Athlon™ II Processor Family AMDAthlonIIProcessorFamily, /// Six-Core AMD Opteron™ Processor Family SixCoreAMDOpteronProcessorFamily, /// AMD Sempron™ M Processor Family AMDSempronMProcessorFamily, /// i860 I860, /// i960 I960, /// Indicator to obtain the processor family from the 'processor_family_2' field SeeProcessorFamily2, /// ARMv7 ARMv7, /// ARMv8 ARMv8, /// ARMv9 ARMv9, /// SH-3 SH3, /// SH-4 SH4, /// ARM ARM, /// StrongARM StrongARM, /// 6x86 Cyrix6x86, /// MediaGX MediaGX, /// MII MII, /// WinChip WinChip, /// DSP DSP, /// Video Processor VideoProcessor, /// RISC-V RV32 RISCVRV32, /// RISC-V RV64 RISCVRV64, /// RISC-V RV128 RISCVRV128, /// LoongArch LoongArch, /// Loongson™ 1 Processor Family Longsoon1ProcessorFamily, /// Loongson™ 2 Processor Family Longsoon2ProcessorFamily, /// Loongson™ 3 Processor Family Longsoon3ProcessorFamily, /// Loongson™ 2K Processor Family Longsoon2KProcessorFamily, /// Loongson™ 3A Processor Family Longsoon3AProcessorFamily, /// Loongson™ 3B Processor Family Longsoon3BProcessorFamily, /// Loongson™ 3C Processor Family Longsoon3CProcessorFamily, /// Loongson™ 3D Processor Family Longsoon3DProcessorFamily, /// Loongson™ 3E Processor Family Longsoon3EProcessorFamily, /// Dual-Core Loongson™ 2K Processor 2xxx Series DualCoreLoongson2KProcessor2xxxSeries, /// Quad-Core Loongson™ 3A Processor 5xxx Series QuadCoreLoongson3AProcessor5xxxSeries, /// Multi-Core Loongson™ 3A Processor 5xxx Series MultiCoreLoongson3AProcessor5xxxSeries, /// Quad-Core Loongson™ 3B Processor 5xxx Series QuadCoreLoongson3BProcessor5xxxSeries, /// Multi-Core Loongson™ 3B Processor 5xxx Series MultiCoreLoongson3BProcessor5xxxSeries, /// Multi-Core Loongson™ 3C Processor 5xxx Series MultiCoreLoongson3CProcessor5xxxSeries, /// Multi-Core Loongson™ 3D Processor 5xxx Series MultiCoreLoongson3DProcessor5xxxSeries, /// A value unknown to this standard, check the raw value None, } impl From for ProcessorFamily { fn from(raw: u16) -> Self { match raw { 0x01 => ProcessorFamily::Other, 0x02 => ProcessorFamily::Unknown, 0x03 => ProcessorFamily::I8086, 0x04 => ProcessorFamily::I80286, 0x05 => ProcessorFamily::Intel386Processor, 0x06 => ProcessorFamily::Intel486Processor, 0x07 => ProcessorFamily::I8087, 0x08 => ProcessorFamily::I80287, 0x09 => ProcessorFamily::I80387, 0x0A => ProcessorFamily::I80487, 0x0B => ProcessorFamily::IntelPentiumProcessor, 0x0C => ProcessorFamily::PentiumProProcessor, 0x0D => ProcessorFamily::PentiumIIProcessor, 0x0E => ProcessorFamily::PentiumprocessorwithMMXtechnology, 0x0F => ProcessorFamily::IntelCeleronProcessor, 0x10 => ProcessorFamily::PentiumIIXeonProcessor, 0x11 => ProcessorFamily::PentiumIIIProcessor, 0x12 => ProcessorFamily::M1Family, 0x13 => ProcessorFamily::M2Family, 0x14 => ProcessorFamily::IntelCeleronMProcessor, 0x15 => ProcessorFamily::IntelPentium4HTProcessor, 0x18 => ProcessorFamily::AMDDuronProcessorFamily, 0x19 => ProcessorFamily::K5Family, 0x1A => ProcessorFamily::K6Family, 0x1B => ProcessorFamily::K62, 0x1C => ProcessorFamily::K63, 0x1D => ProcessorFamily::AMDAthlonProcessorFamily, 0x1E => ProcessorFamily::AMD29000Family, 0x1F => ProcessorFamily::K62Plus, 0x20 => ProcessorFamily::PowerPCFamily, 0x21 => ProcessorFamily::PowerPC601, 0x22 => ProcessorFamily::PowerPC603, 0x23 => ProcessorFamily::PowerPC603Plus, 0x24 => ProcessorFamily::PowerPC604, 0x25 => ProcessorFamily::PowerPC620, 0x26 => ProcessorFamily::PowerPCx704, 0x27 => ProcessorFamily::PowerPC750, 0x28 => ProcessorFamily::IntelCoreDuoProcessor, 0x29 => ProcessorFamily::IntelCoreDuomobileProcessor, 0x2A => ProcessorFamily::IntelCoreSolomobileProcessor, 0x2B => ProcessorFamily::IntelAtomProcessor, 0x2C => ProcessorFamily::IntelCoreMProcessor, 0x2D => ProcessorFamily::IntelCorem3Processor, 0x2E => ProcessorFamily::IntelCorem5Processor, 0x2F => ProcessorFamily::IntelCorem7Processor, 0x30 => ProcessorFamily::AlphaFamily, 0x31 => ProcessorFamily::Alpha21064, 0x32 => ProcessorFamily::Alpha21066, 0x33 => ProcessorFamily::Alpha21164, 0x34 => ProcessorFamily::Alpha21164PC, 0x35 => ProcessorFamily::Alpha21164a, 0x36 => ProcessorFamily::Alpha21264, 0x37 => ProcessorFamily::Alpha21364, 0x38 => ProcessorFamily::AMDTurionIIUltraDualCoreMobileMProcessorFamily, 0x39 => ProcessorFamily::AMDTurionIIDualCoreMobileMProcessorFamily, 0x3A => ProcessorFamily::AMDAthlonIIDualCoreMProcessorFamily, 0x3B => ProcessorFamily::AMDOpteron6100SeriesProcessor, 0x3C => ProcessorFamily::AMDOpteron4100SeriesProcessor, 0x3D => ProcessorFamily::AMDOpteron6200SeriesProcessor, 0x3E => ProcessorFamily::AMDOpteron4200SeriesProcessor, 0x3F => ProcessorFamily::AMDFXSeriesProcessor, 0x40 => ProcessorFamily::MIPSFamily, 0x41 => ProcessorFamily::MIPSR4000, 0x42 => ProcessorFamily::MIPSR4200, 0x43 => ProcessorFamily::MIPSR4400, 0x44 => ProcessorFamily::MIPSR4600, 0x45 => ProcessorFamily::MIPSR10000, 0x46 => ProcessorFamily::AMDCSeriesProcessor, 0x47 => ProcessorFamily::AMDESeriesProcessor, 0x48 => ProcessorFamily::AMDASeriesProcessor, 0x49 => ProcessorFamily::AMDGSeriesProcessor, 0x4A => ProcessorFamily::AMDZSeriesProcessor, 0x4B => ProcessorFamily::AMDRSeriesProcessor, 0x4C => ProcessorFamily::AMDOpteron4300SeriesProcessor, 0x4D => ProcessorFamily::AMDOpteron6300SeriesProcessor, 0x4E => ProcessorFamily::AMDOpteron3300SeriesProcessor, 0x4F => ProcessorFamily::AMDFireProSeriesProcessor, 0x50 => ProcessorFamily::SPARCFamily, 0x51 => ProcessorFamily::SuperSPARC, 0x52 => ProcessorFamily::MicroSparcii, 0x53 => ProcessorFamily::MicroSparciiep, 0x54 => ProcessorFamily::UltraSPARC, 0x55 => ProcessorFamily::UltraSPARCII, 0x56 => ProcessorFamily::UltraSPARCIii, 0x57 => ProcessorFamily::UltraSPARCIII, 0x58 => ProcessorFamily::UltraSPARCIIIi, 0x60 => ProcessorFamily::M68040Family, 0x61 => ProcessorFamily::M68xxx, 0x62 => ProcessorFamily::M68000, 0x63 => ProcessorFamily::M68010, 0x64 => ProcessorFamily::M68020, 0x65 => ProcessorFamily::M68030, 0x66 => ProcessorFamily::AMDAthlonX4QuadCoreProcessorFamily, 0x67 => ProcessorFamily::AMDOpteronX1000SeriesProcessor, 0x68 => ProcessorFamily::AMDOpteronX2000SeriesAPU, 0x69 => ProcessorFamily::AMDOpteronASeriesProcessor, 0x6A => ProcessorFamily::AMDOpteronX3000SeriesAPU, 0x6B => ProcessorFamily::AMDZenProcessorFamily, 0x70 => ProcessorFamily::HobbitFamily, 0x78 => ProcessorFamily::CrusoeTM5000Family, 0x79 => ProcessorFamily::CrusoeTM3000Family, 0x7A => ProcessorFamily::EfficeonTM8000Family, 0x80 => ProcessorFamily::Weitek, 0x82 => ProcessorFamily::Itaniumprocessor, 0x83 => ProcessorFamily::AMDAthlon64ProcessorFamily, 0x84 => ProcessorFamily::AMDOpteronProcessorFamily, 0x85 => ProcessorFamily::AMDSempronProcessorFamily, 0x86 => ProcessorFamily::AMDTurion64MobileTechnology, 0x87 => ProcessorFamily::DualCoreAMDOpteronProcessorFamily, 0x88 => ProcessorFamily::AMDAthlon64X2DualCoreProcessorFamily, 0x89 => ProcessorFamily::AMDTurion64X2MobileTechnology, 0x8A => ProcessorFamily::QuadCoreAMDOpteronProcessorFamily, 0x8B => ProcessorFamily::ThirdGenerationAMDOpteronProcessorFamily, 0x8C => ProcessorFamily::AMDPhenomFXQuadCoreProcessorFamily, 0x8D => ProcessorFamily::AMDPhenomX4QuadCoreProcessorFamily, 0x8E => ProcessorFamily::AMDPhenomX2DualCoreProcessorFamily, 0x8F => ProcessorFamily::AMDAthlonX2DualCoreProcessorFamily, 0x90 => ProcessorFamily::PARISCFamily, 0x91 => ProcessorFamily::PARISC8500, 0x92 => ProcessorFamily::PARISC8000, 0x93 => ProcessorFamily::PARISC7300LC, 0x94 => ProcessorFamily::PARISC7200, 0x95 => ProcessorFamily::PARISC7100LC, 0x96 => ProcessorFamily::PARISC7100, 0xA0 => ProcessorFamily::V30Family, 0xA1 => ProcessorFamily::QuadCoreIntelXeonProcessor3200Series, 0xA2 => ProcessorFamily::DualCoreIntelXeonProcessor3000Series, 0xA3 => ProcessorFamily::QuadCoreIntelXeonProcessor5300Series, 0xA4 => ProcessorFamily::DualCoreIntelXeonProcessor5100Series, 0xA5 => ProcessorFamily::DualCoreIntelXeonProcessor5000Series, 0xA6 => ProcessorFamily::DualCoreIntelXeonProcessorLV, 0xA7 => ProcessorFamily::DualCoreIntelXeonProcessorULV, 0xA8 => ProcessorFamily::DualCoreIntelXeonProcessor7100Series, 0xA9 => ProcessorFamily::QuadCoreIntelXeonProcessor5400Series, 0xAA => ProcessorFamily::QuadCoreIntelXeonProcessor, 0xAB => ProcessorFamily::DualCoreIntelXeonProcessor5200Series, 0xAC => ProcessorFamily::DualCoreIntelXeonProcessor7200Series, 0xAD => ProcessorFamily::QuadCoreIntelXeonProcessor7300Series, 0xAE => ProcessorFamily::QuadCoreIntelXeonProcessor7400Series, 0xAF => ProcessorFamily::MultiCoreIntelXeonProcessor7400Series, 0xB0 => ProcessorFamily::PentiumIIIXeonProcessor, 0xB1 => ProcessorFamily::PentiumIIIProcessorwithIntelSpeedStepTechnology, 0xB2 => ProcessorFamily::Pentium4Processor, 0xB3 => ProcessorFamily::IntelXeonProcessor, 0xB4 => ProcessorFamily::AS400Family, 0xB5 => ProcessorFamily::IntelXeonProcessorMP, 0xB6 => ProcessorFamily::AMDAthlonXPProcessorFamily, 0xB7 => ProcessorFamily::AMDAthlonMPProcessorFamily, 0xB8 => ProcessorFamily::IntelItanium2Processor, 0xB9 => ProcessorFamily::IntelPentiumMProcessor, 0xBA => ProcessorFamily::IntelCeleronDProcessor, 0xBB => ProcessorFamily::IntelPentiumDProcessor, 0xBC => ProcessorFamily::IntelPentiumProcessorExtremeEdition, 0xBD => ProcessorFamily::IntelCoreSoloProcessor, 0xBF => ProcessorFamily::IntelCore2DuoProcessor, 0xC0 => ProcessorFamily::IntelCore2SoloProcessor, 0xC1 => ProcessorFamily::IntelCore2ExtremeProcessor, 0xC2 => ProcessorFamily::IntelCore2QuadProcessor, 0xC3 => ProcessorFamily::IntelCore2ExtremeMobileProcessor, 0xC4 => ProcessorFamily::IntelCore2DuoMobileProcessor, 0xC5 => ProcessorFamily::IntelCore2SoloMobileProcessor, 0xC6 => ProcessorFamily::IntelCorei7Processor, 0xC7 => ProcessorFamily::DualCoreIntelCeleronProcessor, 0xC8 => ProcessorFamily::IBM390Family, 0xC9 => ProcessorFamily::G4, 0xCA => ProcessorFamily::G5, 0xCB => ProcessorFamily::ESA390G6, 0xCC => ProcessorFamily::ZArchitecturebase, 0xCD => ProcessorFamily::IntelCorei5processor, 0xCE => ProcessorFamily::IntelCorei3processor, 0xCF => ProcessorFamily::IntelCorei9processor, 0xD2 => ProcessorFamily::VIAC7MProcessorFamily, 0xD3 => ProcessorFamily::VIAC7DProcessorFamily, 0xD4 => ProcessorFamily::VIAC7ProcessorFamily, 0xD5 => ProcessorFamily::VIAEdenProcessorFamily, 0xD6 => ProcessorFamily::MultiCoreIntelXeonProcessor, 0xD7 => ProcessorFamily::DualCoreIntelXeonProcessor3xxxSeries, 0xD8 => ProcessorFamily::QuadCoreIntelXeonProcessor3xxxSeries, 0xD9 => ProcessorFamily::VIANanoProcessorFamily, 0xDA => ProcessorFamily::DualCoreIntelXeonProcessor5xxxSeries, 0xDB => ProcessorFamily::QuadCoreIntelXeonProcessor5xxxSeries, 0xDD => ProcessorFamily::DualCoreIntelXeonProcessor7xxxSeries, 0xDE => ProcessorFamily::QuadCoreIntelXeonProcessor7xxxSeries, 0xDF => ProcessorFamily::MultiCoreIntelXeonProcessor7xxxSeries, 0xE0 => ProcessorFamily::MultiCoreIntelXeonProcessor3400Series, 0xE4 => ProcessorFamily::AMDOpteron3000SeriesProcessor, 0xE5 => ProcessorFamily::AMDSempronIIProcessor, 0xE6 => ProcessorFamily::EmbeddedAMDOpteronQuadCoreProcessorFamily, 0xE7 => ProcessorFamily::AMDPhenomTripleCoreProcessorFamily, 0xE8 => ProcessorFamily::AMDTurionUltraDualCoreMobileProcessorFamily, 0xE9 => ProcessorFamily::AMDTurionDualCoreMobileProcessorFamily, 0xEA => ProcessorFamily::AMDAthlonDualCoreProcessorFamily, 0xEB => ProcessorFamily::AMDSempronSIProcessorFamily, 0xEC => ProcessorFamily::AMDPhenomIIProcessorFamily, 0xED => ProcessorFamily::AMDAthlonIIProcessorFamily, 0xEE => ProcessorFamily::SixCoreAMDOpteronProcessorFamily, 0xEF => ProcessorFamily::AMDSempronMProcessorFamily, 0xFA => ProcessorFamily::I860, 0xFB => ProcessorFamily::I960, 0xFE => ProcessorFamily::SeeProcessorFamily2, 0x100 => ProcessorFamily::ARMv7, 0x101 => ProcessorFamily::ARMv8, 0x102 => ProcessorFamily::ARMv9, 0x104 => ProcessorFamily::SH3, 0x105 => ProcessorFamily::SH4, 0x118 => ProcessorFamily::ARM, 0x119 => ProcessorFamily::StrongARM, 0x12C => ProcessorFamily::Cyrix6x86, 0x12D => ProcessorFamily::MediaGX, 0x12E => ProcessorFamily::MII, 0x140 => ProcessorFamily::WinChip, 0x15E => ProcessorFamily::DSP, 0x1F4 => ProcessorFamily::VideoProcessor, 0x200 => ProcessorFamily::RISCVRV32, 0x201 => ProcessorFamily::RISCVRV64, 0x202 => ProcessorFamily::RISCVRV128, 0x258 => ProcessorFamily::LoongArch, 0x259 => ProcessorFamily::Longsoon1ProcessorFamily, 0x25A => ProcessorFamily::Longsoon2ProcessorFamily, 0x25B => ProcessorFamily::Longsoon3ProcessorFamily, 0x25C => ProcessorFamily::Longsoon2KProcessorFamily, 0x25D => ProcessorFamily::Longsoon3AProcessorFamily, 0x25E => ProcessorFamily::Longsoon3BProcessorFamily, 0x25F => ProcessorFamily::Longsoon3CProcessorFamily, 0x260 => ProcessorFamily::Longsoon3DProcessorFamily, 0x261 => ProcessorFamily::Longsoon3EProcessorFamily, 0x262 => ProcessorFamily::DualCoreLoongson2KProcessor2xxxSeries, 0x26C => ProcessorFamily::QuadCoreLoongson3AProcessor5xxxSeries, 0x26D => ProcessorFamily::MultiCoreLoongson3AProcessor5xxxSeries, 0x26E => ProcessorFamily::QuadCoreLoongson3BProcessor5xxxSeries, 0x26F => ProcessorFamily::MultiCoreLoongson3BProcessor5xxxSeries, 0x270 => ProcessorFamily::MultiCoreLoongson3CProcessor5xxxSeries, 0x271 => ProcessorFamily::MultiCoreLoongson3DProcessor5xxxSeries, _ => ProcessorFamily::None, } } } /// # pub struct ProcessorUpgradeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [ProcessorUpgrade] value pub value: ProcessorUpgrade, } impl fmt::Debug for ProcessorUpgradeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for ProcessorUpgradeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ProcessorUpgradeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for ProcessorUpgradeData { type Target = ProcessorUpgrade; fn deref(&self) -> &Self::Target { &self.value } } /// # #[derive(Serialize, Debug, PartialEq, Eq)] pub enum ProcessorUpgrade { /// Other Other, /// Unknown Unknown, /// Daughter Board DaughterBoard, /// ZIF Socket ZIFSocket, /// Replaceable Piggy Back ReplaceablePiggyBack, /// No Upgrade NoUpgrade, /// LIF Socket LIFSocket, /// Slot 1 Slot1, /// Slot 2 Slot2, /// 370-pin socket PinSocket370, /// Slot A SlotA, /// Slot M SlotM, /// Socket 423 Socket423, /// Socket A (Socket 462) SocketASocket462, /// Socket 478 Socket478, /// Socket 754 Socket754, /// Socket 940 Socket940, /// Socket 939 Socket939, /// Socket mPGA604 SocketmPGA604, /// Socket LGA771 SocketLGA771, /// Socket LGA775 SocketLGA775, /// Socket S1 SocketS1, /// Socket AM2 SocketAM2, /// Socket F (1207) SocketF1207, /// Socket LGA1366 SocketLGA1366, /// Socket G34 SocketG34, /// Socket AM3 SocketAM3, /// Socket C32 SocketC32, /// Socket LGA1156 SocketLGA1156, /// Socket LGA1567 SocketLGA1567, /// Socket PGA988A SocketPGA988A, /// Socket BGA1288 SocketBGA1288, /// Socket rPGA988B SocketrPGA988B, /// Socket BGA1023 SocketBGA1023, /// Socket BGA1224 SocketBGA1224, /// Socket LGA1155 SocketLGA1155, /// Socket LGA1356 SocketLGA1356, /// Socket LGA2011 SocketLGA2011, /// Socket FS1 SocketFS1, /// Socket FS2 SocketFS2, /// Socket FM1 SocketFM1, /// Socket FM2 SocketFM2, /// Socket LGA2011-3 SocketLGA2011_3, /// Socket LGA1356-3 SocketLGA1356_3, /// Socket LGA1150 SocketLGA1150, /// Socket BGA1168 SocketBGA1168, /// Socket BGA1234 SocketBGA1234, /// Socket BGA1364 SocketBGA1364, /// Socket AM4 SocketAM4, /// Socket LGA1151 SocketLGA1151, /// Socket BGA1356 SocketBGA1356, /// Socket BGA1440 SocketBGA1440, /// Socket BGA1515 SocketBGA1515, /// Socket LGA3647-1 SocketLGA3647_1, /// Socket SP3 SocketSP3, /// Socket SP3r2 SocketSP3r23, /// Socket LGA2066 SocketLGA2066, /// Socket BGA1392 SocketBGA1392, /// Socket BGA1510 SocketBGA1510, /// Socket BGA1528 SocketBGA1528, /// Socket LGA4189 SocketLGA4189, /// Socket LGA1200 SocketLGA1200, /// Socket LGA4677 SocketLGA4677, /// Socket LGA1700 SocketLGA1700, /// Socket BGA1744 SocketBGA1744, /// Socket BGA1781 SocketBGA1781, /// Socket BGA1211 SocketBGA1211, /// Socket BGA2422 SocketBGA2422, /// Socket LGA1211 SocketLGA1211, /// Socket LGA2422 SocketLGA2422, /// Socket LGA5773 SocketLGA5773, /// Socket BGA5773 SocketBGA5773, /// Socket AM5 SocketAM5, /// Socket SP5 SocketSP5, /// Socket SP6 SocketSP6, /// Socket BGA883 SocketBGA883, /// Socket BGA1190 SocketBGA1190, /// Socket BGA4129 SocketBGA4129, /// Socket LGA4710 SocketLGA4710, /// Socket LGA7529 SocketLGA7529, /// A value unknown to this standard, check the raw value None, } impl From for ProcessorUpgradeData { fn from(raw: u8) -> Self { ProcessorUpgradeData { value: match raw { 0x01 => ProcessorUpgrade::Other, 0x02 => ProcessorUpgrade::Unknown, 0x03 => ProcessorUpgrade::DaughterBoard, 0x04 => ProcessorUpgrade::ZIFSocket, 0x05 => ProcessorUpgrade::ReplaceablePiggyBack, 0x06 => ProcessorUpgrade::NoUpgrade, 0x07 => ProcessorUpgrade::LIFSocket, 0x08 => ProcessorUpgrade::Slot1, 0x09 => ProcessorUpgrade::Slot2, 0x0A => ProcessorUpgrade::PinSocket370, 0x0B => ProcessorUpgrade::SlotA, 0x0C => ProcessorUpgrade::SlotM, 0x0D => ProcessorUpgrade::Socket423, 0x0E => ProcessorUpgrade::SocketASocket462, 0x0F => ProcessorUpgrade::Socket478, 0x10 => ProcessorUpgrade::Socket754, 0x11 => ProcessorUpgrade::Socket940, 0x12 => ProcessorUpgrade::Socket939, 0x13 => ProcessorUpgrade::SocketmPGA604, 0x14 => ProcessorUpgrade::SocketLGA771, 0x15 => ProcessorUpgrade::SocketLGA775, 0x16 => ProcessorUpgrade::SocketS1, 0x17 => ProcessorUpgrade::SocketAM2, 0x18 => ProcessorUpgrade::SocketF1207, 0x19 => ProcessorUpgrade::SocketLGA1366, 0x1A => ProcessorUpgrade::SocketG34, 0x1B => ProcessorUpgrade::SocketAM3, 0x1C => ProcessorUpgrade::SocketC32, 0x1D => ProcessorUpgrade::SocketLGA1156, 0x1E => ProcessorUpgrade::SocketLGA1567, 0x1F => ProcessorUpgrade::SocketPGA988A, 0x20 => ProcessorUpgrade::SocketBGA1288, 0x21 => ProcessorUpgrade::SocketrPGA988B, 0x22 => ProcessorUpgrade::SocketBGA1023, 0x23 => ProcessorUpgrade::SocketBGA1224, 0x24 => ProcessorUpgrade::SocketLGA1155, 0x25 => ProcessorUpgrade::SocketLGA1356, 0x26 => ProcessorUpgrade::SocketLGA2011, 0x27 => ProcessorUpgrade::SocketFS1, 0x28 => ProcessorUpgrade::SocketFS2, 0x29 => ProcessorUpgrade::SocketFM1, 0x2A => ProcessorUpgrade::SocketFM2, 0x2B => ProcessorUpgrade::SocketLGA2011_3, 0x2C => ProcessorUpgrade::SocketLGA1356_3, 0x2D => ProcessorUpgrade::SocketLGA1150, 0x2E => ProcessorUpgrade::SocketBGA1168, 0x2F => ProcessorUpgrade::SocketBGA1234, 0x30 => ProcessorUpgrade::SocketBGA1364, 0x31 => ProcessorUpgrade::SocketAM4, 0x32 => ProcessorUpgrade::SocketLGA1151, 0x33 => ProcessorUpgrade::SocketBGA1356, 0x34 => ProcessorUpgrade::SocketBGA1440, 0x35 => ProcessorUpgrade::SocketBGA1515, 0x36 => ProcessorUpgrade::SocketLGA3647_1, 0x37 => ProcessorUpgrade::SocketSP3, 0x38 => ProcessorUpgrade::SocketSP3r23, 0x39 => ProcessorUpgrade::SocketLGA2066, 0x3A => ProcessorUpgrade::SocketBGA1392, 0x3B => ProcessorUpgrade::SocketBGA1510, 0x3C => ProcessorUpgrade::SocketBGA1528, 0x3D => ProcessorUpgrade::SocketLGA4189, 0x3E => ProcessorUpgrade::SocketLGA1200, 0x3F => ProcessorUpgrade::SocketLGA4677, 0x40 => ProcessorUpgrade::SocketLGA1700, 0x41 => ProcessorUpgrade::SocketBGA1744, 0x42 => ProcessorUpgrade::SocketBGA1781, 0x43 => ProcessorUpgrade::SocketBGA1211, 0x44 => ProcessorUpgrade::SocketBGA2422, 0x45 => ProcessorUpgrade::SocketLGA1211, 0x46 => ProcessorUpgrade::SocketLGA2422, 0x47 => ProcessorUpgrade::SocketLGA5773, 0x48 => ProcessorUpgrade::SocketBGA5773, 0x49 => ProcessorUpgrade::SocketAM5, 0x4A => ProcessorUpgrade::SocketSP5, 0x4B => ProcessorUpgrade::SocketSP6, 0x4C => ProcessorUpgrade::SocketBGA883, 0x4D => ProcessorUpgrade::SocketBGA1190, 0x4E => ProcessorUpgrade::SocketBGA4129, 0x4F => ProcessorUpgrade::SocketLGA4710, 0x50 => ProcessorUpgrade::SocketLGA7529, _ => ProcessorUpgrade::None, }, raw, } } } /// # Processor Characteristics #[derive(PartialEq, Eq)] pub struct ProcessorCharacteristics { /// Raw value pub raw: u16, } impl Deref for ProcessorCharacteristics { type Target = u16; fn deref(&self) -> &Self::Target { &self.raw } } impl From for ProcessorCharacteristics { fn from(raw: u16) -> Self { ProcessorCharacteristics { raw } } } impl ProcessorCharacteristics { /// Bit 1 Unknown pub fn unknown(&self) -> bool { self.raw & 0x0002 == 0x0002 } /// Bit 2 64-bit Capable pub fn bit_64capable(&self) -> bool { self.raw & 0x0004 == 0x0004 } /// Bit 3 Multi-Core pub fn multi_core(&self) -> bool { self.raw & 0x0008 == 0x0008 } /// Bit 4 Hardware Thread pub fn hardware_thread(&self) -> bool { self.raw & 0x0010 == 0x0010 } /// Bit 5 Execute Protection pub fn execute_protection(&self) -> bool { self.raw & 0x0020 == 0x0020 } /// Bit 6 Enhanced Virtualization pub fn enhanced_virtualization(&self) -> bool { self.raw & 0x0040 == 0x0040 } /// Bit 7 Power/Performance Control pub fn power_performance_control(&self) -> bool { self.raw & 0x0080 == 0x0080 } /// Bit 8 128-bit Capable pub fn bit_128capable(&self) -> bool { self.raw & 0x0100 == 0x0100 } /// Bit 9 Arm64 SoC ID pub fn arm_64soc_id(&self) -> bool { self.raw & 0x200 == 0x200 } } impl fmt::Debug for ProcessorCharacteristics { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("unknown", &self.unknown()) .field("bit_64capable", &self.bit_64capable()) .field("multi_core", &self.multi_core()) .field("hardware_thread", &self.hardware_thread()) .field("execute_protection", &self.execute_protection()) .field("enhanced_virtualization", &self.enhanced_virtualization()) .field( "power_performance_control", &self.power_performance_control(), ) .field("bit_128capable", &self.bit_128capable()) .field("arm_64soc_id", &self.arm_64soc_id()) .finish() } } impl Serialize for ProcessorCharacteristics { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ProcessorCharacteristics", 10)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("unknown", &self.unknown())?; state.serialize_field("bit_64capable", &self.bit_64capable())?; state.serialize_field("multi_core", &self.multi_core())?; state.serialize_field("hardware_thread", &self.hardware_thread())?; state.serialize_field("execute_protection", &self.execute_protection())?; state.serialize_field("enhanced_virtualization", &self.enhanced_virtualization())?; state.serialize_field( "power_performance_control", &self.power_performance_control(), )?; state.serialize_field("bit_128capable", &self.bit_128capable())?; state.serialize_field("arm_64soc_id", &self.arm_64soc_id())?; state.end() } } /// # Processor Voltage #[derive(Serialize, Debug)] pub enum ProcessorVoltage { /// Current Processor Voltage CurrentVolts(f32), /// Processor Supported Voltages SupportedVolts(ProcessorSupportedVoltages), } impl From for ProcessorVoltage { fn from(raw: u8) -> Self { if raw & 0b1000_0000 == 0b1000_0000 { ProcessorVoltage::CurrentVolts((raw & 0b0111_1111) as f32 / 10.0) } else { ProcessorVoltage::SupportedVolts(ProcessorSupportedVoltages::from(raw)) } } } /// # Processor Supported Voltages #[derive(PartialEq, Eq)] pub struct ProcessorSupportedVoltages { /// Raw value pub raw: u8, } impl Deref for ProcessorSupportedVoltages { type Target = u8; fn deref(&self) -> &Self::Target { &self.raw } } impl From for ProcessorSupportedVoltages { fn from(raw: u8) -> Self { debug_assert_eq!(raw, raw & 0b0111_1111); ProcessorSupportedVoltages { raw } } } impl ProcessorSupportedVoltages { /// Bit 0 – 5V pub fn volts_5_0(&self) -> bool { self.raw & 0x01 == 0x01 } /// Bit 1 – 3.3V pub fn volts_3_3(&self) -> bool { self.raw & 0x02 == 0x02 } /// Bit 2 – 2.9V pub fn volts_2_9(&self) -> bool { self.raw & 0x04 == 0x04 } /// Available Voltages pub fn voltages(&self) -> Vec { let mut result = Vec::new(); if self.volts_2_9() { result.push(2.9); } if self.volts_3_3() { result.push(3.3); } if self.volts_5_0() { result.push(5.0); } result } } impl fmt::Debug for ProcessorSupportedVoltages { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("voltages", &self.voltages().as_slice()) .finish() } } impl Serialize for ProcessorSupportedVoltages { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ProcessorSupportedVoltages", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("voltages", &self.voltages().as_slice())?; state.end() } } /// External Clock Frequency in MHz #[derive(Serialize)] pub enum ProcessorExternalClock { /// The value is unknown Unknown, /// External Clock Frequency in MHz MHz(u16), } impl From for ProcessorExternalClock { fn from(raw: u16) -> Self { match raw { 0 => ProcessorExternalClock::Unknown, _ => ProcessorExternalClock::MHz(raw), } } } impl fmt::Debug for ProcessorExternalClock { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { use ProcessorExternalClock::*; match self { Unknown => write! {fmt, "Unknown"}, MHz(n) => write! {fmt, "{} MHz", n}, } } } /// Processor Speed in MHz #[derive(Serialize)] pub enum ProcessorSpeed { /// The value is unknown Unknown, /// The Processor Speed in MHz MHz(u16), } impl From for ProcessorSpeed { fn from(raw: u16) -> Self { match raw { 0 => ProcessorSpeed::Unknown, _ => ProcessorSpeed::MHz(raw), } } } impl fmt::Debug for ProcessorSpeed { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { use ProcessorSpeed::*; match self { Unknown => write! {fmt, "Unknown"}, MHz(n) => write! {fmt, "{} MHz", n}, } } } /// # Processor Socket and CPU Status #[derive(PartialEq, Eq)] pub struct ProcessorStatus { /// Raw value pub raw: u8, } impl Deref for ProcessorStatus { type Target = u8; fn deref(&self) -> &Self::Target { &self.raw } } impl From for ProcessorStatus { fn from(raw: u8) -> Self { ProcessorStatus { raw } } } impl ProcessorStatus { /// CPU Socket Populated pub fn socket_populated(&self) -> bool { self.raw & 0b0100_0000 == 0b0100_0000 } /// CPU Status pub fn cpu_status(&self) -> CpuStatus { CpuStatus::from(self.raw) } } impl fmt::Debug for ProcessorStatus { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("socket_populated", &self.socket_populated()) .field("cpu_status", &self.cpu_status()) .finish() } } impl Serialize for ProcessorStatus { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ProcessorStatus", 3)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("socket_populated", &self.socket_populated())?; state.serialize_field("cpu_status", &self.cpu_status())?; state.end() } } /// CPU Status #[derive(Serialize, Debug, PartialEq, Eq)] pub enum CpuStatus { /// 0h – Unknown Unknown, /// 1h – CPU Enabled Enabled, /// 2h – CPU Disabled by User through BIOS Setup UserDisabled, /// 3h – CPU Disabled By BIOS (POST Error) BiosDisabled, /// 4h – CPU is Idle, waiting to be enabled. Idle, /// 7h – Other Other, /// A value unknown to this standard, check the raw value None, } impl From for CpuStatus { fn from(raw: u8) -> Self { match raw & 0b0000_0111 { 0 => CpuStatus::Unknown, 1 => CpuStatus::Enabled, 2 => CpuStatus::UserDisabled, 3 => CpuStatus::BiosDisabled, 4 => CpuStatus::Idle, 7 => CpuStatus::Other, _ => CpuStatus::None, } } } /// Processor Core Count #[derive(Serialize, Debug)] pub enum CoreCount { /// The value is unknown Unknown, /// Number of cores per processor socket Count(u8), /// For core counts of 256 or greater the 'core_count_2' field /// is set to the number of cores. SeeCoreCount2, } impl From for CoreCount { fn from(raw: u8) -> Self { match raw { 0 => CoreCount::Unknown, 0xFF => CoreCount::SeeCoreCount2, _ => CoreCount::Count(raw), } } } /// Processor Core Count #2 #[derive(Serialize, Debug)] pub enum CoreCount2 { /// The value is unknown Unknown, /// Number of cores per processor socket Count(u16), /// Reserved (0xFFFF) Reserved, } impl From for CoreCount2 { fn from(raw: u16) -> Self { match raw { 0 => CoreCount2::Unknown, 0xFFFF => CoreCount2::Reserved, _ => CoreCount2::Count(raw), } } } /// Processor Cores Enabled #[derive(Serialize, Debug)] pub enum CoresEnabled { /// The value is unknown Unknown, /// Number of cores enabled Count(u8), /// For core counts of 256 or greater the 'cores_enabled_2' field /// is set to the number of enabled cores. SeeCoresEnabled2, } impl From for CoresEnabled { fn from(raw: u8) -> Self { match raw { 0 => CoresEnabled::Unknown, 0xFF => CoresEnabled::SeeCoresEnabled2, _ => CoresEnabled::Count(raw), } } } /// Processor Cores Enabled #2 #[derive(Serialize, Debug)] pub enum CoresEnabled2 { /// The value is unknown Unknown, /// Number of cores enabled Count(u16), /// Reserved (0xFFFF) Reserved, } impl From for CoresEnabled2 { fn from(raw: u16) -> Self { match raw { 0 => CoresEnabled2::Unknown, 0xFFFF => CoresEnabled2::Reserved, _ => CoresEnabled2::Count(raw), } } } /// Processor Thread Count #[derive(Serialize, Debug)] pub enum ThreadCount { /// The value is unknown Unknown, /// Number of threads per processor socket Count(u8), /// For thread counts of 256 or greater the 'thread_count_2' field /// is set to the number of cores. SeeThreadCount2, } impl From for ThreadCount { fn from(raw: u8) -> Self { match raw { 0 => ThreadCount::Unknown, 0xFF => ThreadCount::SeeThreadCount2, _ => ThreadCount::Count(raw), } } } /// Processor Thread Count #2 #[derive(Serialize, Debug)] pub enum ThreadCount2 { /// The value is unknown Unknown, /// Number of threads per processor socket Count(u16), /// Reserved (0xFFFF) Reserved, } impl From for ThreadCount2 { fn from(raw: u16) -> Self { match raw { 0 => ThreadCount2::Unknown, 0xFFFF => ThreadCount2::Reserved, _ => ThreadCount2::Count(raw), } } } /// Thread Enabled #[derive(Serialize, Debug)] pub enum ThreadEnabled { /// The value is unknown (0x0000) Unknown, /// thread enabled counts 1 to 65534, respectively Count(u16), /// Reserved (0xFFFF) Reserved, } impl From for ThreadEnabled { fn from(raw: u16) -> Self { match raw { 0 => ThreadEnabled::Unknown, 0xFFFF => ThreadEnabled::Reserved, _ => ThreadEnabled::Count(raw), } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type4 = vec![ 0x04, 0x30, 0x56, 0x00, 0x01, 0x03, 0xB3, 0x02, 0x54, 0x06, 0x05, 0x00, 0xFF, 0xFB, 0xEB, 0xBF, 0x03, 0x90, 0x64, 0x00, 0x3C, 0x0F, 0x10, 0x0E, 0x41, 0x01, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x00, 0x04, 0x00, 0x06, 0x06, 0x0C, 0xFC, 0x00, 0xB3, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x43, 0x50, 0x55, 0x30, 0x00, 0x49, 0x6E, 0x74, 0x65, 0x6C, 0x28, 0x52, 0x29, 0x20, 0x43, 0x6F, 0x72, 0x70, 0x6F, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x49, 0x6E, 0x74, 0x65, 0x6C, 0x28, 0x52, 0x29, 0x20, 0x58, 0x65, 0x6F, 0x6E, 0x28, 0x52, 0x29, 0x20, 0x57, 0x2D, 0x32, 0x31, 0x33, 0x33, 0x20, 0x43, 0x50, 0x55, 0x20, 0x40, 0x20, 0x33, 0x2E, 0x36, 0x30, 0x47, 0x48, 0x7A, 0x00, 0x55, 0x4E, 0x4B, 0x4E, 0x4F, 0x57, 0x4E, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type4); let test_struct = SMBiosProcessorInformation::new(&parts); assert_eq!( test_struct.socket_designation().to_string(), "CPU0".to_string() ); assert_eq!( *test_struct.processor_type().unwrap(), ProcessorType::CentralProcessor ); assert_eq!( *test_struct.processor_family().unwrap(), ProcessorFamily::IntelXeonProcessor ); assert_eq!( test_struct.processor_manufacturer().to_string(), "Intel(R) Corporation".to_string() ); assert_eq!( test_struct.processor_id(), Some(&[0x54u8, 0x06, 0x05, 0x00, 0xFF, 0xFB, 0xEB, 0xBF]) ); assert_eq!( test_struct.processor_version().to_string(), "Intel(R) Xeon(R) W-2133 CPU @ 3.60GHz".to_string() ); match test_struct.voltage().unwrap() { ProcessorVoltage::CurrentVolts(volts) => assert_eq!(volts, 1.6), ProcessorVoltage::SupportedVolts(_) => panic!("expected current volts"), } match test_struct.external_clock().unwrap() { ProcessorExternalClock::MHz(mhz) => assert_eq!(mhz, 100), ProcessorExternalClock::Unknown => panic!("expected MHz"), } match test_struct.max_speed().unwrap() { ProcessorSpeed::MHz(mhz) => assert_eq!(mhz, 3900), ProcessorSpeed::Unknown => panic!("expected MHz"), } match test_struct.current_speed().unwrap() { ProcessorSpeed::MHz(mhz) => assert_eq!(mhz, 3600), ProcessorSpeed::Unknown => panic!("expected MHz"), } let processor_status = test_struct.status().unwrap(); assert!(processor_status.socket_populated()); assert_eq!(processor_status.cpu_status(), CpuStatus::Enabled); assert_eq!( *test_struct.processor_upgrade().unwrap(), ProcessorUpgrade::Other ); assert_eq!(*test_struct.l1cache_handle().unwrap(), 83); assert_eq!(*test_struct.l2cache_handle().unwrap(), 84); assert_eq!(*test_struct.l3cache_handle().unwrap(), 85); assert_eq!(test_struct.serial_number().to_string(), "".to_string()); assert_eq!(test_struct.asset_tag().to_string(), "UNKNOWN".to_string()); assert_eq!(test_struct.part_number().to_string(), "".to_string()); match test_struct.core_count().unwrap() { CoreCount::Count(number) => assert_eq!(number, 6), CoreCount::Unknown => panic!("expected number"), CoreCount::SeeCoreCount2 => panic!("expected number"), } match test_struct.cores_enabled().unwrap() { CoresEnabled::Count(number) => assert_eq!(number, 6), CoresEnabled::Unknown => panic!("expected number"), CoresEnabled::SeeCoresEnabled2 => panic!("expected number"), } match test_struct.thread_count().unwrap() { ThreadCount::Count(number) => assert_eq!(number, 12), ThreadCount::Unknown => panic!("expected number"), ThreadCount::SeeThreadCount2 => panic!("expected number"), } assert_eq!( test_struct.processor_characteristics(), Some(ProcessorCharacteristics::from(252)) ); assert_eq!( *test_struct.processor_family_2().unwrap(), ProcessorFamily::IntelXeonProcessor ); match test_struct.core_count_2().unwrap() { CoreCount2::Count(number) => assert_eq!(number, 6), CoreCount2::Unknown => panic!("expected number"), CoreCount2::Reserved => panic!("expected number"), } match test_struct.cores_enabled_2().unwrap() { CoresEnabled2::Count(number) => assert_eq!(number, 6), CoresEnabled2::Unknown => panic!("expected number"), CoresEnabled2::Reserved => panic!("expected number"), } match test_struct.thread_count_2().unwrap() { ThreadCount2::Count(number) => assert_eq!(number, 12), ThreadCount2::Unknown => panic!("expected number"), ThreadCount2::Reserved => panic!("expected number"), } } } smbios-lib-0.9.2/src/structs/types/string_property.rs000064400000000000000000000141621046102023000211620ustar 00000000000000use crate::core::{strings::*, Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # String Property (Type 46) /// /// This structure defines a string property for another structure. This allows adding string properties that are /// common to several structures without having to modify the definitions of these structures. Multiple type 46 /// structures can add string properties to the same parent structure. /// /// NOTE: This structure type was added in version 3.5 of this specification. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.5.0 (DSP0134) /// Document Date: 2021-09-15 pub struct SMBiosStringProperty<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosStringProperty<'a> { const STRUCT_TYPE: u8 = 46u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosStringProperty<'a> { /// String Property Id pub fn string_property_id(&self) -> Option { self.parts .get_field_word(0x04) .map(|raw| StringPropertyIdData::from(raw)) } /// String Property Value pub fn string_property_value(&self) -> SMBiosString { self.parts.get_field_string(0x06) } /// Parent Handle /// /// Handle corresponding to the structure this string property applies to pub fn parent_handle(&self) -> Option { self.parts.get_field_handle(0x07) } } impl fmt::Debug for SMBiosStringProperty<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("string_property_id", &self.string_property_id()) .field("string_property_value", &self.string_property_value()) .field("parent_handle", &self.parent_handle()) .finish() } } impl Serialize for SMBiosStringProperty<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosStringProperty", 3)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("string_property_id", &self.string_property_id())?; state.serialize_field("string_property_value", &self.string_property_value())?; state.serialize_field("parent_handle", &self.parent_handle())?; state.end() } } /// # String Property Id Data of [SMBiosStringProperty]. pub struct StringPropertyIdData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u16, /// The contained [StringPropertyId] value pub value: StringPropertyId, } impl fmt::Debug for StringPropertyIdData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for StringPropertyIdData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("StringPropertyIdData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for StringPropertyIdData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { StringPropertyId::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for StringPropertyIdData { type Target = StringPropertyId; fn deref(&self) -> &Self::Target { &self.value } } impl From for StringPropertyIdData { fn from(raw: u16) -> Self { StringPropertyIdData { value: match raw { 0x0001 => StringPropertyId::UefiDevicePath, _ => match raw & 0b1000_0000_0000_0000 { // >= 32768 ? 0b1000_0000_0000_0000 => match raw & 0b1100_0000_0000_0000 { // >= 49152 ? 0b1100_0000_0000_0000 => StringPropertyId::OemSpecific, // 49152-65535 _ => StringPropertyId::VendorSpecific, // 32768-49151 }, _ => StringPropertyId::None, }, }, raw, } } } /// # String Property Id of [SMBiosStringProperty] #[derive(Serialize, Debug, PartialEq, Eq)] pub enum StringPropertyId { /// UEFI Device Path /// /// String representation of a UEFI device path, as converted by /// EFI_DEVICE_PATH_TO_TEXT_PROTOCOL. ConvertDevicePathToText() and then converted to UTF-8 UefiDevicePath, /// Vendor Specific VendorSpecific, /// OEM Specific OemSpecific, /// A value unknown to this standard, check the raw value None, } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type46 = vec![ // struct_type(46), length(0x09), handle(0x10) 0x2E, 0x09, 0x10, 0x00, // string_property_id: (0x0001 - StringPropertyId::UefiDevicePath), string_property_value(1), parent_handle(0x0008) 0x01, 0x00, 0x01, 0x08, 0x00, //string_property_value: "Abcd" b'A', b'b', b'c', b'd', 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type46); let test_struct = SMBiosStringProperty::new(&parts); assert_eq!( test_struct.string_property_id().unwrap().value, StringPropertyId::UefiDevicePath ); assert_eq!(test_struct.string_property_value().to_string(), "Abcd"); assert_eq!(*test_struct.parent_handle().unwrap(), 8u16); } } smbios-lib-0.9.2/src/structs/types/system_boot_information.rs000064400000000000000000000166301046102023000226660ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # System Boot Information (Type 32) /// /// The client system firmware (for example, BIOS) communicates the /// System Boot Status to the client’s Pre1864 boot Execution Environment /// (PXE) boot image or OS-present management application through this /// structure. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosSystemBootInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosSystemBootInformation<'a> { const STRUCT_TYPE: u8 = 32u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosSystemBootInformation<'a> { /// offset of boot_status field const BOOT_STATUS_OFFSET: usize = 0x0A; /// Boot status can be a size from 1 to 10 const BOOT_STATUS_MAX_SIZE: usize = 0x0A; /// Status and Additional Data fields that identify the boot status pub fn boot_status_data(&self) -> Option> { // boot_status is from 1 to 10 bytes in length. The entire structure must be at least 0xB in length // and boot_status starts at offset 0xA; // meaning, at least 1 byte of boot_status exists, but not more than 10 bytes total. let struct_length = self.parts.header.length() as usize; if struct_length < Self::BOOT_STATUS_OFFSET + 1 { return None; } let end_index: usize; if struct_length < Self::BOOT_STATUS_OFFSET + Self::BOOT_STATUS_MAX_SIZE { end_index = struct_length; } else { end_index = Self::BOOT_STATUS_OFFSET + Self::BOOT_STATUS_MAX_SIZE; } self.parts .get_field_data(Self::BOOT_STATUS_OFFSET, end_index) .map(|raw| SystemBootStatusData { raw }) } } impl fmt::Debug for SMBiosSystemBootInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("boot_status_data", &self.boot_status_data()) .finish() } } impl Serialize for SMBiosSystemBootInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosSystemBootInformation", 2)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("boot_status_data", &self.boot_status_data())?; state.end() } } /// # Boot Status data of [SMBiosSystemBootInformation] pub struct SystemBootStatusData<'a> { /// Raw data pub raw: &'a [u8], } impl<'a> SystemBootStatusData<'a> { /// System boot status pub fn system_boot_status(&self) -> SystemBootStatus { debug_assert!(self.raw.len() > 0); match self.raw[0] { 0x00 => SystemBootStatus::NoErrors, 0x01 => SystemBootStatus::NoBootableMedia, 0x02 => SystemBootStatus::NormalOSFailedToLoad, 0x03 => SystemBootStatus::FirmwareDetectedFailure, 0x04 => SystemBootStatus::OSDetectedFailure, 0x05 => SystemBootStatus::UserRequestedBoot, 0x06 => SystemBootStatus::SystemSecurityViolation, 0x07 => SystemBootStatus::PreviouslyRequestedImage, 0x08 => SystemBootStatus::SystemWatchdogTimerExpired, _ => SystemBootStatus::None, } } } impl fmt::Debug for SystemBootStatusData<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("system_boot_status", &self.system_boot_status()) .finish() } } impl Serialize for SystemBootStatusData<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SystemBootStatusData", 1)?; state.serialize_field("system_boot_status", &self.system_boot_status())?; state.end() } } /// # System Boot Status #[derive(Serialize, Debug, PartialEq, Eq)] pub enum SystemBootStatus { /// No errors detected NoErrors, /// No bootable media NoBootableMedia, /// “normal” operating system failed to load NormalOSFailedToLoad, /// Firmware-detected hardware failure, including “unknown” failure types FirmwareDetectedFailure, /// Operating system-detected hardware failure /// For ACPI operating systems, the system firmware might set this reason code /// when the OS reports a boot failure through interfaces defined in the Simple /// Boot Flag Specification. OSDetectedFailure, /// User-requested boot, usually through a keystroke UserRequestedBoot, /// System security violation SystemSecurityViolation, /// Previously-requested image /// This reason code allows coordination between OS-present software and the /// OS-absent environment. For example, an OS-present application might /// enable (through a platform-specific interface) the system to boot to the PXE /// and request a specific boot-image. PreviouslyRequestedImage, /// System watchdog timer expired, causing the system to reboot SystemWatchdogTimerExpired, /// A value unknown to this standard, check the raw value None, } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { // test a normal structure with a 10 byte boot status field with "NoErrors" let struct_type32 = vec![ 0x20, 0x14, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type32); let test_struct = SMBiosSystemBootInformation::new(&parts); let boot_status_data = test_struct.boot_status_data().unwrap(); assert_eq!( boot_status_data.raw, &[0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] as &[u8] ); assert_eq!( boot_status_data.system_boot_status(), SystemBootStatus::NoErrors ); // test a structure with a 2 byte boot status field with "NormalOSFailedToLoad" let struct_type32 = vec![ 0x20, 0x0C, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, ]; let parts = UndefinedStruct::new(&struct_type32); let test_struct = SMBiosSystemBootInformation::new(&parts); let boot_status_data = test_struct.boot_status_data().unwrap(); assert_eq!(boot_status_data.raw, &[0x02u8, 0x01] as &[u8]); assert_eq!( boot_status_data.system_boot_status(), SystemBootStatus::NormalOSFailedToLoad ); // test a structure with a 2 byte boot status field but an incorrect header length // extending beyond the end of the structure let struct_type32 = vec![ 0x20, 0x0F, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, ]; let parts = UndefinedStruct::new(&struct_type32); let test_struct = SMBiosSystemBootInformation::new(&parts); assert!(test_struct.boot_status_data().is_none()); } } smbios-lib-0.9.2/src/structs/types/system_chassis_information.rs000064400000000000000000000736021046102023000233620ustar 00000000000000use crate::core::{strings::*, UndefinedStruct}; use crate::{BoardTypeData, SMBiosStruct, SMBiosType}; use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # System Enclosure or Chassis (Type 3) /// /// The information in this structure (see Table 16) defines attributes of the system’s mechanical /// enclosure(s). For example, if a system included a separate enclosure for its peripheral devices, two /// structures would be returned: one for the main system enclosure and the second for the peripheral device /// enclosure. The additions to this structure in version 2.1 of this specification support the population of the /// CIM_Chassis class. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosSystemChassisInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosSystemChassisInformation<'a> { const STRUCT_TYPE: u8 = 3u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosSystemChassisInformation<'a> { const CONTAINED_ELEMENTS_OFFSET: usize = 0x15usize; /// Manufacturer pub fn manufacturer(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Chassis type /// /// Bit 7 Chassis lock is present if 1. /// Otherwise, either a lock is not present or it is /// unknown if the enclosure has a lock. /// Bits 6:0 Enumeration value. pub fn chassis_type(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| ChassisTypeData::from(raw)) } /// Version pub fn version(&self) -> SMBiosString { self.parts.get_field_string(0x06) } /// Serial number pub fn serial_number(&self) -> SMBiosString { self.parts.get_field_string(0x07) } /// Asset tag number pub fn asset_tag_number(&self) -> SMBiosString { self.parts.get_field_string(0x08) } /// Boot-up State /// /// State of the enclosure when it was last booted. pub fn bootup_state(&self) -> Option { self.parts .get_field_byte(0x09) .map(|raw| ChassisStateData::from(raw)) } /// Power supply state /// /// State of the enclosure’s power supply (or /// supplies) when last booted pub fn power_supply_state(&self) -> Option { self.parts .get_field_byte(0x0A) .map(|raw| ChassisStateData::from(raw)) } /// Thermal state /// /// Thermal state of the enclosure when last /// booted. pub fn thermal_state(&self) -> Option { self.parts .get_field_byte(0x0B) .map(|raw| ChassisStateData::from(raw)) } /// Security status /// /// Physical security status of the enclosure when /// last booted. pub fn security_status(&self) -> Option { self.parts .get_field_byte(0x0C) .map(|raw| ChassisSecurityStatusData::from(raw)) } /// OEM-defined /// /// OEM- or BIOS vendor-specific information pub fn oem_defined(&self) -> Option { self.parts.get_field_dword(0x0D) } /// Height /// /// Height of the enclosure, in 'U's /// /// A U is a standard unit of measure for the /// height of a rack or rack-mountable component /// and is equal to 1.75 inches or 4.445 cm. pub fn height(&self) -> Option { self.parts .get_field_byte(0x11) .map(|raw| ChassisHeight::from(raw)) } /// Number of power cords /// /// Number of power cords associated with the /// enclosure or chassis pub fn number_of_power_cords(&self) -> Option { self.parts .get_field_byte(0x12) .map(|raw| PowerCords::from(raw)) } /// Contained element count (n) /// /// Number of Contained Element records that /// follow, in the range 0 to 255 /// Each Contained Element group comprises m /// bytes, as specified by the Contained Element /// Record Length field that follows. If no /// Contained Elements are included, this field is /// set to 0. pub fn contained_element_count(&self) -> Option { self.parts.get_field_byte(0x13) } /// Contained element record length (m) /// /// Byte length of each Contained Element record /// that follows, in the range 0 to 255 /// If no Contained Elements are included, this /// field is set to 0. For version 2.3.2 and later of /// this specification, this field is set to at least 03h /// when Contained Elements are specified. pub fn contained_element_record_length(&self) -> Option { self.parts.get_field_byte(0x14) } fn contained_elements_size(&self) -> Option { self.contained_element_record_length().and_then(|m| { self.contained_element_count() .and_then(|n| Some(m as usize * n as usize)) }) } /// Contained Elements pub fn contained_elements(&self) -> Option> { ContainedElements::new(self) } /// SKU number /// /// Chassis or enclosure SKU number pub fn sku_number(&self) -> SMBiosString { match self.contained_elements_size() { Some(size) => self .parts .get_field_string(Self::CONTAINED_ELEMENTS_OFFSET + size), None => Err(SMBiosStringError::FieldOutOfBounds).into(), } } } impl fmt::Debug for SMBiosSystemChassisInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("manufacturer", &self.manufacturer()) .field("chassis_type", &self.chassis_type()) .field("version", &self.version()) .field("serial_number", &self.serial_number()) .field("asset_tag_number", &self.asset_tag_number()) .field("bootup_state", &self.bootup_state()) .field("power_supply_state", &self.power_supply_state()) .field("thermal_state", &self.thermal_state()) .field("security_status", &self.security_status()) .field("oem_defined", &self.oem_defined()) .field("height", &self.height()) .field("number_of_power_cords", &self.number_of_power_cords()) .field("contained_element_count", &self.contained_element_count()) .field( "contained_element_record_length", &self.contained_element_record_length(), ) .field("contained_elements", &self.contained_elements()) .field("sku_number", &self.sku_number()) .finish() } } impl Serialize for SMBiosSystemChassisInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosSystemChassisInformation", 17)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("manufacturer", &self.manufacturer())?; state.serialize_field("chassis_type", &self.chassis_type())?; state.serialize_field("version", &self.version())?; state.serialize_field("serial_number", &self.serial_number())?; state.serialize_field("asset_tag_number", &self.asset_tag_number())?; state.serialize_field("bootup_state", &self.bootup_state())?; state.serialize_field("power_supply_state", &self.power_supply_state())?; state.serialize_field("thermal_state", &self.thermal_state())?; state.serialize_field("security_status", &self.security_status())?; state.serialize_field("oem_defined", &self.oem_defined())?; state.serialize_field("height", &self.height())?; state.serialize_field("number_of_power_cords", &self.number_of_power_cords())?; state.serialize_field("contained_element_count", &self.contained_element_count())?; state.serialize_field( "contained_element_record_length", &self.contained_element_record_length(), )?; state.serialize_field("contained_elements", &self.contained_elements())?; state.serialize_field("sku_number", &self.sku_number())?; state.end() } } /// # Chassis Height #[derive(Serialize, Debug)] pub enum ChassisHeight { /// A chassis enclosure height is not specified. Unspecified, /// Height of the enclosure, in 'U's /// /// A U is a standard unit of measure for the height of a rack /// or rack-mountable component and is equal to 1.75 inches or /// 4.445 cm. U(u8), } impl From for ChassisHeight { fn from(raw: u8) -> Self { match raw { 0 => ChassisHeight::Unspecified, _ => ChassisHeight::U(raw), } } } /// # Number of Power Cords #[derive(Serialize, Debug)] pub enum PowerCords { /// The number of power cords is not specified. Unspecified, /// The number of power cords Count(u8), } impl From for PowerCords { fn from(raw: u8) -> Self { match raw { 0 => PowerCords::Unspecified, _ => PowerCords::Count(raw), } } } /// # Chassis Lock Presence #[derive(Serialize, Debug)] pub enum ChassisLockPresence { /// The enclosure has a lock. Present, /// Either a lock is not present or it is unknown if the enclosure has a lock. NotPresent, } /// # Chassis Type Data pub struct ChassisTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [ChassisType] value pub value: ChassisType, /// Chassis lock presence pub lock_presence: ChassisLockPresence, } impl fmt::Debug for ChassisTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .field("lock_presence", &self.lock_presence) .finish() } } impl Serialize for ChassisTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ChassisTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.serialize_field("lock_presence", &self.lock_presence)?; state.end() } } impl fmt::Display for ChassisTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { ChassisType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for ChassisTypeData { type Target = ChassisType; fn deref(&self) -> &Self::Target { &self.value } } /// # Chassis Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum ChassisType { /// Other Other, /// Unknown Unknown, /// Desktop Desktop, /// Low Profile Desktop LowProfileDesktop, /// Pizza Box PizzaBox, /// Mini Tower MiniTower, /// Tower Tower, /// Portable Portable, /// Laptop Laptop, /// Notebook Notebook, /// Hand Held HandHeld, /// Docking Station DockingStation, /// All in One AllInOne, /// Sub Notebook SubNotebook, /// Space-saving SpaceSaving, /// Lunch Box LunchBox, /// Main Server Chassis MainServerChassis, /// Expansion Chassis ExpansionChassis, /// SubChassis SubChassis, /// Bus Expansion Chassis BusExpansionChassis, /// Peripheral Chassis PeripheralChassis, /// RAID Chassis RaidChassis, /// Rack Mount Chassis RackMountChassis, /// Sealed-case PC SealedCasePC, /// Multi-system chassis MultiSystemChassis, /// Compact PCI CompactPci, /// Advanced TCA AdvancedTca, /// Blade Blade, /// Blade Encloser BladeEnclosure, /// Tablet Tablet, /// Convertible Convertible, /// Detachable Detachable, /// IoT Gateway IoTGateway, /// Embedded PC EmbeddedPC, /// Mini PC MiniPC, /// Stick PC StickPC, /// A value unknown to this standard, check the raw value None, } impl From for ChassisTypeData { fn from(raw: u8) -> Self { ChassisTypeData { value: match raw & 0x7F { 0x01 => ChassisType::Other, 0x02 => ChassisType::Unknown, 0x03 => ChassisType::Desktop, 0x04 => ChassisType::LowProfileDesktop, 0x05 => ChassisType::PizzaBox, 0x06 => ChassisType::MiniTower, 0x07 => ChassisType::Tower, 0x08 => ChassisType::Portable, 0x09 => ChassisType::Laptop, 0x0A => ChassisType::Notebook, 0x0B => ChassisType::HandHeld, 0x0C => ChassisType::DockingStation, 0x0D => ChassisType::AllInOne, 0x0E => ChassisType::SubNotebook, 0x0F => ChassisType::SpaceSaving, 0x10 => ChassisType::LunchBox, 0x11 => ChassisType::MainServerChassis, 0x12 => ChassisType::ExpansionChassis, 0x13 => ChassisType::SubChassis, 0x14 => ChassisType::BusExpansionChassis, 0x15 => ChassisType::PeripheralChassis, 0x16 => ChassisType::RaidChassis, 0x17 => ChassisType::RackMountChassis, 0x18 => ChassisType::SealedCasePC, 0x19 => ChassisType::MultiSystemChassis, 0x1A => ChassisType::CompactPci, 0x1B => ChassisType::AdvancedTca, 0x1C => ChassisType::Blade, 0x1D => ChassisType::BladeEnclosure, 0x1E => ChassisType::Tablet, 0x1F => ChassisType::Convertible, 0x20 => ChassisType::Detachable, 0x21 => ChassisType::IoTGateway, 0x22 => ChassisType::EmbeddedPC, 0x23 => ChassisType::MiniPC, 0x24 => ChassisType::StickPC, _ => ChassisType::None, }, raw, lock_presence: if raw & 0x80 == 0x80 { ChassisLockPresence::Present } else { ChassisLockPresence::NotPresent }, } } } /// # Chassis State Data pub struct ChassisStateData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [ChassisState] value pub value: ChassisState, } impl fmt::Debug for ChassisStateData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for ChassisStateData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ChassisStateData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for ChassisStateData { type Target = ChassisState; fn deref(&self) -> &Self::Target { &self.value } } /// # Chassis Statue #[derive(Serialize, Debug, PartialEq, Eq)] pub enum ChassisState { /// Other Other, /// Unknown Unknown, /// Safe Safe, /// Warning Warning, /// Critical Critical, /// Non-recoverable NonRecoverable, /// A value unknown to this standard, check the raw value None, } impl From for ChassisStateData { fn from(raw: u8) -> Self { ChassisStateData { value: match raw { 0x01 => ChassisState::Other, 0x02 => ChassisState::Unknown, 0x03 => ChassisState::Safe, 0x04 => ChassisState::Warning, 0x05 => ChassisState::Critical, 0x06 => ChassisState::NonRecoverable, _ => ChassisState::None, }, raw, } } } /// # Chassis Security Status Data pub struct ChassisSecurityStatusData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [ChassisSecurityStatus] value pub value: ChassisSecurityStatus, } impl fmt::Debug for ChassisSecurityStatusData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for ChassisSecurityStatusData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ChassisSecurityStatusData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for ChassisSecurityStatusData { type Target = ChassisSecurityStatus; fn deref(&self) -> &Self::Target { &self.value } } /// # Chassis Security Status #[derive(Serialize, Debug, PartialEq, Eq)] pub enum ChassisSecurityStatus { /// Other Other, /// Unknown Unknown, /// None StatusNone, /// External interface locked out ExternalInterfaceLockedOut, /// External interface enabled ExternalInterfaceEnabled, /// A value unknown to this standard, check the raw value None, } impl From for ChassisSecurityStatusData { fn from(raw: u8) -> Self { ChassisSecurityStatusData { value: match raw { 0x01 => ChassisSecurityStatus::Other, 0x02 => ChassisSecurityStatus::Unknown, 0x03 => ChassisSecurityStatus::StatusNone, 0x04 => ChassisSecurityStatus::ExternalInterfaceLockedOut, 0x05 => ChassisSecurityStatus::ExternalInterfaceEnabled, _ => ChassisSecurityStatus::None, }, raw, } } } /// # Contained Elements pub struct ContainedElements<'a> { raw: &'a [u8], record_count: usize, record_length: usize, } impl<'a> ContainedElements<'a> { fn new(chassis_information: &'a SMBiosSystemChassisInformation<'a>) -> Option { chassis_information .contained_element_record_length() .and_then(|record_length| { chassis_information .contained_element_count() .and_then(|record_count| { chassis_information .parts() .get_field_data( SMBiosSystemChassisInformation::CONTAINED_ELEMENTS_OFFSET, SMBiosSystemChassisInformation::CONTAINED_ELEMENTS_OFFSET + (record_length as usize * record_count as usize), ) .and_then(|raw| { Some(Self { raw, record_count: record_count as usize, record_length: record_length as usize, }) }) }) }) } } impl<'a> fmt::Debug for ContainedElements<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("records", &self.into_iter()) .finish() } } impl<'a> Serialize for ContainedElements<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let elements: Vec> = self.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(elements.len()))?; for e in elements { seq.serialize_element(&e)?; } seq.end() } } /// # Contained Chassis Element pub struct ChassisElement<'a> { /// Raw byte slice for this chassis element pub raw: &'a [u8], } impl<'a> ChassisElement<'a> { const MINIMUM_RAW_SIZE: usize = 3usize; const ELEMENT_TYPE_OFFSET: usize = 0usize; const ELEMENT_MINIMUM_OFFSET: usize = 1usize; const ELEMENT_MAXIMUM_OFFSET: usize = 2usize; fn new(raw: &'a [u8]) -> Option { if raw.len() < Self::MINIMUM_RAW_SIZE { None } else { Some(Self { raw }) } } /// Contained Element Type pub fn element_type(&self) -> ElementType { ElementType::from(self.raw[Self::ELEMENT_TYPE_OFFSET]) } /// Contained Element Minimum pub fn element_minimum(&self) -> ElementMinimum { ElementMinimum::from(self.raw[Self::ELEMENT_MINIMUM_OFFSET]) } /// Contained Element Maximum pub fn element_maximum(&self) -> ElementMaximum { ElementMaximum::from(self.raw[Self::ELEMENT_MAXIMUM_OFFSET]) } } impl fmt::Debug for ChassisElement<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("raw", &self.raw) .field("element_type", &self.element_type()) .field("element_minimum", &self.element_minimum()) .field("element_maximum", &self.element_maximum()) .finish() } } impl Serialize for ChassisElement<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("ChassisElement", 4)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("element_type", &self.element_type())?; state.serialize_field("element_minimum", &self.element_minimum())?; state.serialize_field("element_maximum", &self.element_maximum())?; state.end() } } /// # Contained Element Type #[derive(Serialize, Debug)] pub enum ElementType { /// SMBIOS Baseboard Type enumeration BaseboardType(BoardTypeData), /// SMBIOS structure type enumeration SMBiosType(SMBiosType), } impl From for ElementType { fn from(raw: u8) -> Self { if raw & 0b1000_0000 == 0b1000_0000 { ElementType::SMBiosType(SMBiosType(raw & 0b0111_1111)) } else { ElementType::BaseboardType(BoardTypeData::from(raw)) } } } /// # Contained Element Minimum /// /// Specifies the minimum number of the 'element_type' that can be /// installed in the chassis for the chassis to properly operate, /// in the range 0 to 254. #[derive(Serialize, Debug)] pub enum ElementMinimum { /// Specifies the minimum number of the 'element_type' that can be /// installed in the chassis for the chassis to properly operate, /// in the range 0 to 254. Count(u8), /// The value 255 (0FFh) is reserved for future definition by this specification. Reserved, } impl From for ElementMinimum { fn from(raw: u8) -> Self { match raw { 0xFF => ElementMinimum::Reserved, _ => ElementMinimum::Count(raw), } } } /// # Contained Element Maximum /// /// Specifies the minimum number of the 'element_type' that can be /// installed in the chassis in the range 0 to 254. #[derive(Serialize, Debug)] pub enum ElementMaximum { /// Specifies the maximum number of the 'element_type' that can be /// installed in the chassis for the chassis to properly operate, /// in the range 1 to 255. Count(u8), /// The value 0 is reserved for future definition by this specification. Reserved, } impl From for ElementMaximum { fn from(raw: u8) -> Self { match raw { 0x00 => ElementMaximum::Reserved, _ => ElementMaximum::Count(raw), } } } /// # Iterates over the [ChassisElement] entries within [ContainedElements] pub struct ContainedElementsIterator<'a> { contained_elements: &'a ContainedElements<'a>, current_index: usize, current_entry: usize, } impl<'a> ContainedElementsIterator<'a> { fn reset(&mut self) { self.current_index = 0; self.current_entry = 0; } } impl<'a> IntoIterator for &'a ContainedElements<'a> { type Item = ChassisElement<'a>; type IntoIter = ContainedElementsIterator<'a>; fn into_iter(self) -> Self::IntoIter { ContainedElementsIterator { contained_elements: self, current_index: 0, current_entry: 0, } } } impl<'a> Iterator for ContainedElementsIterator<'a> { type Item = ChassisElement<'a>; fn next(&mut self) -> Option { if self.current_entry == self.contained_elements.record_count { self.reset(); return None; } let next_index = self.current_index + self.contained_elements.record_length; match ChassisElement::new(&self.contained_elements.raw[self.current_index..next_index]) { Some(chassis_element) => { self.current_index = next_index; self.current_entry += 1; Some(chassis_element) } None => { self.reset(); None } } } } impl<'a> fmt::Debug for ContainedElementsIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list() .entries(self.contained_elements.into_iter()) .finish() } } impl<'a> Serialize for ContainedElementsIterator<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let elements: Vec> = self.contained_elements.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(elements.len()))?; for e in elements { seq.serialize_element(&e)?; } seq.end() } } #[cfg(test)] mod tests { use super::*; use crate::structs::types::{ BoardType, ChassisHeight, ChassisSecurityStatus, ChassisState, ChassisType, ElementType, PowerCords, SMBiosSystemChassisInformation, }; #[test] fn unit_test() { let struct_type3 = vec![ 0x03, 0x1C, 0x03, 0x00, 0x01, 0x03, 0x02, 0x03, 0x04, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x85, 0x00, 0x02, 0x05, 0x00, 0x02, 0x05, b'L', b'E', b'N', b'O', b'V', b'O', 0x00, b'N', b'o', b'n', b'e', 0x00, b'M', b'J', b'0', b'6', b'U', b'R', b'D', b'Z', 0x00, b'4', b'0', b'8', b'9', b'9', b'8', b'5', 0x00, b'D', b'e', b'f', b'a', b'u', b'l', b't', b' ', b's', b't', b'r', b'i', b'n', b'g', 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type3); let test_struct = SMBiosSystemChassisInformation::new(&parts); assert_eq!(test_struct.manufacturer().to_string(), "LENOVO".to_string()); assert_eq!(*test_struct.chassis_type().unwrap(), ChassisType::Desktop); assert_eq!(test_struct.version().to_string(), "None".to_string()); assert_eq!( test_struct.serial_number().to_string(), "MJ06URDZ".to_string() ); assert_eq!( test_struct.asset_tag_number().to_string(), "4089985".to_string() ); assert_eq!(*test_struct.bootup_state().unwrap(), ChassisState::Safe); assert_eq!( *test_struct.power_supply_state().unwrap(), ChassisState::Safe ); assert_eq!(*test_struct.thermal_state().unwrap(), ChassisState::Safe); assert_eq!( *test_struct.security_status().unwrap(), ChassisSecurityStatus::StatusNone ); assert_eq!(test_struct.oem_defined(), Some(0)); match test_struct.height().unwrap() { ChassisHeight::U(_) => panic!("expected no height specified"), ChassisHeight::Unspecified => (), } match test_struct.number_of_power_cords().unwrap() { PowerCords::Count(count) => assert_eq!(count, 1), PowerCords::Unspecified => panic!("expected a count"), } assert_eq!(test_struct.contained_element_count(), Some(2)); assert_eq!(test_struct.contained_element_record_length(), Some(3)); let contained_elements = test_struct.contained_elements().unwrap(); let mut iterator = contained_elements.into_iter(); let first = iterator.next().unwrap(); match first.element_type() { ElementType::SMBiosType(bios_type) => { assert_eq!(*bios_type, 5) } _ => panic!("expected SMBIOS type"), } let second = iterator.next().unwrap(); match second.element_type() { ElementType::BaseboardType(baseboard_type) => { assert_eq!(*baseboard_type, BoardType::SystemManagementModule) } _ => panic!("expected baseboard type"), } assert_eq!( test_struct.sku_number().to_string(), "Default string".to_string() ); } } smbios-lib-0.9.2/src/structs/types/system_configuration_options.rs000064400000000000000000000052401046102023000237330ustar 00000000000000use crate::{SMBiosStringSet, SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # System Configuration Options (Type 12) /// /// This structure contains information required to configure the baseboard’s Jumpers and Switches. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosSystemConfigurationOptions<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosSystemConfigurationOptions<'a> { const STRUCT_TYPE: u8 = 12u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosSystemConfigurationOptions<'a> { /// Number of strings pub fn count(&self) -> Option { self.parts.get_field_byte(0x04) } /// Iterable collection of OEM strings /// /// EXAMPLES: /// "JP2: 1-2 Cache Size is 256K, 2-3 Cache Size is 512K" /// "SW1-1: Close to Disable On Board Video" pub fn configuration_strings(&self) -> &SMBiosStringSet { &self.parts.strings } } impl fmt::Debug for SMBiosSystemConfigurationOptions<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("count", &self.count()) .field("configuration_strings", &self.configuration_strings()) .finish() } } impl Serialize for SMBiosSystemConfigurationOptions<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosSystemConfigurationOptions", 3)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("count", &self.count())?; state.serialize_field("configuration_strings", &self.configuration_strings())?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type12 = vec![ 0x0C, 0x05, 0x23, 0x00, 0x01, b's', b'c', b'r', b'e', b'+', b'+', 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type12); let test_struct = SMBiosSystemConfigurationOptions::new(&parts); assert_eq!(test_struct.count(), Some(1)); assert_eq!( test_struct .configuration_strings() .into_iter() .next() .unwrap() .ok(), Some("scre++".to_string()) ); } } smbios-lib-0.9.2/src/structs/types/system_event_log.rs000064400000000000000000000726321046102023000213040ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer}; use std::fmt; use std::ops::Deref; /// # System Event Log (Type 15) /// /// The presence of this structure within the SMBIOS data returned for a system indicates that the system /// supports an event log. An event log is a fixed-length area within a non-volatile /// storage element, starting with a fixed-length (and vendor-specific) header record, followed by one or more /// variable-length log records. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosSystemEventLog<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosSystemEventLog<'a> { const STRUCT_TYPE: u8 = 15u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosSystemEventLog<'a> { const LOG_TYPE_DESCRIPTORS_OFFSET: usize = 0x17usize; /// Length, in bytes, of the overall event log area, /// from the first byte of header to the last byte of data pub fn log_area_length(&self) -> Option { self.parts.get_field_word(0x04) } /// Defines the starting offset (or index) within the /// nonvolatile storage of the event-log’s header, /// from the Access Method Address /// For single-byte indexed I/O accesses, the /// most-significant byte of the start offset is set /// to 00h. pub fn log_header_start_offset(&self) -> Option { self.parts.get_field_word(0x06) } /// Defines the starting offset (or index) within the /// nonvolatile storage of the event-log’s first /// data byte, from the Access Method Address /// For single-byte indexed I/O accesses, the /// most-significant byte of the start offset is set /// to 00h. /// /// NOTE: The data directly follows any header /// information. Therefore, the header length /// can be determined by subtracting the /// Header Start Offset from the Data Start /// Offset. pub fn log_data_start_offset(&self) -> Option { self.parts.get_field_word(0x08) } /// Defines the Location and Method used by higher-level software to access the log area pub fn access_method(&self) -> Option { self.parts .get_field_byte(0x0A) .map(|raw| AccessMethodData::from(raw)) } /// Current status of the system event-log pub fn log_status(&self) -> Option { self.parts .get_field_byte(0x0B) .map(|raw| LogStatus::from(raw)) } /// Unique token that is reassigned every time /// the event log changes /// /// Can be used to determine if additional events /// have occurred since the last time the log was /// read. pub fn log_change_token(&self) -> Option { self.parts.get_field_dword(0x0C) } /// Address associated with the access method /// /// The data present depends on the Access /// Method field value pub fn access_method_address(&self) -> Option { self.parts.get_field_dword(0x10) } /// Format of the log header area pub fn log_header_format(&self) -> Option { self.parts .get_field_byte(0x14) .map(|raw| HeaderFormatData::from(raw)) } /// Number of supported event log type /// descriptors that follow /// /// If the value is 0, the list that starts at offset /// 17h is not present. pub fn number_of_supported_log_type_descriptors(&self) -> Option { self.parts.get_field_byte(0x15) } /// Number of bytes associated with each type /// entry in the list below /// The value is currently “hard-coded” as 2, /// because each entry consists of two bytes. /// This field’s presence allows future additions /// to the type list. Software that interprets the /// following list should not assume a list entry’s /// length. pub fn length_of_each_log_type_descriptor(&self) -> Option { self.parts.get_field_byte(0x16) } /// Type Descriptors pub fn type_descriptors(&self) -> Option> { TypeDescriptors::new(self) } } impl fmt::Debug for SMBiosSystemEventLog<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("log_area_length", &self.log_area_length()) .field("log_header_start_offset", &self.log_header_start_offset()) .field("log_data_start_offset", &self.log_data_start_offset()) .field("access_method", &self.access_method()) .field("log_status", &self.log_status()) .field("log_change_token", &self.log_change_token()) .field("access_method_address", &self.access_method_address()) .field("log_header_format", &self.log_header_format()) .field( "number_of_supported_log_type_descriptors", &self.number_of_supported_log_type_descriptors(), ) .field( "length_of_each_log_type_descriptor", &self.length_of_each_log_type_descriptor(), ) .field("type_descriptors", &self.type_descriptors()) .finish() } } impl Serialize for SMBiosSystemEventLog<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosSystemEventLog", 12)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("log_area_length", &self.log_area_length())?; state.serialize_field("log_header_start_offset", &self.log_header_start_offset())?; state.serialize_field("log_data_start_offset", &self.log_data_start_offset())?; state.serialize_field("access_method", &self.access_method())?; state.serialize_field("log_status", &self.log_status())?; state.serialize_field("log_change_token", &self.log_change_token())?; state.serialize_field("access_method_address", &self.access_method_address())?; state.serialize_field("log_header_format", &self.log_header_format())?; state.serialize_field( "number_of_supported_log_type_descriptors", &self.number_of_supported_log_type_descriptors(), )?; state.serialize_field( "length_of_each_log_type_descriptor", &self.length_of_each_log_type_descriptor(), )?; state.serialize_field("type_descriptors", &self.type_descriptors())?; state.end() } } /// # System Event Log - Log Type Data pub struct LogTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [LogType] value pub value: LogType, } impl fmt::Debug for LogTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for LogTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("LogTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for LogTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { LogType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for LogTypeData { type Target = LogType; fn deref(&self) -> &Self::Target { &self.value } } /// # System Event Log - Log Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum LogType { /// Single-bit ECC memory error SingleBitEccMemoryError, /// Multi-bit ECC memory error MultiBitEccMemoryError, /// Parity memory error ParityMemoryError, /// Bus time-out BusTimeOut, /// I/O Channel Check IOChannelCheck, /// Software NMI SoftwareNmi, /// POST Memory Resize PostMemoryResize, /// POST Error PostError, /// PCI Parity Error PciParityError, /// PCI System Error PciSystemError, /// CPU Failure CpuFailure, /// EISA FailSafe Timer time-out EisaFailSafeTimerTimeout, /// Correctable memory log disabled CorrectableMemoryLogDisabled, /// Logging disabled for a specific Event Type — too many errors of the same type received in a short amount of time LoggingDisabledForSpecificEventType, /// Reserved Reserved0F, /// System Limit Exceeded (for example, voltage or temperature threshold exceeded) SystemLimitExceeded, /// Asynchronous hardware timer expired and issued a system reset AsyncHardwareTimerExpired, /// System configuration information SystemConfigurationInformation, /// Hard-disk information HardDiskInformation, /// System reconfigured SystemReconfigured, /// Uncorrectable CPU-complex error UncorrectableCpuComplexError, /// Log Area Reset/Cleared LogAreaReset, /// System boot. If implemented, this log entry is guaranteed to be the first one written on any system boot. SystemBoot, /// A value unknown to this standard, check the raw value None, } impl From for LogTypeData { fn from(raw: u8) -> Self { LogTypeData { value: match raw { 0x01 => LogType::SingleBitEccMemoryError, 0x02 => LogType::MultiBitEccMemoryError, 0x03 => LogType::ParityMemoryError, 0x04 => LogType::BusTimeOut, 0x05 => LogType::IOChannelCheck, 0x06 => LogType::SoftwareNmi, 0x07 => LogType::PostMemoryResize, 0x08 => LogType::PostError, 0x09 => LogType::PciParityError, 0x0A => LogType::PciSystemError, 0x0B => LogType::CpuFailure, 0x0C => LogType::EisaFailSafeTimerTimeout, 0x0D => LogType::CorrectableMemoryLogDisabled, 0x0E => LogType::LoggingDisabledForSpecificEventType, 0x0F => LogType::Reserved0F, 0x10 => LogType::SystemLimitExceeded, 0x11 => LogType::AsyncHardwareTimerExpired, 0x12 => LogType::SystemConfigurationInformation, 0x13 => LogType::HardDiskInformation, 0x14 => LogType::SystemReconfigured, 0x15 => LogType::UncorrectableCpuComplexError, 0x16 => LogType::LogAreaReset, 0x17 => LogType::SystemBoot, _ => LogType::None, }, raw, } } } /// # System Event Log - Variable Data Format Type Data pub struct VariableDataFormatTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [VariableDataFormatType] value pub value: VariableDataFormatType, } impl fmt::Debug for VariableDataFormatTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for VariableDataFormatTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("VariableDataFormatTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for VariableDataFormatTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { VariableDataFormatType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for VariableDataFormatTypeData { type Target = VariableDataFormatType; fn deref(&self) -> &Self::Target { &self.value } } /// # System Event Log - Variable Data Format Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum VariableDataFormatType { /// No standard format data is available; the first byte of the variable data (if present) contains OEM-specific unformatted information. NoStandardFormat, /// The first WORD of the variable data contains the handle of the SMBIOS structure associated with the hardware element that failed. Handle, /// The first DWORD of the variable data contains a multiple-event counter (see 7.16.6.3 for details). MultipleEvent, /// The first WORD of the variable data contains the handle of the SMBIOS structure associated with the hardware element that failed; it is followed by a DWORD containing a multiple-event counter (see 7.16.6.3 for details). MultipleEventHandle, /// The first two DWORDs of the variable data contain the POST Results Bitmap, as described in 7.16.6.4. PostResultsBitmap, /// The first DWORD of the variable data contains a value that identifies a system-management condition. See 7.16.6.5 for the enumerated values. SystemManagementType, /// The first DWORD of the variable data contains a value that identifies a system-management condition. (See 7.16.6.5 for the enumerated values.) This DWORD is directly followed by a DWORD that contains a multiple- event counter (see 7.16.6.3 for details). MultipleEventSystemManagementType, /// A value unknown to this standard, check the raw value None, } impl From for VariableDataFormatTypeData { fn from(raw: u8) -> Self { VariableDataFormatTypeData { value: match raw { 0x00 => VariableDataFormatType::NoStandardFormat, 0x01 => VariableDataFormatType::Handle, 0x02 => VariableDataFormatType::MultipleEvent, 0x03 => VariableDataFormatType::MultipleEventHandle, 0x04 => VariableDataFormatType::PostResultsBitmap, 0x05 => VariableDataFormatType::SystemManagementType, 0x06 => VariableDataFormatType::MultipleEventSystemManagementType, _ => VariableDataFormatType::None, }, raw, } } } /// # System Event Log - Access Method Data pub struct AccessMethodData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [AccessMethod] value pub value: AccessMethod, } impl fmt::Debug for AccessMethodData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for AccessMethodData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("AccessMethodData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for AccessMethodData { type Target = AccessMethod; fn deref(&self) -> &Self::Target { &self.value } } impl From for AccessMethodData { fn from(raw: u8) -> Self { AccessMethodData { value: AccessMethod::from(raw), raw, } } } /// # System Event Log - Access Method /// /// Defines the Location and Method used by higher-level software to access the log area. #[derive(Serialize, Debug, PartialEq, Eq)] pub enum AccessMethod { /// 00h Indexed I/O /// /// 1 8-bit index port, 1 8-bit data port. The Access Method Address field contains the /// 16-bit I/O addresses for the index and data ports. See 7.16.2.1 for usage details. IndexedIO18Bit, /// 01h Indexed I/O /// /// 2 8-bit index ports, 1 8-bit data port. The Access Method Address field contains the /// 16-bit I/O address for the index and data ports. See 7.16.2.2 for usage details. IndexedIO28Bit, /// 02h Indexed I/O /// /// 1 16-bit index port, 1 8-bit data port. The Access Method Address field contains the /// 16-bit I/O address for the index and data ports. See 7.16.2.3 for usage details. IndexedIO116Bit, /// 03h Memory-mapped physical 32-bit address. /// /// The Access Method Address field contains the 4-byte (Intel DWORD format) starting physical address. MemoryMapped32Bit, /// 04h Available through General-Purpose NonVolatile Data functions. /// /// The Access Method Address field contains the 2-byte (Intel WORD format) GPNV handle. GeneralPurposeNonVolatile, /// A value unknown to this standard, check the raw value None, } impl From for AccessMethod { fn from(raw: u8) -> Self { match raw { 0x00 => AccessMethod::IndexedIO18Bit, 0x01 => AccessMethod::IndexedIO28Bit, 0x02 => AccessMethod::IndexedIO116Bit, 0x03 => AccessMethod::MemoryMapped32Bit, 0x04 => AccessMethod::GeneralPurposeNonVolatile, _ => AccessMethod::None, } } } /// System Event Log Type Descriptor /// /// Each entry consists of a 1-byte type field and a 1-byte data-format descriptor, as shown in Table 61. The /// presence of an entry identifies that the Log Type is supported by the system and the format of any /// variable data that accompanies the first bytes of the log’s variable data — a specific log record might /// have more variable data than specified by its Variable Data Format Type. pub struct EventLogTypeDescriptor<'a> { /// Raw byte slice for this event log type descriptor pub raw: &'a [u8], } impl<'a> EventLogTypeDescriptor<'a> { const MINIMUM_RAW_SIZE: usize = 2usize; const LOG_TYPE_OFFSET: usize = 0usize; const VARIABLE_DATA_FORMAT_TYPE_OFFSET: usize = 1usize; fn new(raw: &'a [u8]) -> Option { if raw.len() < Self::MINIMUM_RAW_SIZE { None } else { Some(Self { raw }) } } /// Event Log Type pub fn log_type(&self) -> LogTypeData { LogTypeData::from(self.raw[Self::LOG_TYPE_OFFSET]) } /// Event Log Variable Data Format Type /// /// The Variable Data Format Type, specified in the Event Log structure’s Supported Event Type fields, /// identifies the standard format that application software can apply to the first n bytes of the associated. /// Log Type’s variable data.Additional OEM-specific data might follow in the log’s variable data field. pub fn variable_data_format_type(&self) -> VariableDataFormatTypeData { VariableDataFormatTypeData::from(self.raw[Self::VARIABLE_DATA_FORMAT_TYPE_OFFSET]) } } impl<'a> fmt::Debug for EventLogTypeDescriptor<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("raw", &self.raw) .field("log_type", &self.log_type()) .field( "variable_data_format_type", &self.variable_data_format_type(), ) .finish() } } impl<'a> Serialize for EventLogTypeDescriptor<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("EventLogTypeDescriptor", 3)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("log_type", &self.log_type())?; state.serialize_field( "variable_data_format_type", &self.variable_data_format_type(), )?; state.end() } } /// # System Event Log Type Descriptors within [SMBiosSystemEventLog] pub struct TypeDescriptors<'a> { raw: &'a [u8], record_count: usize, record_length: usize, } impl<'a> TypeDescriptors<'a> { fn new(system_event_log: &'a SMBiosSystemEventLog<'a>) -> Option { system_event_log .length_of_each_log_type_descriptor() .and_then(|record_length| { system_event_log .number_of_supported_log_type_descriptors() .and_then(|record_count| { system_event_log .parts() .get_field_data( SMBiosSystemEventLog::LOG_TYPE_DESCRIPTORS_OFFSET, SMBiosSystemEventLog::LOG_TYPE_DESCRIPTORS_OFFSET + (record_length as usize * record_count as usize), ) .and_then(|raw| { Some(Self { raw, record_count: record_count as usize, record_length: record_length as usize, }) }) }) }) } } impl<'a> fmt::Debug for TypeDescriptors<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("descriptors", &self.into_iter()) .finish() } } impl<'a> Serialize for TypeDescriptors<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut seq = serializer.serialize_seq(Some(self.record_count))?; for e in self { seq.serialize_element(&e)?; } seq.end() } } /// # Iterates over the [EventLogTypeDescriptor] entries within [TypeDescriptors] pub struct TypeDescriptorsIterator<'a> { descriptors: &'a TypeDescriptors<'a>, current_index: usize, current_entry: usize, } impl<'a> TypeDescriptorsIterator<'a> { fn reset(&mut self) { self.current_index = 0; self.current_entry = 0; } } impl<'a> IntoIterator for &'a TypeDescriptors<'a> { type Item = EventLogTypeDescriptor<'a>; type IntoIter = TypeDescriptorsIterator<'a>; fn into_iter(self) -> Self::IntoIter { TypeDescriptorsIterator { descriptors: self, current_index: 0, current_entry: 0, } } } impl<'a> Iterator for TypeDescriptorsIterator<'a> { type Item = EventLogTypeDescriptor<'a>; fn next(&mut self) -> Option { if self.current_entry == self.descriptors.record_count { self.reset(); return None; } let next_index = self.current_index + self.descriptors.record_length; match EventLogTypeDescriptor::new(&self.descriptors.raw[self.current_index..next_index]) { Some(event_log_type_descriptor) => { self.current_index = next_index; self.current_entry += 1; Some(event_log_type_descriptor) } None => { self.reset(); None } } } } impl<'a> fmt::Debug for TypeDescriptorsIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list() .entries(self.descriptors.into_iter()) .finish() } } impl<'a> Serialize for TypeDescriptorsIterator<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let descriptors: Vec> = self.descriptors.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(descriptors.len()))?; for e in descriptors { seq.serialize_element(&e)?; } seq.end() } } /// # System Event Log - Log Status #[derive(PartialEq, Eq)] pub struct LogStatus { /// Raw value pub raw: u8, } impl Deref for LogStatus { type Target = u8; fn deref(&self) -> &Self::Target { &self.raw } } impl From for LogStatus { fn from(raw: u8) -> Self { LogStatus { raw } } } impl LogStatus { /// If true, log area valid; otherwise false pub fn log_area_valid(&self) -> bool { self.raw & 0x01 == 0x01 } /// If true log area full; otherwise false pub fn log_area_full(&self) -> bool { self.raw & 0x02 == 0x02 } } impl fmt::Debug for LogStatus { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("log_area_valid", &self.log_area_valid()) .field("log_area_full", &self.log_area_full()) .finish() } } impl Serialize for LogStatus { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("LogStatus", 3)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("log_area_valid", &self.log_area_valid())?; state.serialize_field("log_area_full", &self.log_area_full())?; state.end() } } /// # System Event Log - Header Format Data pub struct HeaderFormatData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [HeaderFormat] value pub value: HeaderFormat, } impl fmt::Debug for HeaderFormatData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for HeaderFormatData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("HeaderFormatData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl Deref for HeaderFormatData { type Target = HeaderFormat; fn deref(&self) -> &Self::Target { &self.value } } /// # System Event Log - Header Format #[derive(Serialize, Debug, PartialEq, Eq)] pub enum HeaderFormat { /// No header (for example, the header is 0 bytes in length) NoHeader, /// Type 1 log header Type1LogHeader, /// A value unknown to this standard, check the raw value None, } impl From for HeaderFormatData { fn from(raw: u8) -> Self { HeaderFormatData { value: match raw { 0x00 => HeaderFormat::NoHeader, 0x01 => HeaderFormat::Type1LogHeader, _ => HeaderFormat::None, }, raw, } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type15 = vec![ 0x0F, 0x49, 0x3D, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x03, 0x01, 0x05, 0x00, 0x00, 0x00, 0x18, 0x20, 0xAE, 0x6A, 0x01, 0x19, 0x02, 0x01, 0x03, 0x02, 0x03, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x04, 0x09, 0x03, 0x0A, 0x03, 0x0B, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0xFF, 0x00, 0xE0, 0xE0, 0xE1, 0xE1, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type15); let test_struct = SMBiosSystemEventLog::new(&parts); println!("{:?}", test_struct); assert_eq!(test_struct.log_area_length(), Some(4096)); assert_eq!(test_struct.log_header_start_offset(), Some(0)); assert_eq!(test_struct.log_data_start_offset(), Some(16)); assert_eq!( *test_struct.access_method().unwrap(), AccessMethod::MemoryMapped32Bit ); assert_eq!( test_struct.log_status().unwrap(), LogStatus::from(0b0000_0001) ); assert_eq!(test_struct.log_change_token(), Some(5)); assert_eq!(test_struct.access_method_address(), Some(1789796376)); assert_eq!( *test_struct.log_header_format().unwrap(), HeaderFormat::Type1LogHeader ); assert_eq!( test_struct.number_of_supported_log_type_descriptors(), Some(25) ); assert_eq!(test_struct.length_of_each_log_type_descriptor(), Some(2)); let type_descriptors = test_struct.type_descriptors().unwrap(); let mut iterator = type_descriptors.into_iter(); let first = iterator.next().unwrap(); assert_eq!(*first.log_type(), LogType::SingleBitEccMemoryError); } } smbios-lib-0.9.2/src/structs/types/system_information.rs000064400000000000000000000321071046102023000216400ustar 00000000000000use crate::core::{strings::*, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::{ array::TryFromSliceError, convert::{TryFrom, TryInto}, fmt, ops::Deref, }; /// # System Information (Type 1) /// /// The information in this structure defines attributes of the overall system and is intended to be associated /// with the Component ID group of the system’s MIF. An SMBIOS implementation is associated with a single /// system instance and contains one and only one System Information (Type 1) structure. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosSystemInformation<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosSystemInformation<'a> { const STRUCT_TYPE: u8 = 1u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosSystemInformation<'a> { /// Manufacturer pub fn manufacturer(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Product name pub fn product_name(&self) -> SMBiosString { self.parts.get_field_string(0x05) } /// Version pub fn version(&self) -> SMBiosString { self.parts.get_field_string(0x06) } /// Serial number pub fn serial_number(&self) -> SMBiosString { self.parts.get_field_string(0x07) } /// System UUID pub fn uuid(&self) -> Option { self.parts .get_field_data(0x08, 0x18) .map(|raw| SystemUuidData::try_from(raw).expect("A GUID is 0x10 bytes")) } /// Wake-up type /// /// Identifies the event that caused the system to power up. pub fn wakeup_type(&self) -> Option { self.parts .get_field_byte(0x18) .map(|raw| SystemWakeUpTypeData::from(raw)) } /// SKU Number /// /// This text string identifies a particular computer /// configuration for sale. It is sometimes also /// called a product ID or purchase order number. /// This number is frequently found in existing /// fields, but there is no standard format. /// Typically for a given system board from a /// given OEM, there are tens of unique /// processor, memory, hard drive, and optical /// drive configurations. pub fn sku_number(&self) -> SMBiosString { self.parts.get_field_string(0x19) } /// Family /// /// This text string identifies the family to which a /// particular computer belongs. A family refers to /// a set of computers that are similar but not /// identical from a hardware or software point of /// view. Typically, a family is composed of /// different computer models, which have /// different configurations and pricing points. /// Computers in the same family often have /// similar branding and cosmetic features. pub fn family(&self) -> SMBiosString { self.parts.get_field_string(0x1A) } } impl fmt::Debug for SMBiosSystemInformation<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("manufacturer", &self.manufacturer()) .field("product_name", &self.product_name()) .field("version", &self.version()) .field("serial_number", &self.serial_number()) .field("uuid", &self.uuid()) .field("wakeup_type", &self.wakeup_type()) .field("sku_number", &self.sku_number()) .field("family", &self.family()) .finish() } } impl Serialize for SMBiosSystemInformation<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosSystemInformation", 9)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("manufacturer", &self.manufacturer())?; state.serialize_field("product_name", &self.product_name())?; state.serialize_field("version", &self.version())?; state.serialize_field("serial_number", &self.serial_number())?; state.serialize_field("uuid", &self.uuid())?; state.serialize_field("wakeup_type", &self.wakeup_type())?; state.serialize_field("sku_number", &self.sku_number())?; state.serialize_field("family", &self.family())?; state.end() } } /// # System - UUID Data #[derive(Serialize, Debug)] pub enum SystemUuidData { /// The ID is not currently present in the system, but it can be set IdNotPresentButSettable, /// The ID is not present in the system IdNotPresent, /// System UUID Uuid(SystemUuid), } impl SystemUuidData { fn new<'a>(array: &'a [u8; 0x10]) -> SystemUuidData { if array.iter().all(|&x| x == 0) { SystemUuidData::IdNotPresentButSettable } else if array.iter().all(|&x| x == 0xFF) { SystemUuidData::IdNotPresent } else { SystemUuidData::Uuid(SystemUuid::from(array)) } } } impl<'a> TryFrom<&'a [u8]> for SystemUuidData { type Error = TryFromSliceError; fn try_from(raw: &'a [u8]) -> Result { <&[u8; 0x10]>::try_from(raw).and_then(|array| Ok(SystemUuidData::new(array))) } } impl fmt::Display for SystemUuidData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &*self { SystemUuidData::IdNotPresent => write!(f, "IdNotPresent"), SystemUuidData::IdNotPresentButSettable => write!(f, "IdNotPresentButSettable"), SystemUuidData::Uuid(_system_uuid) => write!(f, "{}", &_system_uuid), } } } /// # System - UUID #[derive(PartialEq, Eq)] pub struct SystemUuid { /// Raw byte array for this UUID pub raw: [u8; 0x10], } impl SystemUuid { /// Low field of the timestamp pub fn time_low(&self) -> u32 { u32::from_le_bytes(self.raw[..0x4].try_into().expect("incorrect size")) } /// Middle field of the timestamp pub fn time_mid(&self) -> u16 { u16::from_le_bytes(self.raw[0x4..0x6].try_into().expect("incorrect size")) } /// High field of the timestamp multiplexed with the version number pub fn time_high_and_version(&self) -> u16 { u16::from_le_bytes(self.raw[0x6..0x8].try_into().expect("incorrect size")) } /// High field of the clock sequence multiplexed with the variant pub fn clock_seq_high_and_reserved(&self) -> u8 { self.raw[0x8] } /// Low field of the clock sequence pub fn clock_seq_low(&self) -> u8 { self.raw[0x9] } /// Spatially unique node identifier pub fn node(&self) -> &[u8; 6] { self.raw[0xA..0x10].try_into().expect("incorrect size") } } impl<'a> From<&'a [u8; 0x10]> for SystemUuid { fn from(raw: &'a [u8; 0x10]) -> Self { SystemUuid { raw: raw.clone() } } } impl fmt::Display for SystemUuid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Example output: // "00360fe7-d4d5-11e5-9c43-bc0000f00000" // ---- // Format is described in RFC4122, but the actual field contents are opaque and not // significant to the SMBIOS specification, which is only concerned with the byte order. // http://www.ietf.org/rfc/rfc4122.txt // RFC4122: The hexadecimal values "a" through "f" are output as // lower case characters and are case insensitive on input. write!( f, "{:08x}-{:04x}-{:04x}-{:02x}{:02x}-", self.time_low(), self.time_mid(), self.time_high_and_version(), self.clock_seq_high_and_reserved(), self.clock_seq_low() )?; self.node().iter().fold(Ok(()), |result, node_byte| { result.and_then(|_| write!(f, "{:02x}", node_byte)) }) } } impl fmt::Debug for SystemUuid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", &self) } } impl Serialize for SystemUuid { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_str(format!("{}", self).as_str()) } } /// # System - Wake-up Type Data pub struct SystemWakeUpTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [SystemWakeUpType] value pub value: SystemWakeUpType, } impl fmt::Debug for SystemWakeUpTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for SystemWakeUpTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SystemWakeUpTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for SystemWakeUpTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { SystemWakeUpType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } impl Deref for SystemWakeUpTypeData { type Target = SystemWakeUpType; fn deref(&self) -> &Self::Target { &self.value } } /// # System - Wake-up Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum SystemWakeUpType { /// Other Other, /// Unknown Unknown, /// APM Timer ApmTimer, /// Modem Ring ModernRing, /// LAN Remote LanRemote, /// Power Switch PowerSwitch, /// PCI PME# PciPme, /// AC Power Restored ACPowerRestored, /// A value unknown to this standard, check the raw value None, } impl From for SystemWakeUpTypeData { fn from(raw: u8) -> Self { SystemWakeUpTypeData { value: match raw { 0x01 => SystemWakeUpType::Other, 0x02 => SystemWakeUpType::Unknown, 0x03 => SystemWakeUpType::ApmTimer, 0x04 => SystemWakeUpType::ModernRing, 0x05 => SystemWakeUpType::LanRemote, 0x06 => SystemWakeUpType::PowerSwitch, 0x07 => SystemWakeUpType::PciPme, 0x08 => SystemWakeUpType::ACPowerRestored, _ => SystemWakeUpType::None, }, raw, } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type1 = vec![ 0x01, 0x1B, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0xD2, 0x01, 0x25, 0x3E, 0x48, 0xE6, 0x11, 0xE8, 0xBA, 0xD3, 0x70, 0x20, 0x84, 0x0F, 0x9D, 0x47, 0x06, 0x05, 0x06, b'L', b'E', b'N', b'O', b'V', b'O', 0x00, b'3', b'0', b'B', b'F', b'S', b'0', b'7', b'5', b'0', b'0', 0x00, b'T', b'h', b'i', b'n', b'k', b'S', b't', b'a', b't', b'i', b'o', b'n', b' ', b'P', b'5', b'2', b'0', 0x00, b'M', b'N', b'0', b'6', b'P', b'Q', b'R', b'S', 0x00, b'L', b'E', b'N', b'O', b'V', b'O', b'_', b'M', b'T', b'_', b'3', b'0', b'B', b'F', b'_', b'B', b'U', b'_', b'T', b'h', b'i', b'n', b'k', b'_', b'F', b'M', b'_', b'T', b'h', b'i', b'n', b'k', b'S', b't', b'a', b't', b'i', b'o', b'n', b' ', b'P', b'5', b'2', b'0', 0x00, b'T', b'h', b'i', b'n', b'k', b'S', b't', b'a', b't', b'i', b'o', b'n', b' ', b'P', b'5', b'2', b'0', 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type1); let test_struct = SMBiosSystemInformation::new(&parts); assert_eq!(test_struct.manufacturer().to_string(), "LENOVO".to_string()); assert_eq!( test_struct.product_name().to_string(), "30BFS07500".to_string() ); assert_eq!( test_struct.version().to_string(), "ThinkStation P520".to_string() ); assert_eq!( test_struct.serial_number().to_string(), "MN06PQRS".to_string() ); assert_eq!( format!("{:?}", test_struct.uuid()), "Some(Uuid(3e2501d2-e648-e811-bad3-7020840f9d47))".to_string() ); assert_eq!( *test_struct.wakeup_type().unwrap(), SystemWakeUpType::PowerSwitch ); assert_eq!( test_struct.sku_number().to_string(), "LENOVO_MT_30BF_BU_Think_FM_ThinkStation P520".to_string() ); assert_eq!( test_struct.family().to_string(), "ThinkStation P520".to_string() ); } } smbios-lib-0.9.2/src/structs/types/system_power_controls.rs000064400000000000000000000121441046102023000223710ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # System Power Controls (Type 25) /// /// This structure describes the attributes for controlling the main power supply to the system. /// /// Software that interprets this structure uses the month, day, hour, minute, and second values to determine /// the number of seconds until the next power-on of the system. The presence of this structure implies that a /// timed power-on facility is available for the system. /// /// NOTE This structure type was added in version 2.2 of the specification. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosSystemPowerControls<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosSystemPowerControls<'a> { const STRUCT_TYPE: u8 = 25u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosSystemPowerControls<'a> { /// Next scheduled power-on month /// /// BCD value of the month on which the next scheduled /// power-on is to occur, in the range 01h to 12h. pub fn next_scheduled_power_on_month(&self) -> Option { self.parts.get_field_byte(0x04) } /// Next scheduled power-on day-of month /// /// BCD value of the day-of-month on which the next /// scheduled power-on is to occur, in the range 01h to 31h. pub fn next_scheduled_power_on_day_of_month(&self) -> Option { self.parts.get_field_byte(0x05) } /// Next scheduled power-on hour /// /// BCD value of the hour on which the next scheduled power-on /// is to occur, in the range 00h to 23h. pub fn next_scheduled_power_on_hour(&self) -> Option { self.parts.get_field_byte(0x06) } /// Next scheduled power-on minute /// /// BCD value of the minute on which the next scheduled /// power-on is to occur, in the range 00h to 59h. pub fn next_scheduled_power_on_minute(&self) -> Option { self.parts.get_field_byte(0x07) } /// Next scheduled power-on second /// /// BCD value of the second on which the next scheduled /// power-on is to occur, in the range 00h to 59h. pub fn next_scheduled_power_on_second(&self) -> Option { self.parts.get_field_byte(0x08) } } impl fmt::Debug for SMBiosSystemPowerControls<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field( "next_scheduled_power_on_month", &self.next_scheduled_power_on_month(), ) .field( "next_scheduled_power_on_day_of_month", &self.next_scheduled_power_on_day_of_month(), ) .field( "next_scheduled_power_on_hour", &self.next_scheduled_power_on_hour(), ) .field( "next_scheduled_power_on_minute", &self.next_scheduled_power_on_minute(), ) .field( "next_scheduled_power_on_second", &self.next_scheduled_power_on_second(), ) .finish() } } impl Serialize for SMBiosSystemPowerControls<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosSystemPowerControls", 6)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field( "next_scheduled_power_on_month", &self.next_scheduled_power_on_month(), )?; state.serialize_field( "next_scheduled_power_on_day_of_month", &self.next_scheduled_power_on_day_of_month(), )?; state.serialize_field( "next_scheduled_power_on_hour", &self.next_scheduled_power_on_hour(), )?; state.serialize_field( "next_scheduled_power_on_minute", &self.next_scheduled_power_on_minute(), )?; state.serialize_field( "next_scheduled_power_on_second", &self.next_scheduled_power_on_second(), )?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type25 = vec![ 0x19, 0x09, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type25); let test_struct = SMBiosSystemPowerControls::new(&parts); assert_eq!(test_struct.next_scheduled_power_on_month(), Some(0)); assert_eq!(test_struct.next_scheduled_power_on_day_of_month(), Some(0)); assert_eq!(test_struct.next_scheduled_power_on_hour(), Some(0)); assert_eq!(test_struct.next_scheduled_power_on_minute(), Some(0)); assert_eq!(test_struct.next_scheduled_power_on_second(), Some(0)); } } smbios-lib-0.9.2/src/structs/types/system_power_supply.rs000064400000000000000000000410711046102023000220630ustar 00000000000000use crate::core::{strings::*, Handle, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # System Power Supply (Type 39) /// /// This structure identifies attributes of a system power supply. Table 116 provides details. One instance of /// this structure is present for each possible power supply in a system. /// /// NOTE This structure type was added in version 2.3.1 of this specification. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosSystemPowerSupply<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosSystemPowerSupply<'a> { const STRUCT_TYPE: u8 = 39u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosSystemPowerSupply<'a> { /// Power unit group /// /// Power unit group to which this power supply is /// associated /// /// Specifying the same Power Unit Group value for more /// than one System Power Supply structure indicates a /// redundant power supply configuration. The field’s value is /// 00h if the power supply is not a member of a redundant /// power unit. Non-zero values imply redundancy and that /// at least one other power supply will be enumerated with /// the same value. pub fn power_unit_group(&self) -> Option { self.parts.get_field_byte(0x04) } /// Location /// /// Identifies the location of the power supply. /// /// EXAMPLES: "in the back, on the left-hand side" or /// "Left Supply Bay" pub fn location(&self) -> SMBiosString { self.parts.get_field_string(0x05) } /// Device name /// /// Number of the string that names the power supply device /// /// EXAMPLE: "DR-36" pub fn device_name(&self) -> SMBiosString { self.parts.get_field_string(0x06) } /// Manufacturer /// /// Names the company that manufactured the supply pub fn manufacturer(&self) -> SMBiosString { self.parts.get_field_string(0x07) } /// Serial number /// /// The serial number for the power supply pub fn serial_number(&self) -> SMBiosString { self.parts.get_field_string(0x08) } /// Asset tag number pub fn asset_tag_number(&self) -> SMBiosString { self.parts.get_field_string(0x09) } /// Model part number /// /// The OEM part order number pub fn model_part_number(&self) -> SMBiosString { self.parts.get_field_string(0x0A) } /// Revision level /// /// Power supply revision string /// /// EXAMPLE: "2.30" pub fn revision_level(&self) -> SMBiosString { self.parts.get_field_string(0x0B) } /// Max power capacity /// /// Maximum sustained power output in Watts /// /// Set to 0x8000 if unknown. Note that the units specified by /// the DMTF for this field are milliWatts. pub fn max_power_capacity(&self) -> Option { self.parts .get_field_word(0x0C) .map(|raw| MaxPowerCapacity::from(raw)) } /// Power supply characteristics pub fn power_supply_characteristics(&self) -> Option { self.parts .get_field_word(0x0E) .map(|raw| PowerSupplyCharacteristics::from(raw)) } /// Input voltage probe handle /// /// Handle, or instance number, of a [super::SMBiosVoltageProbe] (Type 26) /// monitoring this power supply's input voltage /// /// A value of 0xFFFF indicates that no probe is provided pub fn input_voltage_probe_handle(&self) -> Option { self.parts.get_field_handle(0x10) } /// Cooling device handle /// /// Handle, or instance number, of a [super::SMBiosCoolingDevice] (Type /// 27) associated with this power supply /// /// A value of 0xFFFF indicates that no cooling device is /// provided. pub fn cooling_device_handle(&self) -> Option { self.parts.get_field_handle(0x12) } /// Input current probe handle /// /// Handle, or instance number, of the [super::SMBiosElectricalCurrentProbe] /// (Type 29) monitoring this power supply’s input /// current /// /// A value of 0xFFFF indicates that no current probe is /// provided. pub fn input_current_probe_handle(&self) -> Option { self.parts.get_field_handle(0x14) } } impl fmt::Debug for SMBiosSystemPowerSupply<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("power_unit_group", &self.power_unit_group()) .field("location", &self.location()) .field("device_name", &self.device_name()) .field("manufacturer", &self.manufacturer()) .field("serial_number", &self.serial_number()) .field("asset_tag_number", &self.asset_tag_number()) .field("model_part_number", &self.model_part_number()) .field("revision_level", &self.revision_level()) .field("max_power_capacity", &self.max_power_capacity()) .field( "power_supply_characteristics", &self.power_supply_characteristics(), ) .field( "input_voltage_probe_handle", &self.input_voltage_probe_handle(), ) .field("cooling_device_handle", &self.cooling_device_handle()) .field( "input_current_probe_handle", &self.input_current_probe_handle(), ) .finish() } } impl Serialize for SMBiosSystemPowerSupply<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosSystemPowerSupply", 14)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("power_unit_group", &self.power_unit_group())?; state.serialize_field("location", &self.location())?; state.serialize_field("device_name", &self.device_name())?; state.serialize_field("manufacturer", &self.manufacturer())?; state.serialize_field("serial_number", &self.serial_number())?; state.serialize_field("asset_tag_number", &self.asset_tag_number())?; state.serialize_field("model_part_number", &self.model_part_number())?; state.serialize_field("revision_level", &self.revision_level())?; state.serialize_field("max_power_capacity", &self.max_power_capacity())?; state.serialize_field( "power_supply_characteristics", &self.power_supply_characteristics(), )?; state.serialize_field( "input_voltage_probe_handle", &self.input_voltage_probe_handle(), )?; state.serialize_field("cooling_device_handle", &self.cooling_device_handle())?; state.serialize_field( "input_current_probe_handle", &self.input_current_probe_handle(), )?; state.end() } } /// # Power Supply Characteristics #[derive(PartialEq, Eq)] pub struct PowerSupplyCharacteristics { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u16, } impl From for PowerSupplyCharacteristics { fn from(raw: u16) -> Self { PowerSupplyCharacteristics { raw } } } impl PowerSupplyCharacteristics { /// Power Supply Types pub fn power_supply_type(&self) -> PowerSupplyType { PowerSupplyType::from(self.raw) } /// Power Supply Status pub fn power_supply_status(&self) -> PowerSupplyStatus { PowerSupplyStatus::from(self.raw) } /// DMTF Input Voltage Range Switching pub fn input_voltage_range_switching(&self) -> InputVoltageRangeSwitching { InputVoltageRangeSwitching::from(self.raw) } /// Power supply is unplugged from the wall pub fn unplugged_from_wall(&self) -> bool { self.raw & 0b0000_0000_0000_0100 == 0b0000_0000_0000_0100 } /// Power supply is present pub fn is_present(&self) -> bool { self.raw & 0b0000_0000_0000_0010 == 0b0000_0000_0000_0010 } /// Power supply is hot-replaceable pub fn hot_replaceable(&self) -> bool { self.raw & 0b0000_0000_0000_0001 == 0b0000_0000_0000_0001 } } impl fmt::Debug for PowerSupplyCharacteristics { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("power_supply_type", &self.power_supply_type()) .field("power_supply_status", &self.power_supply_status()) .field( "input_voltage_range_switching", &self.input_voltage_range_switching(), ) .field("unplugged_from_wall", &self.unplugged_from_wall()) .field("is_present", &self.is_present()) .field("hot_replaceable", &self.hot_replaceable()) .finish() } } impl Serialize for PowerSupplyCharacteristics { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("PowerSupplyCharacteristics", 7)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("power_supply_type", &self.power_supply_type())?; state.serialize_field("power_supply_status", &self.power_supply_status())?; state.serialize_field( "input_voltage_range_switching", &self.input_voltage_range_switching(), )?; state.serialize_field("unplugged_from_wall", &self.unplugged_from_wall())?; state.serialize_field("is_present", &self.is_present())?; state.serialize_field("hot_replaceable", &self.hot_replaceable())?; state.end() } } /// # DMTF Power Supply Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum PowerSupplyType { /// Other Other, /// Unknown Unknown, /// Linear Linear, /// Switching Switching, /// Battery Battery, /// UPS Ups, /// Converter Converter, /// Regulator Regulator, /// A value unknown to this standard, check the raw value None, } impl From for PowerSupplyType { fn from(raw: u16) -> Self { match raw & 0b0011_1100_0000_0000 { 0b0000_0100_0000_0000 => PowerSupplyType::Other, 0b0000_1000_0000_0000 => PowerSupplyType::Unknown, 0b0000_1100_0000_0000 => PowerSupplyType::Linear, 0b0001_0000_0000_0000 => PowerSupplyType::Switching, 0b0001_0100_0000_0000 => PowerSupplyType::Battery, 0b0001_1000_0000_0000 => PowerSupplyType::Ups, 0b0001_1100_0000_0000 => PowerSupplyType::Converter, 0b0010_0000_0000_0000 => PowerSupplyType::Regulator, _ => PowerSupplyType::None, } } } /// # Power Supply Status #[derive(Serialize, Debug, PartialEq, Eq)] pub enum PowerSupplyStatus { /// Other Other, /// Unknown Unknown, /// OK OK, /// Non-critical NonCritical, /// Critical; power supply has failed and has been taken off-line. Critical, /// A value unknown to this standard, check the raw value None, } impl From for PowerSupplyStatus { fn from(raw: u16) -> Self { match raw & 0b0000_0011_1000_0000 { 0b0000_0000_1000_0000 => PowerSupplyStatus::Other, 0b0000_0001_0000_0000 => PowerSupplyStatus::Unknown, 0b0000_0001_1000_0000 => PowerSupplyStatus::OK, 0b0000_0010_0000_0000 => PowerSupplyStatus::NonCritical, 0b0000_0010_1000_0000 => PowerSupplyStatus::Critical, _ => PowerSupplyStatus::None, } } } /// # DMTF Input Voltage Range Switching #[derive(Serialize, Debug, PartialEq, Eq)] pub enum InputVoltageRangeSwitching { /// Other Other, /// Unknown Unknown, /// Manual, Manual, /// Auto-switch AutoSwitch, /// Wide range WideRange, /// Not applicable NotApplicable, /// A value unknown to this standard, check the raw value None, } impl From for InputVoltageRangeSwitching { fn from(raw: u16) -> Self { match raw & 0b0000_0000_0111_1000 { 0b0000_0000_0000_1000 => InputVoltageRangeSwitching::Other, 0b0000_0000_0001_0000 => InputVoltageRangeSwitching::Unknown, 0b0000_0000_0001_1000 => InputVoltageRangeSwitching::Manual, 0b0000_0000_0010_0000 => InputVoltageRangeSwitching::AutoSwitch, 0b0000_0000_0010_1000 => InputVoltageRangeSwitching::WideRange, 0b0000_0000_0011_0000 => InputVoltageRangeSwitching::NotApplicable, _ => InputVoltageRangeSwitching::None, } } } /// # Max Power Capacity /// /// Maximum sustained power output in Watts #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MaxPowerCapacity { /// Maximum sustained power output in Watts Watts(u16), /// Maximum sustained power output is unknown Unknown, } impl From for MaxPowerCapacity { fn from(raw: u16) -> Self { if raw == 0x8000 { MaxPowerCapacity::Unknown } else { MaxPowerCapacity::Watts(raw) } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type39 = vec![ 0x27, 0x16, 0x3A, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x80, 0xA2, 0x11, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00, b'T', b'o', b' ', b'B', b'e', b' ', b'F', b'i', b'l', b'l', b'e', b'd', b' ', b'B', b'y', b' ', b'O', b'.', b'E', b'.', b'M', b'.', 0x00, b'T', b'o', b' ', b'B', b'e', b' ', b'F', b'i', b'l', b'l', b'e', b'd', b' ', b'B', b'y', b' ', b'O', b'.', b'E', b'.', b'M', b'.', 0x00, b'T', b'o', b' ', b'B', b'e', b' ', b'F', b'i', b'l', b'l', b'e', b'd', b' ', b'B', b'y', b' ', b'O', b'.', b'E', b'.', b'M', b'.', 0x00, b'T', b'o', b' ', b'B', b'e', b' ', b'F', b'i', b'l', b'l', b'e', b'd', b' ', b'B', b'y', b' ', b'O', b'.', b'E', b'.', b'M', b'.', 0x00, b'T', b'o', b' ', b'B', b'e', b' ', b'F', b'i', b'l', b'l', b'e', b'd', b' ', b'B', b'y', b' ', b'O', b'.', b'E', b'.', b'M', b'.', 0x00, b'T', b'o', b' ', b'B', b'e', b' ', b'F', b'i', b'l', b'l', b'e', b'd', b' ', b'B', b'y', b' ', b'O', b'.', b'E', b'.', b'M', b'.', 0x00, b'T', b'o', b' ', b'B', b'e', b' ', b'F', b'i', b'l', b'l', b'e', b'd', b' ', b'B', b'y', b' ', b'O', b'.', b'E', b'.', b'M', b'.', 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type39); let test_struct = SMBiosSystemPowerSupply::new(&parts); println!("{:?}", test_struct); assert_eq!(test_struct.power_unit_group(), Some(1)); assert_eq!( test_struct.location().to_string(), "To Be Filled By O.E.M.".to_string() ); assert_eq!( test_struct.device_name().to_string(), "To Be Filled By O.E.M.".to_string() ); assert_eq!( test_struct.manufacturer().to_string(), "To Be Filled By O.E.M.".to_string() ); assert_eq!( test_struct.serial_number().to_string(), "To Be Filled By O.E.M.".to_string() ); assert_eq!( test_struct.asset_tag_number().to_string(), "To Be Filled By O.E.M.".to_string() ); assert_eq!( test_struct.model_part_number().to_string(), "To Be Filled By O.E.M.".to_string() ); assert_eq!( test_struct.revision_level().to_string(), "To Be Filled By O.E.M.".to_string() ); assert_eq!( test_struct.max_power_capacity(), Some(MaxPowerCapacity::Unknown) ); assert_eq!( test_struct.power_supply_characteristics(), Some(PowerSupplyCharacteristics::from(4514)) ); assert_eq!(*test_struct.input_voltage_probe_handle().unwrap(), 54); assert_eq!(*test_struct.cooling_device_handle().unwrap(), 56); assert_eq!(*test_struct.input_current_probe_handle().unwrap(), 57); } } smbios-lib-0.9.2/src/structs/types/system_reset.rs000064400000000000000000000244651046102023000204450ustar 00000000000000use crate::{SMBiosStruct, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # System Reset (Type 23) /// /// This structure describes whether Automatic System Reset functions are enabled (Status). /// /// If the system has a watchdog timer and the timer is not reset (Timer Reset) before the Interval elapses, /// an automatic system reset occurs. The system re-boots according to the Boot Option. This function may /// repeat until the Limit is reached, at which time the system re-boots according to the Boot Option at Limit. /// /// NOTE This structure type was added for version 2.2 of this specification. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134) /// Document Date: 2020-07-17 pub struct SMBiosSystemReset<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosSystemReset<'a> { const STRUCT_TYPE: u8 = 23u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosSystemReset<'a> { /// Capabilities bit-field /// /// Identifies the system-reset capabilities for the system pub fn capabilities(&self) -> Option { self.parts .get_field_byte(0x04) .map(|raw| SystemResetCapabilities::from(raw)) } /// Reset count /// /// Number of automatic system resets since the last intentional /// reset pub fn reset_count(&self) -> Option { self.parts .get_field_word(0x05) .map(|raw| ResetCount::from(raw)) } /// Reset limit /// /// Number of consecutive times the system reset is attempted pub fn reset_limit(&self) -> Option { self.parts .get_field_word(0x07) .map(|raw| ResetLimit::from(raw)) } /// Timer interval /// /// Number of minutes to use for the watchdog timer /// /// If the timer is not reset within this interval, the system reset /// timeout begins. pub fn timer_interval(&self) -> Option { self.parts .get_field_word(0x09) .map(|raw| TimerInterval::from(raw)) } /// Timeout /// /// Number of minutes before the reboot is initiated /// /// It is used after a system power cycle, system reset (local or /// remote), and automatic system reset. pub fn timeout(&self) -> Option { self.parts .get_field_word(0x0B) .map(|raw| Timeout::from(raw)) } } impl fmt::Debug for SMBiosSystemReset<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("capabilities", &self.capabilities()) .field("reset_count", &self.reset_count()) .field("reset_limit", &self.reset_limit()) .field("timer_interval", &self.timer_interval()) .field("timeout", &self.timeout()) .finish() } } impl Serialize for SMBiosSystemReset<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosSystemReset", 6)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("capabilities", &self.capabilities())?; state.serialize_field("reset_count", &self.reset_count())?; state.serialize_field("reset_limit", &self.reset_limit())?; state.serialize_field("timer_interval", &self.timer_interval())?; state.serialize_field("timeout", &self.timeout())?; state.end() } } /// # System Reset Capabilities #[derive(PartialEq, Eq)] pub struct SystemResetCapabilities { /// Raw byte of the system reset capabilities pub raw: u8, } impl From for SystemResetCapabilities { fn from(raw: u8) -> Self { SystemResetCapabilities { raw } } } impl SystemResetCapabilities { /// System contains a watchdog timer; either /// True (1) or False (0). pub fn has_watchdog_timer(&self) -> bool { self.raw & 0b0010_0000 == 0b0010_0000 } /// Boot Option on Limit /// /// Identifies one of the system actions /// to be taken when the Reset Limit is reached. pub fn boot_option_on_limit(&self) -> BootOptionOnLimit { BootOptionOnLimit::from(self.raw) } /// Boot Option /// /// Indicates one of the following actions /// to be taken after a watchdog reset: pub fn boot_option(&self) -> BootOption { BootOption::from(self.raw) } /// Status /// /// Identifies whether (1) or not (0) /// the system reset is enabled by the user. pub fn reset_enabled(&self) -> bool { self.raw & 0b0000_0001 == 0b0000_0001 } } impl fmt::Debug for SystemResetCapabilities { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("has_watchdog_timer", &self.has_watchdog_timer()) .field("boot_option_on_limit", &self.boot_option_on_limit()) .field("boot_option", &self.boot_option()) .field("reset_enabled", &self.reset_enabled()) .finish() } } impl Serialize for SystemResetCapabilities { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SystemResetCapabilities", 5)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("has_watchdog_timer", &self.has_watchdog_timer())?; state.serialize_field("boot_option_on_limit", &self.boot_option_on_limit())?; state.serialize_field("boot_option", &self.boot_option())?; state.serialize_field("reset_enabled", &self.reset_enabled())?; state.end() } } /// # Boot Option on Limit /// /// Identifies one of the following system actions to /// be taken when the Reset Limit is reached #[derive(Serialize, Debug, PartialEq, Eq)] pub enum BootOptionOnLimit { /// Reserved, do not use. Reserved, /// Operating System OperatingSystem, /// System utilities SystemUtilities, /// Do not reboot DoNotReboot, } impl From for BootOptionOnLimit { fn from(raw: u8) -> Self { match raw & 0b0001_1000 { 0b0000_0000 => BootOptionOnLimit::Reserved, 0b0000_1000 => BootOptionOnLimit::OperatingSystem, 0b0001_0000 => BootOptionOnLimit::SystemUtilities, 0b0001_1000 => BootOptionOnLimit::DoNotReboot, _ => panic!("impossible value"), } } } /// # Boot Option /// /// Indicates one of the following actions to be taken // after a watchdog reset #[derive(Serialize, Debug, PartialEq, Eq)] pub enum BootOption { /// Reserved, do not use. Reserved, /// Operating System OperatingSystem, /// System utilities SystemUtilities, /// Do not reboot DoNotReboot, } impl From for BootOption { fn from(raw: u8) -> Self { match raw & 0b0000_0110 { 0b0000_0000 => BootOption::Reserved, 0b0000_0010 => BootOption::OperatingSystem, 0b0000_0100 => BootOption::SystemUtilities, 0b0000_0110 => BootOption::DoNotReboot, _ => panic!("impossible value"), } } } /// # Reset Count #[derive(Serialize, Debug)] pub enum ResetCount { /// Number of automatic system resets since the last intentional reset Count(u16), /// Reset count is unknown. Unknown, } impl From for ResetCount { fn from(raw: u16) -> Self { match raw { 0xFFFF => ResetCount::Unknown, _ => ResetCount::Count(raw), } } } /// # Reset Limit #[derive(Serialize, Debug)] pub enum ResetLimit { /// Number of consecutive times the system reset is attempted Count(u16), /// Reset limit is unknown. Unknown, } impl From for ResetLimit { fn from(raw: u16) -> Self { match raw { 0xFFFF => ResetLimit::Unknown, _ => ResetLimit::Count(raw), } } } /// # Timer Interval #[derive(Serialize, Debug)] pub enum TimerInterval { /// Number of minutes to use for the watchdog timer /// /// If the timer is not reset within this interval, /// the system reset timeout begins. Minutes(u16), /// Timer interval is unknown. Unknown, } impl From for TimerInterval { fn from(raw: u16) -> Self { match raw { 0xFFFF => TimerInterval::Unknown, _ => TimerInterval::Minutes(raw), } } } /// # Timeout #[derive(Serialize, Debug)] pub enum Timeout { /// Number of minutes before the reboot is initiated /// /// It is used after a system power cycle, system reset // (local or remote), and automatic system reset. Minutes(u16), /// Timeout is unknown. Unknown, } impl From for Timeout { fn from(raw: u16) -> Self { match raw { 0xFFFF => Timeout::Unknown, _ => Timeout::Minutes(raw), } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type23 = vec![ 0x17, 0x0D, 0x4F, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type23); let test_struct = SMBiosSystemReset::new(&parts); assert_eq!( test_struct.capabilities(), Some(SystemResetCapabilities::from(0)) ); match test_struct.reset_count().unwrap() { ResetCount::Count(_) => panic!("expected unknown"), ResetCount::Unknown => (), } match test_struct.reset_limit().unwrap() { ResetLimit::Count(_) => panic!("expected unknown"), ResetLimit::Unknown => (), } match test_struct.timer_interval().unwrap() { TimerInterval::Minutes(_) => panic!("expected unknown"), TimerInterval::Unknown => (), } match test_struct.timeout().unwrap() { Timeout::Minutes(_) => panic!("expected unknown"), Timeout::Unknown => (), } } } smbios-lib-0.9.2/src/structs/types/system_slot.rs000064400000000000000000001333121046102023000202740ustar 00000000000000use crate::core::{strings::*, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer}; use std::{convert::TryInto, fmt, ops::Deref}; /// # System Slots (Type 9) /// /// The information in this structure defines the attributes of a system slot. One /// structure is provided for each slot in the system. /// /// Compliant with: /// DMTF SMBIOS Reference Specification 3.7.0 (DSP0134) /// Document Date: 2023-07-21 pub struct SMBiosSystemSlot<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosSystemSlot<'a> { const STRUCT_TYPE: u8 = 9u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosSystemSlot<'a> { /// Slot Designation pub fn slot_designation(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Slot Type pub fn system_slot_type(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| SystemSlotTypeData::from(raw)) } /// Slot Data Bus Width pub fn slot_data_bus_width(&self) -> Option { self.parts .get_field_byte(0x06) .map(|raw| SlotWidthData::from(raw)) } /// Current Usage pub fn current_usage(&self) -> Option { self.parts .get_field_byte(0x07) .map(|raw| SlotCurrentUsageData::from(raw)) } /// Slot Length pub fn slot_length(&self) -> Option { self.parts .get_field_byte(0x08) .map(|raw| SlotLengthData::from(raw)) } /// Slot Id pub fn slot_id(&self) -> Option { self.parts .get_field_data(0x09, 0x0B) .map(|id| SystemSlotId(id.try_into().unwrap())) } /// Slot Characteristics 1 pub fn slot_characteristics_1(&self) -> Option { self.parts .get_field_byte(0x0B) .map(|raw| SystemSlotCharacteristics1::from(raw)) } /// Slot Characteristics 2 pub fn slot_characteristics_2(&self) -> Option { self.parts .get_field_byte(0x0C) .map(|raw| SystemSlotCharacteristics2::from(raw)) } /// Segment Group Number (Base) pub fn segment_group_number(&self) -> Option { self.parts .get_field_word(0x0D) .map(|raw| SegmentGroupNumber::from(raw)) } /// Bus Number (Base) pub fn bus_number(&self) -> Option { self.parts .get_field_byte(0x0F) .map(|raw| BusNumber::from(raw)) } /// Device/Function Number (Base) pub fn device_function_number(&self) -> Option { self.parts .get_field_byte(0x10) .map(|raw| DeviceFunctionNumber::from(raw)) } /// Data Bus Width (Base) pub fn data_bus_width(&self) -> Option { self.parts.get_field_byte(0x11) } /// Number of peer Segment/Bus/Device/Function/Width groups that follow pub fn peer_group_count(&self) -> Option { self.parts .get_field_byte(0x12) .and_then(|count| Some(count as usize)) } /// 5*n fn peer_group_size(&self) -> Option { self.peer_group_count() .and_then(|count| Some(count as usize * SlotPeerGroup::SIZE)) } /// Iterates over the [SlotPeerGroup] entries pub fn peer_group_iterator(&'a self) -> SlotPeerGroupIterator<'a> { SlotPeerGroupIterator::new(self) } /// Slot Information pub fn slot_information(&self) -> Option { self.peer_group_size() .and_then(|size| self.parts.get_field_byte(size + 0x13)) } /// Slot Physical Width /// /// This field indicates the physical width of the slot whereas _slot_data_bus_width()_ indicates the /// electrical width of the slot. /// /// The possible values of both fields are listed in Table 46 – System Slots: Slot Width field. pub fn slot_physical_width(&self) -> Option { self.peer_group_size().and_then(|size| { self.parts .get_field_byte(size + 0x14) .map(|raw| SlotWidthData::from(raw)) }) } /// Slot Pitch /// /// The Slot Pitch field contains a numeric value that indicates the pitch of the slot in units of 1/100 millimeter. /// /// The pitch is defined by each slot/card specification, but typically describes add-in card to add-in card /// pitch. /// /// For EDSFF slots, the pitch is defined in SFF-TA-1006 table 7.1, SFF-TA-1007 table 7.1 (add-in card to /// add-in card pitch), and SFF-TA-1008 table 6-1 (SSD to SSD pitch). /// /// For example, if the pitch for the slot is 12.5 mm, the value 1250 would be used. /// /// A value of 0 implies that the slot pitch is not given or is unknown. pub fn slot_pitch(&self) -> Option { self.peer_group_size() .and_then(|size| self.parts.get_field_word(size + 0x15)) } /// Slot Height /// /// This field indicates the maximum supported card height for the slot. /// /// Available in version 3.5.0 and later. pub fn slot_height(&self) -> Option { self.peer_group_size().and_then(|size| { self.parts .get_field_byte(size + 0x17) .map(|raw| SlotHeightData::from(raw)) }) } } impl fmt::Debug for SMBiosSystemSlot<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("slot_designation", &self.slot_designation()) .field("system_slot_type", &self.system_slot_type()) .field("slot_data_bus_width", &self.slot_data_bus_width()) .field("current_usage", &self.current_usage()) .field("slot_length", &self.slot_length()) .field("slot_id", &self.slot_id()) .field("slot_characteristics_1", &self.slot_characteristics_1()) .field("slot_characteristics_2", &self.slot_characteristics_2()) .field("segment_group_number", &self.segment_group_number()) .field("bus_number", &self.bus_number()) .field("device_function_number", &self.device_function_number()) .field("data_bus_width", &self.data_bus_width()) .field("peer_group_count", &self.peer_group_count()) .field("peer_group_iterator", &self.peer_group_iterator()) .field("slot_information", &self.slot_information()) .field("slot_physical_width", &self.slot_physical_width()) .field("slot_pitch", &self.slot_pitch()) .finish() } } impl Serialize for SMBiosSystemSlot<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosSystemSlot", 18)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("slot_designation", &self.slot_designation())?; state.serialize_field("system_slot_type", &self.system_slot_type())?; state.serialize_field("slot_data_bus_width", &self.slot_data_bus_width())?; state.serialize_field("current_usage", &self.current_usage())?; state.serialize_field("slot_length", &self.slot_length())?; state.serialize_field("slot_id", &self.slot_id())?; state.serialize_field("slot_characteristics_1", &self.slot_characteristics_1())?; state.serialize_field("slot_characteristics_2", &self.slot_characteristics_2())?; state.serialize_field("segment_group_number", &self.segment_group_number())?; state.serialize_field("bus_number", &self.bus_number())?; state.serialize_field("device_function_number", &self.device_function_number())?; state.serialize_field("data_bus_width", &self.data_bus_width())?; state.serialize_field("peer_group_count", &self.peer_group_count())?; state.serialize_field("peer_group_iterator", &self.peer_group_iterator())?; state.serialize_field("slot_information", &self.slot_information())?; state.serialize_field("slot_physical_width", &self.slot_physical_width())?; state.serialize_field("slot_pitch", &self.slot_pitch())?; state.end() } } /// # System Slots - Slot Id /// /// The Slot ID field of the System Slot structure provides a mechanism to correlate the physical attributes of /// the slot to its logical access method (which varies based on the Slot Type field). The Slot ID field has /// meaning only for the slot types described in the table: /// /// | Slot Type | Slot ID Field Meaning | /// | --------- | --------------------- | /// | MCA | Identifies the logical Micro Channel slot number, in the range 1 to 15, in byte 0. Byte 1 is set to 0. | /// | PCI, AGP, PCIX, PCI Express | On a system that supports ACPI, identifies the value returned in the _SUN object for this slot. On a system that supports the PCI IRQ Routing Table Specification, identifies the value present in the Slot Number field of the PCI Interrupt Routing table entry that is associated with this slot, in byte 0 - byte 1 is set to 0. The table is returned by the "Get PCI Interrupt Routing Options" PCI BIOS function call and provided directly in the PCI IRQ Routing Table Specification ($PIRQ). Software can determine the PCI bus number and device associated with the slot by matching the "Slot ID" to an entry in the routing-table and ultimately determine what device is present in that slot. NOTE: This definition also applies to the 66 MHz-capable PCI slots. | /// | PCMCIA | Identifies the Adapter Number (byte 0) and Socket Number (byte 1) to be passed toPCMCIA Socket Services to identify this slot | #[derive(Serialize, Debug, PartialEq, Eq, Clone, Copy)] pub struct SystemSlotId(pub [u8; 2]); impl Deref for SystemSlotId { type Target = [u8; 2]; fn deref(&self) -> &Self::Target { &self.0 } } impl SystemSlotId { /// The first system slot Id byte (found at offset 09h). pub fn byte_0(&self) -> u8 { self.0[0] } /// The second system slot Id byte (found at offset 0Ah). pub fn byte_1(&self) -> u8 { self.0[1] } } /// # System Slot Type Data pub struct SystemSlotTypeData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [SystemSlotType] value pub value: SystemSlotType, } impl Deref for SystemSlotTypeData { type Target = SystemSlotType; fn deref(&self) -> &Self::Target { &self.value } } impl From for SystemSlotTypeData { /// System Slot Type fn from(raw: u8) -> Self { use M2SlotType::*; use MXMSlotType::*; use PciExpressGeneration::*; use PciExpressSlotWidth::*; use SystemSlotType::*; SystemSlotTypeData { value: match raw { 0x01 => Other, 0x02 => Unknown, 0x03 => Isa, 0x04 => Mca, 0x05 => Eisa, 0x06 => Pci, 0x07 => Pcmcia, 0x08 => VlVesa, 0x09 => Proprietary, 0x0A => ProcessorCardSlot, 0x0B => ProprietaryMemoryCardSlot, 0x0C => IORiserCardSlot, 0x0D => NuBus, 0x0E => Pci66MhzCapable, 0x0F => Agp(AgpSlotWidth::X1), 0x10 => Agp(AgpSlotWidth::X2), 0x11 => Agp(AgpSlotWidth::X4), 0x12 => PciX, 0x13 => Agp(AgpSlotWidth::X8), 0x14 => M2(M2Socket1DP), 0x15 => M2(M2Socket1SD), 0x16 => M2(M2Socket2), 0x17 => M2(M2Socket3), 0x18 => Mxm(MxmTypeI), 0x19 => Mxm(MxmTypeII), 0x1A => Mxm(MxmTypeIIIStandard), 0x1B => Mxm(MxmTypeIIIHE), 0x1C => Mxm(MxmTypeIV), 0x1D => Mxm(Mxm3TypeA), 0x1E => Mxm(Mxm3TypeB), 0x1F => PciExpress(PCIExpressGen2, Sff8639), 0x20 => PciExpress(PCIExpressGen3, Sff8639), 0x21 => PciExpress(Undefined, PciExpressMini52WithKeepouts), 0x22 => PciExpress(Undefined, PciExpressMini52WithoutKeepouts), 0x23 => PciExpress(Undefined, PciExpressMini76), 0x24 => PciExpress(PCIExpressGen4, Sff8639), 0x25 => PciExpress(PCIExpressGen5, Sff8639), 0x26 => OcpNic30SmallFormFactor, 0x27 => OcpNic30LargeFormFactor, 0x28 => OcpNicPriorTo30, 0x30 => CxlFlexbus1, 0xA0 => PC98C20, 0xA1 => PC98C24, 0xA2 => PC98E, 0xA3 => PC98LocalBus, 0xA4 => PC98Card, 0xA5 => PciExpress(PCIExpressGen1, UndefinedSlotWidth), 0xA6 => PciExpress(PCIExpressGen1, X1), 0xA7 => PciExpress(PCIExpressGen1, X2), 0xA8 => PciExpress(PCIExpressGen1, X4), 0xA9 => PciExpress(PCIExpressGen1, X8), 0xAA => PciExpress(PCIExpressGen1, X16), 0xAB => PciExpress(PCIExpressGen2, UndefinedSlotWidth), 0xAC => PciExpress(PCIExpressGen2, X1), 0xAD => PciExpress(PCIExpressGen2, X2), 0xAE => PciExpress(PCIExpressGen2, X4), 0xAF => PciExpress(PCIExpressGen2, X8), 0xB0 => PciExpress(PCIExpressGen2, X16), 0xB1 => PciExpress(PCIExpressGen3, UndefinedSlotWidth), 0xB2 => PciExpress(PCIExpressGen3, X1), 0xB3 => PciExpress(PCIExpressGen3, X2), 0xB4 => PciExpress(PCIExpressGen3, X4), 0xB5 => PciExpress(PCIExpressGen3, X8), 0xB6 => PciExpress(PCIExpressGen3, X16), 0xB8 => PciExpress(PCIExpressGen4, UndefinedSlotWidth), 0xB9 => PciExpress(PCIExpressGen4, X1), 0xBA => PciExpress(PCIExpressGen4, X2), 0xBB => PciExpress(PCIExpressGen4, X4), 0xBC => PciExpress(PCIExpressGen4, X8), 0xBD => PciExpress(PCIExpressGen4, X16), 0xBE => PciExpress(PCIExpressGen5, UndefinedSlotWidth), 0xBF => PciExpress(PCIExpressGen5, X1), 0xC0 => PciExpress(PCIExpressGen5, X2), 0xC1 => PciExpress(PCIExpressGen5, X4), 0xC2 => PciExpress(PCIExpressGen5, X8), 0xC3 => PciExpress(PCIExpressGen5, X16), 0xC4 => PciExpress(PCIExpressGen6, UndefinedSlotWidth), 0xC5 => EnterpriseAndDataCenter1UE1, 0xC6 => EnterpriseAndDataCenter3InE3, _ => None, }, raw, } } } impl fmt::Debug for SystemSlotTypeData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for SystemSlotTypeData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SystemSlotTypeData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } impl fmt::Display for SystemSlotTypeData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.value { SystemSlotType::None => write!(f, "{}", &self.raw), _ => write!(f, "{:?}", &self.value), } } } /// # System Slot Type #[derive(Serialize, Debug, PartialEq, Eq)] pub enum SystemSlotType { /// Other Other, /// Unknown Unknown, /// ISA Isa, /// MCA Mca, /// EISA Eisa, /// PCI Pci, /// PC Card (PCMCIA) Pcmcia, /// VL-VESA VlVesa, /// Proprietary Proprietary, /// Processor Card Slot ProcessorCardSlot, /// Proprietary Memory Card Slot ProprietaryMemoryCardSlot, /// I/O Riser Card Slot IORiserCardSlot, /// NuBus NuBus, /// PCI – 66MHz Capable Pci66MhzCapable, /// AGP Agp(AgpSlotWidth), /// MXM Mxm(MXMSlotType), /// PCI-X PciX, /// M.2 M2(M2SlotType), /// OCP NIC 3.0 Small Form Factor (SFF) OcpNic30SmallFormFactor, /// OCP NIC 3.0 Large Form Factor (LFF) OcpNic30LargeFormFactor, /// OCP NIC Prior to 3.0 OcpNicPriorTo30, /// CXL Flexbus 1.0 (deprecated, see note below) CxlFlexbus1, /// PC-98/C20 PC98C20, /// PC-98/C24 PC98C24, /// PC-98/E PC98E, /// PC-98/Local Bus PC98LocalBus, /// PC-98/Card PC98Card, /// PCI Express PciExpress(PciExpressGeneration, PciExpressSlotWidth), /// Enterprise and Datacenter 1U E1 Form Factor Slot (EDSFF E1.S, E1.L) E1 slot length is reported in Slot Length field (see section 7.10.4). E1 slot pitch is reported in Slot Pitch field (see section 7.10.12). See specifications SFF-TA-1006 and SFF-TA-1007 for more details on values for slot length and pitch. EnterpriseAndDataCenter1UE1, /// Enterprise and Datacenter 3" E3 Form Factor Slot (EDSFF E3.S, E3.L) E3 slot length is reported in Slot Length field (see section 7.10.4). E3 slot pitch is reported in Slot Pitch field (see section 7.10.12). See specification SFF-TA-1008 for details on values for slot length and pitch. EnterpriseAndDataCenter3InE3, /// A value unknown to this standard, check the raw value None, } /// The generation of PciExpress used by the slot. #[derive(Serialize, Debug, PartialEq, Eq)] pub enum PciExpressGeneration { /// PCI Express Gen 1 PCIExpressGen1, /// PCI Express Gen 2 PCIExpressGen2, /// PCI Express Gen 3 PCIExpressGen3, /// PCI Express Gen 4 PCIExpressGen4, /// PCI Express Gen 5 PCIExpressGen5, /// PCI Express Gen 6 and Beyond PCIExpressGen6, /// Undefined Undefined, } /// The slot width of a PCI Express slot specified in the SystemSlotType #[derive(Serialize, Debug, PartialEq, Eq)] pub enum PciExpressSlotWidth { /// An undefined slot width UndefinedSlotWidth, /// X1 X1, /// X2 X2, /// X4 X4, /// X8 X8, /// X16 X16, /// Small form factor 639 Sff8639, /// PCI Express Mini 52-pin (CEM spec. 2.0) with bottom-side keep-outs. Use Slot Length field value 03h (short length) for "half-Mini card" -only support, 04h (long length) for "full-Mini card" or dual support. PciExpressMini52WithKeepouts, /// PCI Express Mini 52-pin (CEM spec. 2.0) without bottom-side keep-outs. Use Slot Length field value 03h (short length) for "half-Mini card" -only support, 04h (long length) for "full-Mini card" or dual support. PciExpressMini52WithoutKeepouts, /// PCI Express Mini 76-pin (CEM spec. 2.0) Corresponds to Display-Mini card. PciExpressMini76, } /// The slot width of an AGP slot specified in the SystemSlotType #[derive(Serialize, Debug, PartialEq, Eq)] pub enum AgpSlotWidth { /// X1 X1, /// X2 X2, /// X4 X4, /// X8 X8, } /// An MXM SlotType #[derive(Serialize, Debug, PartialEq, Eq)] pub enum MXMSlotType { /// MXM Type I MxmTypeI, /// MXM Type II MxmTypeII, /// MXM Type III (standard connector) MxmTypeIIIStandard, /// MXM Type III (HE connector) MxmTypeIIIHE, /// MXM Type IV MxmTypeIV, /// MXM 3.0 Type A Mxm3TypeA, /// MXM 3.0 Type B Mxm3TypeB, } /// An M.2 SlotType #[derive(Serialize, Debug, PartialEq, Eq)] pub enum M2SlotType { /// M.2 Socket 1-DP (Mechanical Key A) M2Socket1DP, /// M.2 Socket 1-SD (Mechanical Key E) M2Socket1SD, /// M.2 Socket 2 (Mechanical Key B) M2Socket2, /// M.2 Socket 3 (Mechanical Key M) M2Socket3, } /// # Data Bus Width Data pub struct SlotWidthData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [SlotWidth] value pub value: SlotWidth, } impl Deref for SlotWidthData { type Target = SlotWidth; fn deref(&self) -> &Self::Target { &self.value } } impl From for SlotWidthData { fn from(raw: u8) -> Self { SlotWidthData { value: match raw { 0x01 => SlotWidth::Other, 0x02 => SlotWidth::Unknown, 0x03 => SlotWidth::Bit8, 0x04 => SlotWidth::Bit16, 0x05 => SlotWidth::Bit32, 0x06 => SlotWidth::Bit64, 0x07 => SlotWidth::Bit128, 0x08 => SlotWidth::X1, 0x09 => SlotWidth::X2, 0x0A => SlotWidth::X4, 0x0B => SlotWidth::X8, 0x0C => SlotWidth::X12, 0x0D => SlotWidth::X16, 0x0E => SlotWidth::X32, _ => SlotWidth::None, }, raw, } } } impl fmt::Debug for SlotWidthData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for SlotWidthData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SlotWidthData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } /// # Slot Width #[derive(Serialize, Debug, PartialEq, Eq)] pub enum SlotWidth { /// Other Other, /// Unknown Unknown, /// 8 bit Bit8, /// 16 bit Bit16, /// 32 bit Bit32, /// 64 bit Bit64, /// 128 bit Bit128, /// 1x or x1 X1, /// 2x or x2 X2, /// 4x or x4 X4, /// 8x or x8 X8, /// 12x or x12 X12, /// 16x or x16 X16, /// 32x or x32 X32, /// A value unknown to this standard, check the raw value None, } /// # Slot Height Data pub struct SlotHeightData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [SlotHeight] value pub value: SlotHeight, } impl Deref for SlotHeightData { type Target = SlotHeight; fn deref(&self) -> &Self::Target { &self.value } } impl From for SlotHeightData { fn from(raw: u8) -> Self { SlotHeightData { value: match raw { 0x00 => SlotHeight::NotApplicable, 0x01 => SlotHeight::Other, 0x02 => SlotHeight::Unknown, 0x03 => SlotHeight::FullHeight, 0x04 => SlotHeight::LowProfile, _ => SlotHeight::None, }, raw, } } } impl fmt::Debug for SlotHeightData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for SlotHeightData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SlotHeightData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } /// # Slot Height #[derive(Serialize, Debug, PartialEq, Eq)] pub enum SlotHeight { /// Not Applicable NotApplicable, /// Other Other, /// Unknown Unknown, /// Full Height FullHeight, /// Low-profile LowProfile, /// A value unknown to this standard, check the raw value None, } /// # System Slot Current Usage Data pub struct SlotCurrentUsageData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [SlotCurrentUsage] value pub value: SlotCurrentUsage, } impl Deref for SlotCurrentUsageData { type Target = SlotCurrentUsage; fn deref(&self) -> &Self::Target { &self.value } } impl From for SlotCurrentUsageData { fn from(raw: u8) -> Self { SlotCurrentUsageData { value: match raw { 0x01 => SlotCurrentUsage::Other, 0x02 => SlotCurrentUsage::Unknown, 0x03 => SlotCurrentUsage::Available, 0x04 => SlotCurrentUsage::InUse, 0x05 => SlotCurrentUsage::Unavailable, _ => SlotCurrentUsage::None, }, raw, } } } impl fmt::Debug for SlotCurrentUsageData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for SlotCurrentUsageData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SlotCurrentUsageData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } /// # System Slot Current Usage #[derive(Serialize, Debug, PartialEq, Eq)] pub enum SlotCurrentUsage { /// Other Other, /// Unknown Unknown, /// Available Available, /// In use InUse, /// Unavailable Unavailable, /// A value unknown to this standard, check the raw value None, } /// # System Slot Current Usage Data pub struct SlotLengthData { /// Raw value /// /// _raw_ is most useful when _value_ is None. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, /// The contained [SlotLength] value pub value: SlotLength, } impl Deref for SlotLengthData { type Target = SlotLength; fn deref(&self) -> &Self::Target { &self.value } } impl From for SlotLengthData { fn from(raw: u8) -> Self { use SlotLength::*; SlotLengthData { value: match raw { 0x01 => Other, 0x02 => Unknown, 0x03 => ShortLength, 0x04 => LongLength, 0x05 => DriveFormFactor25, 0x06 => DriveFormFactor35, _ => None, }, raw, } } } impl fmt::Debug for SlotLengthData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("value", &self.value) .finish() } } impl Serialize for SlotLengthData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SlotLengthData", 2)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("value", &self.value)?; state.end() } } /// # System Slot Length #[derive(Serialize, Debug, PartialEq, Eq)] pub enum SlotLength { /// Other Other, /// Unknown Unknown, /// Short Length ShortLength, /// Long Length LongLength, /// 2.5" drive form factor DriveFormFactor25, /// 3.5" drive form factor DriveFormFactor35, /// A value unknown to this standard, check the raw value None, } /// # System Slot Characteristics 1 #[derive(PartialEq, Eq)] pub struct SystemSlotCharacteristics1 { /// Raw value /// /// _raw_ is useful for masked comparisons. pub raw: u8, } impl Deref for SystemSlotCharacteristics1 { type Target = u8; fn deref(&self) -> &Self::Target { &self.raw } } impl From for SystemSlotCharacteristics1 { fn from(raw: u8) -> Self { SystemSlotCharacteristics1 { raw } } } impl SystemSlotCharacteristics1 { /// Characteristics unknown. pub fn unknown(&self) -> bool { self.raw & 0x01 == 0x01 } /// Provides 5.0 volts. pub fn provides5_volts(&self) -> bool { self.raw & 0x02 == 0x02 } /// Provides 3.3 volts. pub fn provides33_volts(&self) -> bool { self.raw & 0x04 == 0x04 } /// Slot’s opening is shared with another slot (for example, PCI/EISA shared slot). pub fn shared(&self) -> bool { self.raw & 0x08 == 0x08 } /// PC Card slot supports PC Card-16. pub fn supports_pc_card16(&self) -> bool { self.raw & 0x10 == 0x10 } /// PC Card slot supports CardBus. pub fn supports_card_bus(&self) -> bool { self.raw & 0x20 == 0x20 } /// PC Card slot supports Zoom Video. pub fn supports_zoom_video(&self) -> bool { self.raw & 0x40 == 0x40 } /// PC Card slot supports Modem Ring Resume. pub fn supports_modem_ring_resume(&self) -> bool { self.raw & 0x80 == 0x80 } } impl fmt::Debug for SystemSlotCharacteristics1 { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("unknown", &self.unknown()) .field("provides5_volts", &self.provides5_volts()) .field("provides33_volts", &self.provides33_volts()) .field("shared", &self.shared()) .field("supports_pc_card16", &self.supports_pc_card16()) .field("supports_card_bus", &self.supports_card_bus()) .field("supports_zoom_video", &self.supports_zoom_video()) .field( "supports_modem_ring_resume", &self.supports_modem_ring_resume(), ) .finish() } } impl Serialize for SystemSlotCharacteristics1 { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SystemSlotCharacteristics1", 9)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("unknown", &self.unknown())?; state.serialize_field("provides5_volts", &self.provides5_volts())?; state.serialize_field("provides33_volts", &self.provides33_volts())?; state.serialize_field("shared", &self.shared())?; state.serialize_field("supports_pc_card16", &self.supports_pc_card16())?; state.serialize_field("supports_card_bus", &self.supports_card_bus())?; state.serialize_field("supports_zoom_video", &self.supports_zoom_video())?; state.serialize_field( "supports_modem_ring_resume", &self.supports_modem_ring_resume(), )?; state.end() } } /// # System Slot Characteristics 2 #[derive(PartialEq, Eq)] pub struct SystemSlotCharacteristics2 { /// Raw value /// /// _raw_ is useful when there are values not yet defiend. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u8, } impl Deref for SystemSlotCharacteristics2 { type Target = u8; fn deref(&self) -> &Self::Target { &self.raw } } impl From for SystemSlotCharacteristics2 { fn from(raw: u8) -> Self { SystemSlotCharacteristics2 { raw } } } impl SystemSlotCharacteristics2 { /// PCI slot supports Power Management Event (PME#) signal. pub fn supports_power_management_event(&self) -> bool { self.raw & 0x01 == 0x01 } /// Slot supports hot-plug devices. pub fn supports_hot_plug_devices(&self) -> bool { self.raw & 0x02 == 0x02 } /// PCI slot supports SMBus signal. pub fn supports_smbus_signal(&self) -> bool { self.raw & 0x04 == 0x04 } /// PCIe slot supports bifurcation. /// /// This slot can partition its lanes into two or more PCIe devices plugged into the slot. /// Note: This field does not indicate complete details on what levels of bifurcation /// are supported by the slot, but only that the slot supports some level of bifurcation. pub fn supports_bifurcation(&self) -> bool { self.raw & 0x08 == 0x08 } /// Slot supports async/surprise removal. /// /// i.e., removal without prior notification to the operating system, device driver, or applications. pub fn supports_suprise_removal(&self) -> bool { self.raw & 0x10 == 0x10 } /// Flexbus slot, CXL 1.0 capable. pub fn flexbus_slot_cxl10_capable(&self) -> bool { self.raw & 0x20 == 0x20 } /// Flexbus slot, CXL 2.0 capable. pub fn flexbus_slot_cxl20_capable(&self) -> bool { self.raw & 0x40 == 0x40 } /// Flexbus slot, CXL 3.0 capable pub fn flexbus_slot_cxl30_capable(&self) -> bool { self.raw & 0x80 == 0x80 } } impl fmt::Debug for SystemSlotCharacteristics2 { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field( "supports_power_management_event", &self.supports_power_management_event(), ) .field( "supports_hot_plug_devices", &self.supports_hot_plug_devices(), ) .field("supports_smbus_signal", &self.supports_smbus_signal()) .field("supports_bifurcation", &self.supports_bifurcation()) .field("supports_suprise_removal", &self.supports_suprise_removal()) .field( "flexbus_slot_cxl10_capable", &self.flexbus_slot_cxl10_capable(), ) .field( "flexbus_slot_cxl20_capable", &self.flexbus_slot_cxl20_capable(), ) .field( "flexbus_slot_cxl30_capable", &self.flexbus_slot_cxl30_capable(), ) .finish() } } impl Serialize for SystemSlotCharacteristics2 { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SystemSlotCharacteristics2", 8)?; state.serialize_field("raw", &self.raw)?; state.serialize_field( "supports_power_management_event", &self.supports_power_management_event(), )?; state.serialize_field( "supports_hot_plug_devices", &self.supports_hot_plug_devices(), )?; state.serialize_field("supports_smbus_signal", &self.supports_smbus_signal())?; state.serialize_field("supports_bifurcation", &self.supports_bifurcation())?; state.serialize_field("supports_suprise_removal", &self.supports_suprise_removal())?; state.serialize_field( "flexbus_slot_cxl10_capable", &self.flexbus_slot_cxl10_capable(), )?; state.serialize_field( "flexbus_slot_cxl20_capable", &self.flexbus_slot_cxl20_capable(), )?; state.serialize_field( "flexbus_slot_cxl30_capable", &self.flexbus_slot_cxl30_capable(), )?; state.end() } } /// # Segment Group Number #[derive(Serialize, Debug, PartialEq, Eq)] pub enum SegmentGroupNumber { /// Single-Segment Topology (no group number) SingleSegment, /// Segment Group Number Number(u16), /// For devices that are not of types PCI, AGP, PCI-X, or PCI-Express /// and that do not have bus/device/function information. NotApplicable, } impl From for SegmentGroupNumber { fn from(raw: u16) -> Self { match raw { 0x00 => SegmentGroupNumber::SingleSegment, 0xFF => SegmentGroupNumber::NotApplicable, _ => SegmentGroupNumber::Number(raw), } } } /// # Bus Number #[derive(Serialize, Debug, PartialEq, Eq)] pub enum BusNumber { /// Bus Number Number(u8), /// For devices that are not of types PCI, AGP, PCI-X, or PCI-Express /// and that do not have bus/device/function information. NotApplicable, } impl From for BusNumber { fn from(raw: u8) -> Self { match raw { 0xFF => BusNumber::NotApplicable, _ => BusNumber::Number(raw), } } } /// # Device/Function Number #[derive(Serialize, Debug, PartialEq, Eq)] pub enum DeviceFunctionNumber { /// Device/Function Number Number { ///Bits 7:3 – Device number device: u8, /// Bits 2:0 – Function number function: u8, }, /// For devices that are not of types PCI, AGP, PCI-X, or PCI-Express /// and that do not have bus/device/function information. NotApplicable, } impl From for DeviceFunctionNumber { fn from(raw: u8) -> Self { match raw { 0xFF => DeviceFunctionNumber::NotApplicable, _ => DeviceFunctionNumber::Number { device: (raw & 0b11111000) >> 3, function: raw & 0b00000111, }, } } } /// # Slot Peer Group entry within [SMBiosSystemSlot] pub struct SlotPeerGroup<'a> { system_slot: &'a SMBiosSystemSlot<'a>, entry_offset: usize, } impl<'a> SlotPeerGroup<'a> { /// Size in bytes for this structure const SIZE: usize = 5; const SEGMENT_GROUP_NUMBER_OFFSET: usize = 0; const BUS_NUMBER_OFFSET: usize = 2; const DEVICE_FUNCTION_NUMBER_OFFSET: usize = 3; const DATA_BUS_WIDTH_OFFSET: usize = 4; fn new(system_slot: &'a SMBiosSystemSlot<'a>, entry_offset: usize) -> Self { Self { system_slot, entry_offset, } } /// Segment Group Number (Peer) pub fn segment_group_number(&self) -> Option { self.system_slot .parts() .get_field_word(self.entry_offset + Self::SEGMENT_GROUP_NUMBER_OFFSET) } /// Bus Number (Peer) pub fn bus_number(&self) -> Option { self.system_slot .parts() .get_field_byte(self.entry_offset + Self::BUS_NUMBER_OFFSET) } /// Device/Function Number (Peer) pub fn device_function_number(&self) -> Option { self.system_slot .parts() .get_field_byte(self.entry_offset + Self::DEVICE_FUNCTION_NUMBER_OFFSET) } /// Data bus width (Peer) /// /// Indicates electrical bus width of peer Segment/Bus/Device/Function. pub fn data_bus_width(&self) -> Option { self.system_slot .parts() .get_field_byte(self.entry_offset + Self::DATA_BUS_WIDTH_OFFSET) } } impl fmt::Debug for SlotPeerGroup<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("segment_group_number", &self.segment_group_number()) .field("bus_number", &self.bus_number()) .field("device_function_number", &self.device_function_number()) .field("data_bus_width", &self.data_bus_width()) .finish() } } impl Serialize for SlotPeerGroup<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SlotPeerGroup", 4)?; state.serialize_field("segment_group_number", &self.segment_group_number())?; state.serialize_field("bus_number", &self.bus_number())?; state.serialize_field("device_function_number", &self.device_function_number())?; state.serialize_field("data_bus_width", &self.data_bus_width())?; state.end() } } /// # On-board Device Itereator for [SlotPeerGroup]s contained within [SMBiosSystemSlot] pub struct SlotPeerGroupIterator<'a> { data: &'a SMBiosSystemSlot<'a>, current_index: usize, current_entry: usize, number_of_entries: usize, } impl<'a> SlotPeerGroupIterator<'a> { const PEER_GROUPS_OFFSET: usize = 0x13; fn new(data: &'a SMBiosSystemSlot<'a>) -> Self { SlotPeerGroupIterator { data: data, current_index: Self::PEER_GROUPS_OFFSET, current_entry: 0, number_of_entries: data.peer_group_count().unwrap_or(0), } } fn reset(&mut self) { self.current_index = Self::PEER_GROUPS_OFFSET; self.current_entry = 0; } } impl<'a> IntoIterator for &'a SlotPeerGroupIterator<'a> { type Item = SlotPeerGroup<'a>; type IntoIter = SlotPeerGroupIterator<'a>; fn into_iter(self) -> Self::IntoIter { SlotPeerGroupIterator { data: self.data, current_index: SlotPeerGroupIterator::PEER_GROUPS_OFFSET, current_entry: 0, number_of_entries: self.data.peer_group_count().unwrap_or(0), } } } impl<'a> Iterator for SlotPeerGroupIterator<'a> { type Item = SlotPeerGroup<'a>; fn next(&mut self) -> Option { if self.current_entry == self.number_of_entries { self.reset(); return None; } let next_index = self.current_index + SlotPeerGroup::SIZE; match self .data .parts() .get_field_data(self.current_index, next_index) { Some(_) => { let result = SlotPeerGroup::new(self.data, self.current_index); self.current_index = next_index; self.current_entry += 1; Some(result) } None => { self.reset(); None } } } } impl<'a> fmt::Debug for SlotPeerGroupIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().entries(self.into_iter()).finish() } } impl<'a> Serialize for SlotPeerGroupIterator<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let groups: Vec> = self.into_iter().collect(); let mut seq = serializer.serialize_seq(Some(groups.len()))?; for e in groups { seq.serialize_element(&e)?; } seq.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { // System Slot structure lengths and their versions: // 0Ch for version 2.0 implementations // 0Dh for versions 2.1 to 2.5 // 11h for versions 2.6 to 3.1.1 // Minimum of 11h for version 3.2 and later. // 2.6 to 3.1.1 System Slot structure (0x11 length, it does not include _data_bus_width()_ and beyond) let struct_type9 = vec![ 0x09, 0x11, 0x1C, 0x00, 0x01, 0xA5, 0x0D, 0x04, 0x04, 0x05, 0x07, 0x0C, 0x01, 0x00, 0x00, 0x00, 0x08, 0x4A, 0x36, 0x42, 0x32, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type9); let test_struct = SMBiosSystemSlot::new(&parts); assert_eq!( test_struct.slot_designation().to_string(), "J6B2".to_string() ); assert_eq!( *test_struct.system_slot_type().unwrap(), SystemSlotType::PciExpress( PciExpressGeneration::PCIExpressGen1, PciExpressSlotWidth::UndefinedSlotWidth, ) ); assert_eq!(*test_struct.slot_data_bus_width().unwrap(), SlotWidth::X16); let slot_id = test_struct.slot_id().unwrap(); assert_eq!(slot_id.byte_0(), 5); assert_eq!(slot_id.byte_1(), 7); // 2.6 to 3.1.1 has no data_bus_width() field or beyond fields assert!(test_struct.data_bus_width().is_none()); // 3.4 System Slot structure let struct_type9 = vec![ 0x09, 0x1C, 0x1C, 0x00, 0x01, 0xA5, 0x0D, 0x04, 0x04, 0x00, 0x00, 0x0C, 0x01, 0x00, 0x00, 0x00, 0x08, 0x99, 0x01, 0x23, 0x01, 0x04, 0x05, 0x06, 0x07, 0x08, 0xAB, 0x09, 0x4A, 0x36, 0x42, 0x32, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type9); let test_struct = SMBiosSystemSlot::new(&parts); // 3.2 fields assert_eq!(test_struct.data_bus_width(), Some(0x99)); assert_eq!(test_struct.peer_group_count(), Some(0x01)); let mut iterator = test_struct.peer_group_iterator().into_iter(); let first = iterator.next().unwrap(); assert_eq!(first.segment_group_number(), Some(0x0123)); assert_eq!(first.bus_number(), Some(0x04)); assert_eq!(first.device_function_number(), Some(0x05)); assert_eq!(first.data_bus_width(), Some(0x06)); // 3.4 fields // TODO: // Note: There will be an erratum published for these fields. For this test case // the field offsets have been shifted back by 1 from 0x14, 0x15, 0x16 (+ 5 * n), to 0x13... assert_eq!(test_struct.slot_information(), Some(0x07)); assert_eq!(*test_struct.slot_physical_width().unwrap(), SlotWidth::X1); assert_eq!(test_struct.slot_pitch(), Some(0x09AB)); println!("{:?}", test_struct); } } smbios-lib-0.9.2/src/structs/types/temperature_probe.rs000064400000000000000000000315261046102023000214370ustar 00000000000000use crate::core::{strings::*, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Temperature Probe (Type 28) /// /// This structure describes the attributes for a temperature probe in the system. Each structure describes a /// single temperature probe. /// /// NOTE This structure type was added in version 2.2 of this specification. pub struct SMBiosTemperatureProbe<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosTemperatureProbe<'a> { const STRUCT_TYPE: u8 = 28u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosTemperatureProbe<'a> { /// Description /// /// additional descriptive information about the probe or its location pub fn description(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Location and status /// /// Probe’s physical location and the status of the temperature /// monitored by this temperature probe pub fn location_and_status(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| TemperatureProbeLocationAndStatus::from(raw)) } /// Maximum value /// /// Maximum temperature readable by this probe, in 1/10th degrees C /// /// If the value is unknown, the field is set to 0x8000. pub fn maximum_value(&self) -> Option { self.parts .get_field_word(0x06) .map(|raw| ProbeTemperature::from(raw)) } /// Minimum value /// /// Minimum temperature readable by this probe, in 1/10th degrees C /// /// If the value is unknown, the field is set to 0x8000. pub fn minimum_value(&self) -> Option { self.parts .get_field_word(0x08) .map(|raw| ProbeTemperature::from(raw)) } /// Resolution /// /// Resolution for the probe’s reading, in 1/1000th degrees C /// /// If the value is unknown, the field is set to 0x8000. pub fn resolution(&self) -> Option { self.parts .get_field_word(0x0A) .map(|raw| TemperatureProbeResolution::from(raw)) } /// Tolerance /// /// Tolerance for reading from this probe, in plus/minus 1/10th degrees C /// /// If the value is unknown, the field is set to 0x8000. pub fn tolerance(&self) -> Option { self.parts .get_field_word(0x0C) .map(|raw| ProbeTemperature::from(raw)) } /// Accuracy /// /// Accuracy for reading from this probe, in plus/minus 1/100th of a percent /// /// If the value is unknown, the field is set to 0x8000. pub fn accuracy(&self) -> Option { self.parts .get_field_word(0x0E) .map(|raw| TemperatureProbeAccuracy::from(raw)) } /// OEM defined /// /// OEM- or BIOS vendor-specific information pub fn oem_defined(&self) -> Option { self.parts.get_field_dword(0x10) } /// Nominal value for the probe’s reading in 1/10th degrees C /// /// If the value is unknown, the field is set to 0x8000. This field is /// present in the structure only if the structure’s Length is larger /// than 14h. pub fn nominal_value(&self) -> Option { self.parts .get_field_word(0x14) .map(|raw| ProbeTemperature::from(raw)) } } impl fmt::Debug for SMBiosTemperatureProbe<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("description", &self.description()) .field("location_and_status", &self.location_and_status()) .field("maximum_value", &self.maximum_value()) .field("minimum_value", &self.minimum_value()) .field("resolution", &self.resolution()) .field("tolerance", &self.tolerance()) .field("accuracy", &self.accuracy()) .field("oem_defined", &self.oem_defined()) .field("nominal_value", &self.nominal_value()) .finish() } } impl Serialize for SMBiosTemperatureProbe<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosTemperatureProbe", 10)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("description", &self.description())?; state.serialize_field("location_and_status", &self.location_and_status())?; state.serialize_field("maximum_value", &self.maximum_value())?; state.serialize_field("minimum_value", &self.minimum_value())?; state.serialize_field("resolution", &self.resolution())?; state.serialize_field("tolerance", &self.tolerance())?; state.serialize_field("accuracy", &self.accuracy())?; state.serialize_field("oem_defined", &self.oem_defined())?; state.serialize_field("nominal_value", &self.nominal_value())?; state.end() } } /// # Temperature Probe Location and Status #[derive(PartialEq, Eq)] pub struct TemperatureProbeLocationAndStatus { /// Raw value pub raw: u8, } impl From for TemperatureProbeLocationAndStatus { fn from(raw: u8) -> Self { TemperatureProbeLocationAndStatus { raw } } } impl TemperatureProbeLocationAndStatus { /// Temperature Probe Location pub fn location(&self) -> TemperatureProbeLocation { TemperatureProbeLocation::from(self.raw) } /// Temperature Probe Status pub fn status(&self) -> TemperatureProbeStatus { TemperatureProbeStatus::from(self.raw) } } impl fmt::Debug for TemperatureProbeLocationAndStatus { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("location", &self.location()) .field("status", &self.status()) .finish() } } impl Serialize for TemperatureProbeLocationAndStatus { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("TemperatureProbeLocationAndStatus", 3)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("location", &self.location())?; state.serialize_field("status", &self.status())?; state.end() } } /// # Temperature Probe Status #[derive(Serialize, Debug, PartialEq, Eq)] pub enum TemperatureProbeStatus { /// Other Other, /// Unknown Unknown, /// OK OK, /// Non-critical NonCritical, /// Critical Critical, /// Non-recoverable NonRecoverable, /// A value unknown to this standard, check the raw value None, } impl From for TemperatureProbeStatus { fn from(raw: u8) -> Self { match raw & 0b1110_0000 { 0b0000_0000 => TemperatureProbeStatus::None, 0b0010_0000 => TemperatureProbeStatus::Other, 0b0100_0000 => TemperatureProbeStatus::Unknown, 0b0110_0000 => TemperatureProbeStatus::OK, 0b1000_0000 => TemperatureProbeStatus::NonCritical, 0b1010_0000 => TemperatureProbeStatus::Critical, 0b1100_0000 => TemperatureProbeStatus::NonRecoverable, 0b1110_0000 => TemperatureProbeStatus::None, _ => panic!("impossible value"), } } } /// # Temperature Probe Location #[derive(Serialize, Debug, PartialEq, Eq)] pub enum TemperatureProbeLocation { /// Other Other, /// Unknown Unknown, /// Processor Processor, /// Disk Disk, /// Peripheral Bay PeripheralBay, /// System Management Moduel SystemManagementModule, /// Motherboard Motherboard, /// Memory Module MemoryModule, /// Processor Module ProcessorModule, /// Power Unit PowerUnit, /// Add-in Card AddInCard, /// Front Panel Board FrontPanelBoard, /// Back Panel Board BackPanelBoard, /// Power System Board PowerSystemBoard, /// Drive Back Plane DriveBackPlane, /// A value unknown to this standard, check the raw value None, } impl From for TemperatureProbeLocation { fn from(raw: u8) -> Self { match raw & 0b0001_1111 { 0b0000_0001 => TemperatureProbeLocation::Other, 0b0000_0010 => TemperatureProbeLocation::Unknown, 0b0000_0011 => TemperatureProbeLocation::Processor, 0b0000_0100 => TemperatureProbeLocation::Disk, 0b0000_0101 => TemperatureProbeLocation::PeripheralBay, 0b0000_0110 => TemperatureProbeLocation::SystemManagementModule, 0b0000_0111 => TemperatureProbeLocation::Motherboard, 0b0000_1000 => TemperatureProbeLocation::MemoryModule, 0b0000_1001 => TemperatureProbeLocation::ProcessorModule, 0b0000_1010 => TemperatureProbeLocation::PowerUnit, 0b0000_1011 => TemperatureProbeLocation::AddInCard, 0b0000_1100 => TemperatureProbeLocation::FrontPanelBoard, 0b0000_1101 => TemperatureProbeLocation::BackPanelBoard, 0b0000_1110 => TemperatureProbeLocation::PowerSystemBoard, 0b0000_1111 => TemperatureProbeLocation::DriveBackPlane, _ => TemperatureProbeLocation::None, } } } /// # Probe Temperature #[derive(Serialize, Debug)] pub enum ProbeTemperature { /// Temperature in 1/10 degrees C OneTenthDegreesC(u16), /// Temperature is unknown Unknown, } impl From for ProbeTemperature { fn from(raw: u16) -> Self { match raw { 0x8000 => ProbeTemperature::Unknown, _ => ProbeTemperature::OneTenthDegreesC(raw), } } } /// # Temperature Probe Resolution #[derive(Serialize, Debug)] pub enum TemperatureProbeResolution { /// Resolution for the probe's reading in 1/1000 degrees C OneOneThousandthDegreesC(u16), /// Resolution is unknown Unknown, } impl From for TemperatureProbeResolution { fn from(raw: u16) -> Self { match raw { 0x8000 => TemperatureProbeResolution::Unknown, _ => TemperatureProbeResolution::OneOneThousandthDegreesC(raw), } } } /// # Temperature Probe Accuracy #[derive(Serialize, Debug)] pub enum TemperatureProbeAccuracy { /// Accuracy for the probe's reading in 1/100 degrees C OneOneHundredthDegreesC(u16), /// Accuracy is unknown Unknown, } impl From for TemperatureProbeAccuracy { fn from(raw: u16) -> Self { match raw { 0x8000 => TemperatureProbeAccuracy::Unknown, _ => TemperatureProbeAccuracy::OneOneHundredthDegreesC(raw), } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type28 = vec![ 0x1C, 0x16, 0x2A, 0x00, 0x01, 0x67, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4C, 0x4D, 0x37, 0x38, 0x41, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type28); let test_struct = SMBiosTemperatureProbe::new(&parts); assert_eq!(test_struct.description().to_string(), "LM78A".to_string()); assert_eq!( test_struct.location_and_status(), Some(TemperatureProbeLocationAndStatus::from(103)) ); match test_struct.maximum_value().unwrap() { ProbeTemperature::OneTenthDegreesC(_) => panic!("expected unknown"), ProbeTemperature::Unknown => (), } match test_struct.minimum_value().unwrap() { ProbeTemperature::OneTenthDegreesC(_) => panic!("expected unknown"), ProbeTemperature::Unknown => (), } match test_struct.resolution().unwrap() { TemperatureProbeResolution::OneOneThousandthDegreesC(_) => panic!("expected unknown"), TemperatureProbeResolution::Unknown => (), } match test_struct.tolerance().unwrap() { ProbeTemperature::OneTenthDegreesC(_) => panic!("expected unknown"), ProbeTemperature::Unknown => (), } match test_struct.accuracy().unwrap() { TemperatureProbeAccuracy::OneOneHundredthDegreesC(_) => panic!("expected unknown"), TemperatureProbeAccuracy::Unknown => (), } assert_eq!(test_struct.oem_defined(), Some(0)); match test_struct.nominal_value().unwrap() { ProbeTemperature::OneTenthDegreesC(_) => panic!("expected unknown"), ProbeTemperature::Unknown => (), } } } smbios-lib-0.9.2/src/structs/types/tpm_device.rs000064400000000000000000000253511046102023000200310ustar 00000000000000use crate::core::{strings::*, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::{array::TryFromSliceError, convert::TryFrom, fmt, ops::Deref}; /// # TPM Device (Type 43) pub struct SMBiosTpmDevice<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosTpmDevice<'a> { const STRUCT_TYPE: u8 = 43u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosTpmDevice<'a> { /// Vendor Id /// /// Specified as four ASCII characters, as defined by TCG /// Vendor ID (see CAP_VID in TCG Vendor ID Registry). /// /// For example: /// Vendor ID string of "ABC" = (41 42 43 00) /// Vendor ID string of "ABCD" = (41 42 43 44) pub fn vendor_id(&self) -> Option> { self.parts .get_field_data(0x04, 0x08) .and_then(|array| Some(VendorId::try_from(array).expect("Vendor Id is 4 bytes"))) } /// Major spec version /// /// Major TPM version supported by the TPM device. For /// example, the value is 01h for TPM v1.2 and is 02h for /// TPM v2.0. pub fn major_spec_version(&self) -> Option { self.parts.get_field_byte(0x08) } /// Minor spec version /// /// Minor TPM version supported by the TPM device. For /// example, the value is 02h for TPM v1.2 and is 00h for /// TPM v2.0. pub fn minor_spec_version(&self) -> Option { self.parts.get_field_byte(0x09) } /// Firmware version 1 /// /// For Major Spec Version 01h, this field contains the /// TPM_VERSION structure defined in the TPM Main /// Specification, Part 2, Section 5.3. /// /// For Major Spec Version 02h, this field contains the /// most significant 32 bits of a TPM vendor-specific value /// for firmware version (see /// TPM_PT_FIRMWARE_VERSION_1 in TPM Structures /// specification). pub fn firmware_version_1(&self) -> Option { self.parts.get_field_dword(0x0A) } /// Firmware version 2 /// /// For Major Spec Version 01h, this field contains 00h. /// /// For Major Spec Version 02h, this field contains the /// least significant 32 bits of a TPM vendor-specific value /// for firmware version (see /// TPM_PT_FIRMWARE_VERSION_2 in TPM Structures /// specification). pub fn firmware_version_2(&self) -> Option { self.parts.get_field_dword(0x0E) } /// Description /// /// Descriptive information of the TPM device. pub fn description(&self) -> SMBiosString { self.parts.get_field_string(0x12) } /// Characteristics /// /// TPM device characteristics information. pub fn characteristics(&self) -> Option { self.parts .get_field_qword(0x13) .map(|raw| TpmDeviceCharacteristics::from(raw)) } /// OEM defined /// /// OEM- or BIOS vendor-specific information pub fn oem_defined(&self) -> Option { self.parts.get_field_dword(0x1B) } } impl fmt::Debug for SMBiosTpmDevice<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("vendor_id", &self.vendor_id()) .field("major_spec_version", &self.major_spec_version()) .field("minor_spec_version", &self.minor_spec_version()) .field("firmware_version_1", &self.firmware_version_1()) .field("firmware_version_2", &self.firmware_version_2()) .field("description", &self.description()) .field("characteristics", &self.characteristics()) .field("oem_defined", &self.oem_defined()) .finish() } } impl Serialize for SMBiosTpmDevice<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosTpmDevice", 9)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("vendor_id", &self.vendor_id())?; state.serialize_field("major_spec_version", &self.major_spec_version())?; state.serialize_field("minor_spec_version", &self.minor_spec_version())?; state.serialize_field("firmware_version_1", &self.firmware_version_1())?; state.serialize_field("firmware_version_2", &self.firmware_version_2())?; state.serialize_field("description", &self.description())?; state.serialize_field("characteristics", &self.characteristics())?; state.serialize_field("oem_defined", &self.oem_defined())?; state.end() } } /// # Vendor Id /// /// Specified as four ASCII characters, /// as defined by TCG Vendor ID /// (see CAP_VID in TCG Vendor ID Registry) #[derive(PartialEq, Eq)] pub struct VendorId<'a> { /// Raw array /// /// Example: Vendor Id string of "ABC" = (41 42 43 00) pub array: &'a [u8; 4], } impl<'a> TryFrom<&'a [u8]> for VendorId<'a> { type Error = TryFromSliceError; fn try_from(raw: &'a [u8]) -> Result { <&[u8; 4]>::try_from(raw).and_then(|array| Ok(VendorId { array })) } } impl<'a> fmt::Debug for VendorId<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("array", &self.array) .field("string", &String::from_utf8_lossy(self.array)) .finish() } } impl<'a> Serialize for VendorId<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("VendorId", 2)?; state.serialize_field("array", &self.array)?; state.serialize_field("string", &String::from_utf8_lossy(self.array))?; state.end() } } /// # TPM Device Characteristics #[derive(PartialEq, Eq)] pub struct TpmDeviceCharacteristics { /// Raw value /// /// _raw_ is useful when there are values not yet defiend. /// This is most likely to occur when the standard was updated but /// this library code has not been updated to match the current /// standard. pub raw: u64, } impl Deref for TpmDeviceCharacteristics { type Target = u64; fn deref(&self) -> &Self::Target { &self.raw } } impl From for TpmDeviceCharacteristics { fn from(raw: u64) -> Self { TpmDeviceCharacteristics { raw } } } impl TpmDeviceCharacteristics { /// Bit 0 - reserved pub fn reserved_0(&self) -> bool { self.raw & 0x0000000000000001 == 0x0000000000000001 } /// Bit 1 - reserved pub fn reserved_1(&self) -> bool { self.raw & 0x0000000000000002 == 0x0000000000000002 } /// Bit 2 - TPM Device Characteristics are not supported. pub fn not_supported(&self) -> bool { self.raw & 0x0000000000000004 == 0x0000000000000004 } /// Bit 3 - Family configurable via firmware update; for example, switching between TPM 1.2 pub fn family_configurable_via_firmware(&self) -> bool { self.raw & 0x0000000000000008 == 0x0000000000000008 } /// Bit 4 - Family configurable via platform software support, such as BIOS Setup; for example, pub fn family_configurable_via_software(&self) -> bool { self.raw & 0x0000000000000010 == 0x0000000000000010 } /// Bit 5 - Family configurable via OEM proprietary mechanism; for example, switching between TPM 1.2 and TPM 2.0. pub fn family_configurable_via_oem(&self) -> bool { self.raw & 0x0000000000000020 == 0x0000000000000020 } } impl fmt::Debug for TpmDeviceCharacteristics { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("reserved_0", &self.reserved_0()) .field("reserved_1", &self.reserved_1()) .field("not_supported", &self.not_supported()) .field( "family_configurable_via_firmware", &self.family_configurable_via_firmware(), ) .field( "family_configurable_via_software", &self.family_configurable_via_software(), ) .field( "family_configurable_via_oem", &self.family_configurable_via_oem(), ) .finish() } } impl Serialize for TpmDeviceCharacteristics { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("TpmDeviceCharacteristics", 7)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("reserved_0", &self.reserved_0())?; state.serialize_field("reserved_1", &self.reserved_1())?; state.serialize_field("not_supported", &self.not_supported())?; state.serialize_field( "family_configurable_via_firmware", &self.family_configurable_via_firmware(), )?; state.serialize_field( "family_configurable_via_software", &self.family_configurable_via_software(), )?; state.serialize_field( "family_configurable_via_oem", &self.family_configurable_via_oem(), )?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type43 = vec![ 0x2B, 0x1F, 0x3C, 0x00, 0x00, 0x58, 0x46, 0x49, 0x02, 0x00, 0x3E, 0x00, 0x05, 0x00, 0x00, 0x36, 0x0C, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x50, 0x4D, 0x20, 0x32, 0x2E, 0x30, 0x00, 0x49, 0x4E, 0x46, 0x49, 0x4E, 0x45, 0x4F, 0x4E, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type43); let test_struct = SMBiosTpmDevice::new(&parts); println!("{:?}", test_struct); assert_eq!( test_struct.vendor_id().unwrap().array, &[0, b'X', b'F', b'I'] ); assert_eq!(test_struct.major_spec_version(), Some(2)); assert_eq!(test_struct.minor_spec_version(), Some(0)); assert_eq!(test_struct.firmware_version_1(), Some(327742)); assert_eq!(test_struct.firmware_version_2(), Some(800256)); assert_eq!( test_struct.description().to_string(), "INFINEON".to_string() ); assert_eq!( test_struct.characteristics(), Some(TpmDeviceCharacteristics::from(16)) ); assert_eq!(test_struct.oem_defined(), Some(0)); } } smbios-lib-0.9.2/src/structs/types/unknown.rs000064400000000000000000000057731046102023000174170ustar 00000000000000use crate::{Header, UndefinedStruct}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # OEM or Unknown Structure /// /// Types 0 through 127 (7Fh) are reserved for and /// defined by the DMTF SMBIOS specification. /// Types 128 through 256 (80h to FFh) are available for /// system- and OEM-specific information. /// /// When a structure has a type which is not defined or /// its type is an OEM type in the 80h to FFh range, /// this structure is used to represent the type. pub struct SMBiosUnknown<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosUnknown<'a> { /// Creates an instance of this struct pub fn new(parts: &'a UndefinedStruct) -> Self { SMBiosUnknown { parts: parts } } /// Structure parts of this unknown structure /// /// Use this to inspect the structure in more detail. pub fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl fmt::Debug for SMBiosUnknown<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let fields = &self.parts.fields[Header::SIZE..]; fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("fields", &fields) .field("strings", &self.parts.strings) .finish() } } impl Serialize for SMBiosUnknown<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let fields = &self.parts.fields[Header::SIZE..]; let mut state = serializer.serialize_struct("SMBiosUnknown", 3)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("fields", &fields)?; state.serialize_field("strings", &self.parts.strings)?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_unknown_oem_type() { // For testing we've borrowed a language information type (0x0D) structure and change its type to 0x99 (> 0x7F are OEM types) let unknown_bytes = vec![ 0x99u8, 0x16, 0x21, 0x00, // unknown data 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // "en|US|iso8859-1" 0x65, 0x6E, 0x7C, 0x55, 0x53, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31, 0x00, // "fr|FR|iso8859-1" 0x66, 0x72, 0x7C, 0x46, 0x52, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31, 0x00, // "ja|JP|unicode" 0x6A, 0x61, 0x7C, 0x4A, 0x50, 0x7C, 0x75, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, 0x00, // end of structure 0x00, ]; let parts = UndefinedStruct::new(&unknown_bytes); let unknown = SMBiosUnknown::new(&parts); // header tests assert_eq!(*unknown.parts().header.handle(), 0x0021); assert_eq!(unknown.parts().header.length(), 0x16); // debug print test println!("unknown structure: {:?}", unknown); } } smbios-lib-0.9.2/src/structs/types/voltage_probe.rs000064400000000000000000000270751046102023000205470ustar 00000000000000use crate::core::{strings::*, UndefinedStruct}; use crate::SMBiosStruct; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::fmt; /// # Voltage Probe (Type 26) /// /// This describes the attributes for a voltage probe in the system. Each structure describes a single voltage /// probe. /// /// NOTE This structure type was added in version 2.2 of this specification. pub struct SMBiosVoltageProbe<'a> { parts: &'a UndefinedStruct, } impl<'a> SMBiosStruct<'a> for SMBiosVoltageProbe<'a> { const STRUCT_TYPE: u8 = 26u8; fn new(parts: &'a UndefinedStruct) -> Self { Self { parts } } fn parts(&self) -> &'a UndefinedStruct { self.parts } } impl<'a> SMBiosVoltageProbe<'a> { /// Description /// /// Additional descriptive information about the probe or its location pub fn description(&self) -> SMBiosString { self.parts.get_field_string(0x04) } /// Location and status bit-field /// /// Probe’s physical location and status of the voltage /// monitored by this voltage probe pub fn location_and_status(&self) -> Option { self.parts .get_field_byte(0x05) .map(|raw| VoltageProbeLocationAndStatus::from(raw)) } /// Maximum value /// /// Maximum voltage level readable by this probe, in /// millivolts pub fn maximum_value(&self) -> Option { self.parts .get_field_word(0x06) .map(|raw| ProbeVoltage::from(raw)) } /// Minimum value /// /// Minimum voltage level readable by this probe, in millivolts pub fn minimum_value(&self) -> Option { self.parts .get_field_word(0x08) .map(|raw| ProbeVoltage::from(raw)) } /// Resolution /// /// Resolution for the probe’s reading, in tenths of millivolts pub fn resolution(&self) -> Option { self.parts .get_field_word(0x0A) .map(|raw| VoltageProbeResolution::from(raw)) } /// Tolerance /// /// Tolerance for reading from this probe, in plus/minus /// millivolts pub fn tolerance(&self) -> Option { self.parts .get_field_word(0x0C) .map(|raw| ProbeVoltage::from(raw)) } /// Accuracy /// /// Accuracy for reading from this probe, in plus/minus /// 1/100th of a percent pub fn accuracy(&self) -> Option { self.parts .get_field_word(0x0E) .map(|raw| VoltageProbeAccuracy::from(raw)) } /// OEM defined /// /// OEM- or BIOS vendor-specific information. pub fn oem_defined(&self) -> Option { self.parts.get_field_dword(0x10) } /// Nominal value /// /// Nominal value for the probe’s reading in millivolts /// This field is present in the structure only if the structure's /// length is larger than 14h. pub fn nominal_value(&self) -> Option { self.parts .get_field_word(0x14) .map(|raw| ProbeVoltage::from(raw)) } } impl fmt::Debug for SMBiosVoltageProbe<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::>()) .field("header", &self.parts.header) .field("description", &self.description()) .field("location_and_status", &self.location_and_status()) .field("maximum_value", &self.maximum_value()) .field("minimum_value", &self.minimum_value()) .field("resolution", &self.resolution()) .field("tolerance", &self.tolerance()) .field("accuracy", &self.accuracy()) .field("oem_defined", &self.oem_defined()) .field("nominal_value", &self.nominal_value()) .finish() } } impl Serialize for SMBiosVoltageProbe<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("SMBiosVoltageProbe", 10)?; state.serialize_field("header", &self.parts.header)?; state.serialize_field("description", &self.description())?; state.serialize_field("location_and_status", &self.location_and_status())?; state.serialize_field("maximum_value", &self.maximum_value())?; state.serialize_field("minimum_value", &self.minimum_value())?; state.serialize_field("resolution", &self.resolution())?; state.serialize_field("tolerance", &self.tolerance())?; state.serialize_field("accuracy", &self.accuracy())?; state.serialize_field("oem_defined", &self.oem_defined())?; state.serialize_field("nominal_value", &self.nominal_value())?; state.end() } } /// # Voltage Probe Location and Status #[derive(PartialEq, Eq)] pub struct VoltageProbeLocationAndStatus { /// Raw value pub raw: u8, } impl From for VoltageProbeLocationAndStatus { fn from(raw: u8) -> Self { VoltageProbeLocationAndStatus { raw } } } impl VoltageProbeLocationAndStatus { /// Voltage Probe Location pub fn location(&self) -> VoltageProbeLocation { VoltageProbeLocation::from(self.raw) } /// Voltage Probe Status pub fn status(&self) -> VoltageProbeStatus { VoltageProbeStatus::from(self.raw) } } impl fmt::Debug for VoltageProbeLocationAndStatus { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("raw", &self.raw) .field("location", &self.location()) .field("status", &self.status()) .finish() } } impl Serialize for VoltageProbeLocationAndStatus { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("VoltageProbeLocationAndStatus", 3)?; state.serialize_field("raw", &self.raw)?; state.serialize_field("location", &self.location())?; state.serialize_field("status", &self.status())?; state.end() } } /// # Voltage Probe Status #[derive(Serialize, Debug, PartialEq, Eq)] pub enum VoltageProbeStatus { /// Other Other, /// Unknown Unknown, /// OK OK, /// Non-critical NonCritical, /// Critical Critical, /// Non-recoverable NonRecoverable, /// A value unknown to this standard, check the raw value None, } impl From for VoltageProbeStatus { fn from(raw: u8) -> Self { match raw & 0b1110_0000 { 0b0000_0000 => VoltageProbeStatus::None, 0b0010_0000 => VoltageProbeStatus::Other, 0b0100_0000 => VoltageProbeStatus::Unknown, 0b0110_0000 => VoltageProbeStatus::OK, 0b1000_0000 => VoltageProbeStatus::NonCritical, 0b1010_0000 => VoltageProbeStatus::Critical, 0b1100_0000 => VoltageProbeStatus::NonRecoverable, 0b1110_0000 => VoltageProbeStatus::None, _ => panic!("impossible value"), } } } /// # Voltage Probe Location #[derive(Serialize, Debug, PartialEq, Eq)] pub enum VoltageProbeLocation { /// Other Other, /// Unknown Unknown, /// Processor Processor, /// Disk Disk, /// Peripheral Bay PeripheralBay, /// System Management Moduel SystemManagementModule, /// Motherboard Motherboard, /// Memory Module MemoryModule, /// Processor Module ProcessorModule, /// Power Unit PowerUnit, /// Add-in Card AddInCard, /// A value unknown to this standard, check the raw value None, } impl From for VoltageProbeLocation { fn from(raw: u8) -> Self { match raw & 0b0001_1111 { 0b0000_0001 => VoltageProbeLocation::Other, 0b0000_0010 => VoltageProbeLocation::Unknown, 0b0000_0011 => VoltageProbeLocation::Processor, 0b0000_0100 => VoltageProbeLocation::Disk, 0b0000_0101 => VoltageProbeLocation::PeripheralBay, 0b0000_0110 => VoltageProbeLocation::SystemManagementModule, 0b0000_0111 => VoltageProbeLocation::Motherboard, 0b0000_1000 => VoltageProbeLocation::MemoryModule, 0b0000_1001 => VoltageProbeLocation::ProcessorModule, 0b0000_1010 => VoltageProbeLocation::PowerUnit, 0b0000_1011 => VoltageProbeLocation::AddInCard, _ => VoltageProbeLocation::None, } } } /// # Probe Voltage #[derive(Serialize, Debug)] pub enum ProbeVoltage { /// Voltage in millivolts Millivolts(u16), /// Voltage is unknown Unknown, } impl From for ProbeVoltage { fn from(raw: u16) -> Self { match raw { 0x8000 => ProbeVoltage::Unknown, _ => ProbeVoltage::Millivolts(raw), } } } /// # Voltage Probe Resolution #[derive(Serialize, Debug)] pub enum VoltageProbeResolution { /// Resolution for the probe's reading in tenths of millivolts TenthsOfMillivolts(u16), /// Resolution is unknown Unknown, } impl From for VoltageProbeResolution { fn from(raw: u16) -> Self { match raw { 0x8000 => VoltageProbeResolution::Unknown, _ => VoltageProbeResolution::TenthsOfMillivolts(raw), } } } /// # Voltage Probe Accuracy #[derive(Serialize, Debug)] pub enum VoltageProbeAccuracy { /// Accuracy for the probe's reading in 1/100th of a percent OneOneHundredthPercent(u16), /// Accuracy is unknown Unknown, } impl From for VoltageProbeAccuracy { fn from(raw: u16) -> Self { match raw { 0x8000 => VoltageProbeAccuracy::Unknown, _ => VoltageProbeAccuracy::OneOneHundredthPercent(raw), } } } #[cfg(test)] mod tests { use super::*; #[test] fn unit_test() { let struct_type26 = vec![ 26, 0x16, 0x2A, 0x00, 0x01, 0x67, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4C, 0x4D, 0x37, 0x38, 0x41, 0x00, 0x00, ]; let parts = UndefinedStruct::new(&struct_type26); let test_struct = SMBiosVoltageProbe::new(&parts); assert_eq!(test_struct.description().to_string(), "LM78A".to_string()); assert_eq!( test_struct.location_and_status(), Some(VoltageProbeLocationAndStatus::from(103)) ); match test_struct.maximum_value().unwrap() { ProbeVoltage::Millivolts(_) => panic!("expected unknown"), ProbeVoltage::Unknown => (), } match test_struct.minimum_value().unwrap() { ProbeVoltage::Millivolts(_) => panic!("expected unknown"), ProbeVoltage::Unknown => (), } match test_struct.resolution().unwrap() { VoltageProbeResolution::TenthsOfMillivolts(_) => panic!("expected unknown"), VoltageProbeResolution::Unknown => (), } match test_struct.tolerance().unwrap() { ProbeVoltage::Millivolts(_) => panic!("expected unknown"), ProbeVoltage::Unknown => (), } match test_struct.accuracy().unwrap() { VoltageProbeAccuracy::OneOneHundredthPercent(_) => panic!("expected unknown"), VoltageProbeAccuracy::Unknown => (), } assert_eq!(test_struct.oem_defined(), Some(0)); match test_struct.nominal_value().unwrap() { ProbeVoltage::Millivolts(_) => panic!("expected unknown"), ProbeVoltage::Unknown => (), } } } smbios-lib-0.9.2/src/unix/mod.rs000064400000000000000000000003761046102023000146010ustar 00000000000000#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] mod platform; #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] pub use platform::*; pub use std::convert::TryInto; pub use std::{fmt, fs, io}; smbios-lib-0.9.2/src/unix/platform.rs000064400000000000000000000253071046102023000156470ustar 00000000000000use crate::*; use std::{io::Error, io::ErrorKind}; #[cfg(any(target_os = "linux"))] /// Full path to smbios_entry_point file on Linux (contains entry point data) pub const SYS_ENTRY_FILE: &'static str = "/sys/firmware/dmi/tables/smbios_entry_point"; #[cfg(any(target_os = "linux"))] /// Full path to the DMI file on Linux (contains BIOS table data) pub const SYS_TABLE_FILE: &'static str = "/sys/firmware/dmi/tables/DMI"; /// Full path to the memory device (contains BIOS entry point and table data on *nix platforms) pub const DEV_MEM_FILE: &'static str = "/dev/mem"; // Example of Linux structure: /* /sys/firmware/dmi/tables$ sudo hexdump -C smbios_entry_point 00000000 5f 53 4d 33 5f 7e 18 03 03 00 01 00 83 04 00 00 |_SM3_~..........| 00000010 00 20 b0 7b 00 00 00 00 |. .{....| 00000018 Note: _SM3_ indicates the version of the entry point. Offsets 0x7-0x9 are the BIOS version 0x03, 0x03, 0x00 (3.0.0) jeff@blacktop:/sys/firmware/dmi/tables$ sudo hexdump -C DMI 00000000 00 1a 00 00 01 02 00 00 03 ff 80 18 19 0c 00 00 |................| 00000010 00 00 03 0d ff ff ff ff 00 00 4d 69 63 72 6f 73 |..........Micros| 00000020 6f 66 74 20 43 6f 72 70 6f 72 61 74 69 6f 6e 00 |oft Corporation.| 00000030 39 2e 31 30 32 2e 31 34 30 00 31 31 2f 31 36 2f |9.102.140.11/16/| 00000040 32 30 32 30 00 00 01 1b 01 00 01 02 03 04 86 76 |2020...........v| 00000050 fb 97 d5 7b 15 d0 b2 39 6b ba a4 df c0 45 02 05 |...{...9k....E..| 00000060 06 4d 69 63 72 6f 73 6f 66 74 20 43 6f 72 70 6f |.Microsoft Corpo| 00000070 72 61 74 69 6f 6e 00 53 75 72 66 61 63 65 20 4c |ration.Surface L| 00000080 61 70 74 6f 70 20 33 00 31 32 34 49 3a 30 30 30 |aptop 3.124I:000| 00000090 33 36 54 3a 30 30 30 4d 3a 30 33 30 30 30 30 30 |36T:000M:0300000| 000000a0 44 3a 30 42 3a 30 37 46 3a 31 43 3a 30 35 50 3a |D:0B:07F:1C:05P:| 000000b0 34 38 53 3a 30 31 45 3a 30 59 3a 31 4b 3a 30 55 |48S:01E:0Y:1K:0U| 000000c0 3a 30 38 00 30 30 31 39 35 33 33 30 32 30 35 37 |:08.001953302057| 000000d0 00 53 75 72 66 61 63 65 5f 4c 61 70 74 6f 70 5f |.Surface_Laptop_| 000000e0 33 5f 31 38 37 32 00 53 75 72 66 61 63 65 00 00 |3_1872.Surface..| */ // Note: /sys/class/dmi/id contains some of the BIOS values, already parsed by the kernel. // These are useful for cross checking against the results this library produces when reading // /sys/firmware/dmi/tables/DMI #[cfg(any(target_os = "linux"))] /// Loads [SMBiosData] from the device via /sys/firmware/dmi/tables (on Linux) pub fn table_load_from_device() -> Result { let version: SMBiosVersion; let entry_path = std::path::Path::new(SYS_ENTRY_FILE); match SMBiosEntryPoint64::try_load_from_file(entry_path) { Ok(entry_point) => { version = SMBiosVersion { major: entry_point.major_version(), minor: entry_point.minor_version(), revision: entry_point.docrev(), } } Err(err) => match err.kind() { ErrorKind::InvalidData => match SMBiosEntryPoint32::try_load_from_file(entry_path) { Ok(entry_point) => { version = SMBiosVersion { major: entry_point.major_version(), minor: entry_point.minor_version(), revision: 0, } } Err(err) => return Err(err), }, _ => return Err(err), }, } SMBiosData::try_load_from_file(SYS_TABLE_FILE, Some(version)) } #[cfg(any(target_os = "freebsd"))] /// Loads [SMBiosData] from the device via /dev/mem (on FreeBSD) pub fn table_load_from_device() -> Result { const RANGE_START: u64 = 0x000F0000u64; const RANGE_END: u64 = 0x000FFFFFu64; let structure_table_address: u64; let structure_table_length: u32; let version: SMBiosVersion; let mut dev_mem = std::fs::File::open(DEV_MEM_FILE)?; match SMBiosEntryPoint32::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END) { Ok(entry_point) => { structure_table_address = entry_point.structure_table_address() as u64; structure_table_length = entry_point.structure_table_length() as u32; version = SMBiosVersion { major: entry_point.major_version(), minor: entry_point.minor_version(), revision: 0, } } Err(error) => { if error.kind() != ErrorKind::UnexpectedEof { return Err(error); } let entry_point = SMBiosEntryPoint64::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END)?; structure_table_address = entry_point.structure_table_address(); structure_table_length = entry_point.structure_table_maximum_size(); version = SMBiosVersion { major: entry_point.major_version(), minor: entry_point.minor_version(), revision: entry_point.docrev(), } } } if structure_table_address + structure_table_length as u64 > RANGE_END { return Err(Error::new( ErrorKind::InvalidData, format!( "The entry point has given a length which exceeds the range: {}", structure_table_length ), )); } let table = UndefinedStructTable::try_load_from_file_offset( &mut dev_mem, structure_table_address, structure_table_length as usize, )?; Ok(SMBiosData::new(table, Some(version))) } #[cfg(any(target_os = "linux"))] /// Returns smbios raw data via /sys/firmware/dmi/tables (on Linux) pub fn raw_smbios_from_device() -> Result, Error> { Ok(std::fs::read(SYS_TABLE_FILE)?) } #[cfg(any(target_os = "freebsd"))] /// Returns smbios raw data via /dev/mem (on FreeBSD) pub fn raw_smbios_from_device() -> Result, Error> { use std::io::{prelude::*, SeekFrom}; const RANGE_START: u64 = 0x000F0000u64; const RANGE_END: u64 = 0x000FFFFFu64; let structure_table_address: u64; let structure_table_length: usize; let mut dev_mem = std::fs::File::open(DEV_MEM_FILE)?; match SMBiosEntryPoint32::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END) { Ok(entry_point) => { structure_table_address = entry_point.structure_table_address() as u64; structure_table_length = entry_point.structure_table_length() as usize; } Err(error) => { if error.kind() != ErrorKind::UnexpectedEof { return Err(error); } let entry_point = SMBiosEntryPoint64::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END)?; structure_table_address = entry_point.structure_table_address(); structure_table_length = entry_point.structure_table_maximum_size() as usize; } } if structure_table_address < RANGE_START || structure_table_address > RANGE_END { return Err(Error::new( ErrorKind::InvalidData, format!( "The entry point has given an out of range start address for the table: {}", structure_table_address ), )); } if structure_table_address + structure_table_length as u64 > RANGE_END { return Err(Error::new( ErrorKind::InvalidData, format!( "The entry point has given a length which exceeds the range: {}", structure_table_length ), )); } if structure_table_length < Header::SIZE + 2 { return Err(Error::new( ErrorKind::InvalidData, format!("The table has an invalid size: {}", structure_table_length), )); } dev_mem.seek(SeekFrom::Start(structure_table_address))?; let mut table = Vec::with_capacity(structure_table_length); table.resize(structure_table_length, 0); dev_mem.read_exact(&mut table)?; Ok(table) } #[cfg(test)] mod tests { use super::*; use std::fs::File; use std::io; #[test] fn test_dev_mem_scan() -> io::Result<()> { const RANGE_START: u64 = 0x000F0000u64; const RANGE_END: u64 = 0x000FFFFFu64; let mut dev_mem = File::open(DEV_MEM_FILE)?; let structure_table_address: u64; let structure_table_length: u32; match SMBiosEntryPoint32::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END) { Ok(entry_point) => { structure_table_address = entry_point.structure_table_address() as u64; structure_table_length = entry_point.structure_table_length() as u32; println!( "SMBIOS {}.{} present.", entry_point.major_version(), entry_point.minor_version() ); println!( "{} structures occupying {} bytes.", entry_point.number_of_smbios_structures(), entry_point.structure_table_length() ); println!("Table at: {:#010X}.", entry_point.structure_table_address()); } Err(error) => { if error.kind() != ErrorKind::UnexpectedEof { return Err(error); } let entry_point = SMBiosEntryPoint64::try_scan_from_file(&mut dev_mem, RANGE_START..=RANGE_END)?; structure_table_address = entry_point.structure_table_address(); structure_table_length = entry_point.structure_table_maximum_size(); println!( "SMBIOS {}.{}.{} present.", entry_point.major_version(), entry_point.minor_version(), entry_point.docrev() ); println!( "Occupying {} bytes maximum.", entry_point.structure_table_maximum_size() ); println!("Table at: {:#010X}.", entry_point.structure_table_address()); } } if structure_table_address + structure_table_length as u64 > RANGE_END { return Err(Error::new( ErrorKind::InvalidData, format!( "The entry point has given a length which exceeds the range: {}", structure_table_length ), )); } let table = UndefinedStructTable::try_load_from_file_offset( &mut dev_mem, structure_table_address, structure_table_length as usize, )?; println!("{:#X?}", table); Ok(()) } } smbios-lib-0.9.2/src/windows/mod.rs000064400000000000000000000011671046102023000153070ustar 00000000000000//! Windows SMBIOS. //! //! Functions and structures for working with SMBIOS on Windows. //! //! # Example //! ```rust //! #[cfg(target_family = "windows")] //! #[test] //! fn windows_dump() { //! match load_windows_smbios_data() { //! Ok(windows_data) => { //! println!("windows_data: {:#?}", windows_data); //! } //! Err(err) => panic!("failure: {:?}", err), //! } //! } //! ``` mod win_struct; #[cfg(target_family = "windows")] mod platform; pub use win_struct::*; #[cfg(target_family = "windows")] pub use platform::*; pub use std::convert::TryInto; pub use std::{fmt, fs, io}; smbios-lib-0.9.2/src/windows/platform.rs000064400000000000000000000046261046102023000163570ustar 00000000000000use std::{ convert::TryInto, io::{Error, ErrorKind}, }; use crate::SMBiosData; use super::WinSMBiosData; mod ffi { // https://doc.rust-lang.org/nomicon/ffi.html #[link(name = "kernel32")] extern "system" { pub fn GetSystemFirmwareTable( firmware_table_provider_signature: u32, firmware_table_id: u32, firmware_table_buffer_ptr: *mut u8, buffer_size: u32, ) -> u32; } } /// Calls the Windows kernel32 function [GetSystemFirmwareTable](https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemfirmwaretable) pub fn load_windows_smbios_data() -> Result { match raw_smbios_from_device() { Ok(raw) => WinSMBiosData::new(raw), Err(e) => Err(e), } } /// Loads SMBIOS table data ([SMBiosData]) from the device pub fn table_load_from_device() -> Result { Ok(load_windows_smbios_data()?.smbios_data) } /// Returns smbios raw data pub fn raw_smbios_from_device() -> Result, Error> { use std::ptr; unsafe { const MEMORY_ERROR_MESSAGE: &'static str = "Memory error"; const RAW_SMBIOS_SIGNATURE: u32 = 1381190978u32; // 'RSMB' ASCII bytes == 1381190978 let max_i32: u32 = i32::MAX.try_into().unwrap(); let firmware_table_buffer_ptr: *mut u8 = ptr::null_mut(); let buffer_size = ffi::GetSystemFirmwareTable(RAW_SMBIOS_SIGNATURE, 0, firmware_table_buffer_ptr, 0); // 0 is win32 exception, > i32::MAX is memory exception if buffer_size == 0 || buffer_size > max_i32 { return Err(Error::new(ErrorKind::Other, MEMORY_ERROR_MESSAGE)); } let mut firmware_table_buffer = Vec::with_capacity(buffer_size as usize); let firmware_table_buffer_ptr = firmware_table_buffer.as_mut_ptr(); let buffer_size = ffi::GetSystemFirmwareTable( RAW_SMBIOS_SIGNATURE, 0, firmware_table_buffer_ptr, buffer_size, ); // 0 is win32 exception if buffer_size == 0 { Err(Error::last_os_error()) } // > i32::MAX is memory exception else if buffer_size > max_i32 { Err(Error::new(ErrorKind::Other, MEMORY_ERROR_MESSAGE)) } else { firmware_table_buffer.set_len(buffer_size as usize); Ok(firmware_table_buffer) } } } smbios-lib-0.9.2/src/windows/win_struct.rs000064400000000000000000000172471046102023000167370ustar 00000000000000use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::{ convert::TryInto, fmt, io::{Error, ErrorKind}, }; use crate::core::{SMBiosData, SMBiosVersion}; /// # Raw SMBIOS Data /// /// When Windows kernel32 [GetSystemFirmwareTable](https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemfirmwaretable) function is called for RSMB, /// the raw SMBIOS table provider ('RSMB') it retrieves the contents of this /// raw SMBIOS firmware table structure. pub struct WinSMBiosData { windows_header: Vec, /// SMBios table data pub smbios_data: SMBiosData, } impl WinSMBiosData { /// Offset of the Used20CallingMethod field (0) pub const USED20_CALLING_METHOD_OFFSET: usize = 0usize; /// Offset of the SMBIOSMajorVersion field (1) pub const SMBIOS_MAJOR_VERSION_OFFSET: usize = 1usize; /// Offset of the SMBIOSMinorVersion field (2) pub const SMBIOS_MINOR_VERSION_OFFSET: usize = 2usize; /// Offset of the DMIRevision field (3) pub const DMI_REVISION_OFFSET: usize = 3usize; /// Offset of the Length field (4) pub const TABLE_DATA_LENGTH_OFFSET: usize = 4usize; /// Offset of the SMBIOSTableData field (8) pub const SMBIOS_TABLE_DATA_OFFSET: usize = 8usize; /// Creates an instance of [WinSMBiosData] /// /// To retrieve this structure on a windows system call load_windows_smbios_data(). /// /// The new() is provided publicly to allow loading data from other sources /// such as a file or from memory array as is done with testing. pub fn new(raw_smbios_data: Vec) -> Result { if !WinSMBiosData::is_valid_win_smbios_data(&raw_smbios_data) { Err(Error::new( ErrorKind::InvalidData, "Invalid WinSMBiosData structure", )) } else { let windows_header = Vec::from(&raw_smbios_data[..WinSMBiosData::SMBIOS_TABLE_DATA_OFFSET]); let version = WinSMBiosData::version_from_raw_header(&windows_header); Ok(WinSMBiosData { windows_header, smbios_data: { SMBiosData::from_vec_and_version( Vec::from(&raw_smbios_data[WinSMBiosData::SMBIOS_TABLE_DATA_OFFSET..]), Some(version), ) }, }) } } /// Verify if a block of data is a valid WinSMBiosData structure /// /// This only checks if the structure itself is valid and not whether the contained /// [SMBiosData] structure is valid or not. pub fn is_valid_win_smbios_data(raw_data: &Vec) -> bool { let length = raw_data.len(); if length <= WinSMBiosData::SMBIOS_TABLE_DATA_OFFSET { return false; } // retrieve the table data length field let slice = raw_data .get( WinSMBiosData::TABLE_DATA_LENGTH_OFFSET ..WinSMBiosData::TABLE_DATA_LENGTH_OFFSET + 4, ) .unwrap(); let table_data_length = u32::from_le_bytes( slice .try_into() .expect("array length does not match type width"), ) as usize; table_data_length == length - WinSMBiosData::SMBIOS_TABLE_DATA_OFFSET } /// The raw SMBIOS data this structure is wrapping pub fn raw_smbios_data(&self) -> &[u8] { self.windows_header.as_slice() } /// Used20CallingMethod pub fn used20_calling_method(&self) -> u8 { self.windows_header[WinSMBiosData::USED20_CALLING_METHOD_OFFSET] } /// SMBIOS major version pub fn smbios_major_version(&self) -> u8 { self.windows_header[WinSMBiosData::SMBIOS_MAJOR_VERSION_OFFSET] } /// SMBIOS minor version pub fn smbios_minor_version(&self) -> u8 { self.windows_header[WinSMBiosData::SMBIOS_MINOR_VERSION_OFFSET] } /// DMI revision pub fn dmi_revision(&self) -> u8 { self.windows_header[WinSMBiosData::DMI_REVISION_OFFSET] } fn version_from_raw_header(windows_header: &Vec) -> SMBiosVersion { SMBiosVersion { major: windows_header[WinSMBiosData::SMBIOS_MAJOR_VERSION_OFFSET], minor: windows_header[WinSMBiosData::SMBIOS_MINOR_VERSION_OFFSET], revision: windows_header[WinSMBiosData::DMI_REVISION_OFFSET], } } /// Length of the smbios table data pub fn table_data_length(&self) -> u32 { let slice = self .windows_header .get( WinSMBiosData::TABLE_DATA_LENGTH_OFFSET ..WinSMBiosData::TABLE_DATA_LENGTH_OFFSET + 4, ) .unwrap(); u32::from_le_bytes( slice .try_into() .expect("array length does not match type width"), ) } } impl fmt::Debug for WinSMBiosData { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct(std::any::type_name::()) .field("used20_calling_method", &self.used20_calling_method()) .field("smbios_major_version", &self.smbios_major_version()) .field("smbios_minor_version", &self.smbios_minor_version()) .field("dmi_revision", &self.dmi_revision()) .field("table_data_length", &self.table_data_length()) .field("smbios_data", &self.smbios_data) .finish() } } impl Serialize for WinSMBiosData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("WinSMBiosData", 6)?; state.serialize_field("used20_calling_method", &self.used20_calling_method())?; state.serialize_field("smbios_major_version", &self.smbios_major_version())?; state.serialize_field("smbios_minor_version", &self.smbios_minor_version())?; state.serialize_field("dmi_revision", &self.dmi_revision())?; state.serialize_field("table_data_length", &self.table_data_length())?; state.serialize_field("smbios_data", &self.smbios_data)?; state.end() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_is_valid_raw_smbios_data() { // Good structure (lengths are correct) let struct_data = vec![0x00u8, 0x03, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAB]; assert!(WinSMBiosData::is_valid_win_smbios_data(&struct_data)); // Bad structure (too short) let struct_data = vec![0x00u8, 0x03, 0x03]; assert!(!WinSMBiosData::is_valid_win_smbios_data(&struct_data)); // Bad structure (bad table data length) let struct_data = vec![0x00u8, 0x03, 0x03, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xAB]; assert!(!WinSMBiosData::is_valid_win_smbios_data(&struct_data)); } #[test] fn test_win_smbios_data_headers() { let raw_win_data = vec![0x00u8, 0x03, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]; let win_smbios_data = WinSMBiosData::new(raw_win_data).unwrap(); assert_eq!(win_smbios_data.used20_calling_method(), 0x00); assert_eq!(win_smbios_data.smbios_major_version(), 0x03); assert_eq!(win_smbios_data.smbios_minor_version(), 0x04); assert_eq!(win_smbios_data.dmi_revision(), 0x00); assert_eq!(win_smbios_data.table_data_length(), 0x01); } #[test] fn test_win_smbios_data_constructor() { let raw_win_data = vec![0x00u8, 0x03, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0xFF]; let win_smbios_data = WinSMBiosData::new(raw_win_data.clone()).unwrap(); assert_eq!( win_smbios_data.windows_header.as_slice(), &raw_win_data[..8] ); } } smbios-lib-0.9.2/tests/integration_test.rs000064400000000000000000000061441046102023000167730ustar 00000000000000use smbioslib::*; #[cfg(target_family = "windows")] #[test] fn windows_dump() { match load_windows_smbios_data() { Ok(windows_data) => { println!("windows_data: {:#?}", windows_data); } Err(err) => panic!("failure: {:?}", err), } } #[test] fn retrieve_system_uuid() { match table_load_from_device() { Ok(data) => match data.find_map(|sys_info: SMBiosSystemInformation| sys_info.uuid()) { Some(uuid) => println!("System Information UUID == {:?}", uuid), None => println!("No System Information (Type 1) structure found with a UUID field"), }, Err(err) => println!("failure: {:?}", err), } } #[test] fn print_all_memory_devices() { match table_load_from_device() { Ok(data) => { for memory_device in data.collect::() { println!("{:#?}", memory_device); } } Err(err) => println!("failure: {:?}", err), } } /// Finds an associated struct by handle #[test] fn struct_struct_association() { match table_load_from_device() { Ok(data) => match data.first::() { Some(first_memory_device) => { let handle = first_memory_device.physical_memory_array_handle().unwrap(); match data.find_by_handle(&handle) { Some(undefined_struct) => { let physical_memory_array = undefined_struct.defined_struct(); println!("{:#?}", physical_memory_array) } None => println!("No Physical Memory Array (Type 16) structure found"), } } None => println!("No Memory Device (Type 17) structure found"), }, Err(err) => println!("failure: {:?}", err), } } /// Test find() - finds the first populated CPU socket #[test] fn find_first_cpu() { match table_load_from_device() { Ok(data) => match data.find(|proc_info: &SMBiosProcessorInformation| match (proc_info.status(), proc_info.processor_type()) { (Some(status), Some(proc_type)) => { status.socket_populated() && proc_type.value == ProcessorType::CentralProcessor } _ => { false } }) { Some(first_cpu) => { println!("First populated CPU socket: {:#?}", first_cpu); } None => println!("No Processor Information (Type 4) structure found that is a CPU with a populated socket"), }, Err(err) => println!("Table load failure: {:?}", err), } } /// Test filter() - finds all populated memory sockets #[test] fn find_installed_memory() { match table_load_from_device() { Err(err) => println!("Table load failure: {:?}", err), Ok(data) => data .filter( |memory_device: &SMBiosMemoryDevice| match memory_device.size() { Some(size) => size != MemorySize::NotInstalled, _ => false, }, ) .for_each(|installed_memory| println!("Installed memory: {:#X?}", installed_memory)), } } smbios-lib-0.9.2/tests/jeffgerlap_3_2_0.dat000064400000000000000000000020671046102023000165240ustar 00000000000000/L1 - CacheL2 - CacheL3 - Cache0kdAkFP5Advanced Micro Devices, Inc.AMD Ryzen 7 Microsoft Surface (R) EditionUnknownUnknownUnknown(@@ @` ` DIMM 0P0 CHANNEL AHynix00000000HMAA1GS6CMR6N-UH #  (  @@ @` ` DIMM 0P0 CHANNEL BHynix00000000HMAA1GS6CMR6N-UH #    Microsoft Corporation1.2238.14001/16/2020?RNj*bMicrosoft CorporationSurface Laptop 3124I:00044T:000M:0400000B:07023078193757Surface_Laptop_3_1873Surface Microsoft Corporation023078193757 Microsoft CorporationSurface Laptop 3A009250100J1939A_SHA_3b09242554245a33187ac1e6d7f7e5d2cca80653