├── .github └── workflows │ └── ccpp.yml ├── .gitignore ├── CMakeLists.txt ├── README.md ├── LICENSE ├── smbios.h ├── smbios_decode.c └── smbios.c /.github/workflows/ccpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-22.04 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: dependencies 13 | run: sudo apt-get install cmake make gcc 14 | - name: prepare 15 | run: cmake . 16 | - name: compilation 17 | run: make 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(smbios-parser) 3 | 4 | if (CMAKE_BUILD_TYPE STREQUAL "") 5 | message(STATUS "No build type selected, default to 'Release'") 6 | set(CMAKE_BUILD_TYPE "Release") 7 | endif() 8 | 9 | if (UNIX) 10 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wfatal-errors -fvisibility=hidden -Wfatal-errors -pedantic -std=c99 -Wl,--no-undefined -fPIC -Wall -Wextra -Wconversion -Werror=return-type -Werror=incompatible-pointer-types -Werror=sign-compare -Werror=sign-conversion") 11 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s -O3") 12 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -O0") 13 | 14 | set(ENABLE_SANITIZER OFF CACHE BOOL "Enable address sanitizer") 15 | if (ENABLE_SANITIZER) 16 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") 17 | endif() 18 | endif() 19 | 20 | add_library(smbios_static STATIC "smbios.c") 21 | target_include_directories(smbios_static PUBLIC "include") 22 | set_target_properties(smbios_static PROPERTIES 23 | OUTPUT_NAME "smbios" 24 | ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" 25 | PREFIX "lib" ) 26 | 27 | add_library(smbios_shared SHARED "smbios.c") 28 | target_compile_definitions(smbios_shared PRIVATE LIB_EXPORT) 29 | target_include_directories(smbios_shared PUBLIC "include") 30 | set_target_properties(smbios_shared PROPERTIES 31 | OUTPUT_NAME "smbios" 32 | LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" 33 | PREFIX "lib" ) 34 | 35 | add_executable(smbios_decode "smbios_decode.c") 36 | target_link_libraries(smbios_decode smbios_static) 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # smbios-parser 2 | 3 | Small C99 and C++98 library to parse SMBIOS information. 4 | 5 | The [SMBIOS](https://www.dmtf.org/standards/smbios) (System Management BIOS) is a standard specification that specifies how system vendors present management information about their products. It extends the BIOS interface on Intel architecture systems and allow operating systems (or programs) to retrieve information about the hardware without needing to probe it directly. 6 | 7 | This library is a small and standalone implementation of the specification for C and C++ applications. You can also use the shared library with any C-compatible programming language (i.e. Python, Go, Java). 8 | 9 | ## Usage 10 | 11 | The library can be used in C and C++ applications in the following ways: 12 | 13 | * As a static or shared library; 14 | * Copying the files `smbios.h` and `smbios.c` into your project. 15 | 16 | Once selected the preferred integration method, the library can be used as follows: 17 | 18 | ```c 19 | #include 20 | 21 | int main(int argc, char *argv[]) 22 | { 23 | (void) argc; 24 | (void) argv; 25 | 26 | // Get SMBIOS information using a custom function. 27 | // An example in C for Windows and Linux can be found 28 | // in 'smbios_decode.c'. 29 | uint8_t *data = NULL; 30 | size_t size = 0; 31 | if (!get_dmi_data("/sys/firmware/dmi/tables", &data, &size)) 32 | return 1; 33 | 34 | // initialize the parser (the desired SMBIOS version is 3.0) 35 | struct ParserContext context; 36 | if (smbios_initialize(&context, data, size, SMBIOS_3_0) != SMBERR_OK) 37 | { 38 | free(data); 39 | return 1; 40 | } 41 | 42 | // iterate over the SMBIOS entries 43 | const struct Entry *entry = NULL; 44 | while (smbios_next(&context, &entry) == SMBERR_OK) 45 | { 46 | // do something with the current entry 47 | } 48 | 49 | free(data); 50 | 51 | return 0; 52 | } 53 | ``` 54 | 55 | The pointer to the current SMBIOS entry is stored in the variable specified as the second parameter of the `smbios_next` function. The entry is defined by the structure `Entry` and some of its most important fields are: 56 | 57 | * **type**: Entry type, as defined in the SMBIOS specification; 58 | * **handle**: Entry handle, a unique 16-bit number in the range 0 to 0FFFEh (for version 2.0) or 0 to 0FEFFh (for version 2.1 and later); 59 | * **data**: Union with the actual formatted data of the entry for each supported type. Supported types are listed in the `EntryType` enumeration. The table bellow shows the supported types and the corresponding field in the `data` union. If the entry type is not supported, you can still read the data from `rawdata` field. 60 | * **rawdata**: Raw SMBIOS data of the entry (header and data itself). 61 | * **length**: Length of the SMBIOS data in `rawdata` field. 62 | * **strings**: Pointer to the start of the string table; 63 | * **string_count**: Number of strings in the string table. 64 | 65 | |Type|Field| 66 | |---|---| 67 | |TYPE_BIOS_INFO | bios_info | 68 | |TYPE_SYSTEM_INFO | system_info | 69 | |TYPE_BASEBOARD_INFO | baseboard_info | 70 | |TYPE_SYSTEM_ENCLOSURE | system_enclosure | 71 | |TYPE_PROCESSOR_INFO | processor_info | 72 | |TYPE_PORT_CONNECTOR | port_connector | 73 | |TYPE_SYSTEM_SLOT | system_slot | 74 | |TYPE_OEM_STRINGS | oem_strings | 75 | |TYPE_PHYSICAL_MEMORY_ARRAY | physical_memory_array | 76 | |TYPE_MEMORY_DEVICE | memory_device | 77 | |TYPE_MEMORY_ARRAY_MAPPED_ADDRESS | memory_array_mapped_address | 78 | |TYPE_MEMORY_DEVICE_MAPPED_ADDRESS | memory_device_mapped_address | 79 | |TYPE_SYSTEM_BOOT_INFO | system_boot_info | 80 | |TYPE_MANAGEMENT_DEVICE | management_device | 81 | |TYPE_MANAGEMENT_DEVICE_COMPONENT | management_device_component | 82 | |TYPE_MANAGEMENT_DEVICE_THRESHOLD_DATA | management_device_threshold_data | 83 | |TYPE_ONBOARD_DEVICES_EXTENDED_INFO | onboard_devices_extended_info | 84 | 85 | The library do not make heap allocations; everything is done in-place using the provided SMBIOS buffer and the context. 86 | 87 | ## API 88 | 89 | The following functions are available. 90 | 91 | ### smbios_initialize 92 | 93 | `int smbios_initialize(struct ParserContext *context, const uint8_t *data, size_t size, int version )` 94 | 95 | Initialize the SMBIOS parser. 96 | 97 | If the actual version of the SMBIOS data is smaller than the value of the parameter `version`, the parser will use the version of the SMBIOS data. Fields related to SMBIOS versions not selected will be left blank. Valid values are the ones defined in the enumeration `SpecVersion`. 98 | 99 | * **context**: Parser context. 100 | * **data**: SMBIOS data. 101 | * **size**: Size of the SMBIOS data. 102 | * **version**: Preferred SMBIOS version. If set with `SMBIOS_ANY`, the latest version will be used (currently 3.0). 103 | 104 | The function returns SMBERR_OK on success or a negative error code. 105 | 106 | ### smbios_next 107 | 108 | `int smbios_next(struct ParserContext *context, const struct Entry **entry)` 109 | 110 | Get the next SMBIOS entry. 111 | 112 | Calling this function invalidates any previously returned entry. 113 | 114 | * **context**: Parser context. 115 | * **entry**: Pointer to the entry. 116 | 117 | The function returns SMBERR_OK on success or a negative error code. 118 | 119 | ### smbios_reset 120 | 121 | `int smbios_reset(struct ParserContext *context)` 122 | 123 | Reset the SMBIOS parser and let it start from the beginning. 124 | 125 | If the parser failed (e.g. invalid SMBIOS data), calling this function will fail too. 126 | 127 | * **context**: Parser context. 128 | 129 | The function returns SMBERR_OK on success or a negative error code. 130 | 131 | ### smbios_get_version 132 | 133 | `int smbios_get_version(struct ParserContext *context, int *selected, int *original)` 134 | 135 | Returns the selected and/or the original SMBIOS versions. 136 | 137 | * **context**: Parser context. 138 | * **selected**: `(optional)` Selected version used to parse the SMBIOS data. 139 | * **original**: `(optional)` Version of the SMBIOS data. 140 | 141 | The function returns SMBERR_OK on success or a negative error code. 142 | 143 | ### smbios_get_string 144 | 145 | `const char *smbios_get_string( const struct Entry *entry, int index )` 146 | 147 | Returns a string from the SMBIOS entry. 148 | 149 | Fields in the entry that reference a string are automatically set with the corresponding string pointer. However, some entry types have an arbitrary number of strings not pointed by entry fields (e.g. the `OEMStrings` entry type). In this case, you can use this function to retrieve them. 150 | 151 | This is a utility function to retrieve a string from the SMBIOS entry. The function will iterate over the strings in the SMBIOS entry and return the string with the given index, starting from 1. If the index is out of range, the function will return `NULL`. 152 | 153 | If you want to avoid the overhead of the iteration for each call, you can access the string table directly. The start of the string table is set in the field `strings` of the entry. Each string is terminated with a null (00h) byte and the table is terminated with an additional null (00h) byte. The amount of strings is given in the field `string_count` of the entry. 154 | 155 | * **entry**: SMBIOS entry. 156 | * **index**: Index of the string, starting from 1. 157 | 158 | The function returns the string associated with the given index or `NULL` in case of error. 159 | 160 | ## License 161 | 162 | The library is distributed under [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0). 163 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /smbios.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2024 Bruno Costa 3 | * https://github.com/brunexgeek/smbios-parser 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #pragma once 19 | 20 | #define SMBIOS_STRING(name) uint8_t name##_; const char * name 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #if defined(WIN32) || defined(_WIN32) || defined(WINNT) || defined(_WINNT) || defined(WIN64) || defined(_WIN64) 27 | #undef SMBIOS_WINDOWS 28 | #define SMBIOS_WINDOWS 1 29 | #endif 30 | 31 | #undef SMBIOS_EXPORT 32 | #ifdef LIB_EXPORT 33 | #ifdef SMBIOS_WINDOWS 34 | #define SMBIOS_EXPORT __declspec(dllexport) 35 | #else 36 | #define SMBIOS_EXPORT __attribute__ ((visibility("default"))) 37 | #endif 38 | #else 39 | #define SMBIOS_EXPORT 40 | #endif 41 | 42 | #ifdef __cplusplus 43 | #define SMBIOS_CONSTEXPR constexpr 44 | #else 45 | #include 46 | #define SMBIOS_CONSTEXPR const 47 | #endif 48 | 49 | static SMBIOS_CONSTEXPR int SMBERR_OK = 0; 50 | static SMBIOS_CONSTEXPR int SMBERR_INVALID_ARGUMENT = -1; 51 | static SMBIOS_CONSTEXPR int SMBERR_INVALID_DATA = -2; 52 | static SMBIOS_CONSTEXPR int SMBERR_END_OF_STREAM = -3; 53 | 54 | enum EntryType 55 | { 56 | TYPE_BIOS_INFO = 0, 57 | TYPE_SYSTEM_INFO = 1, 58 | TYPE_BASEBOARD_INFO = 2, 59 | TYPE_SYSTEM_ENCLOSURE = 3, 60 | TYPE_PROCESSOR_INFO = 4, 61 | TYPE_PORT_CONNECTOR = 8, 62 | TYPE_SYSTEM_SLOT = 9, 63 | TYPE_OEM_STRINGS = 11, 64 | TYPE_PHYSICAL_MEMORY_ARRAY = 16, 65 | TYPE_MEMORY_DEVICE = 17, 66 | TYPE_MEMORY_ARRAY_MAPPED_ADDRESS = 19, 67 | TYPE_MEMORY_DEVICE_MAPPED_ADDRESS = 20, 68 | TYPE_SYSTEM_BOOT_INFO = 32, 69 | TYPE_MANAGEMENT_DEVICE = 34, 70 | TYPE_MANAGEMENT_DEVICE_COMPONENT = 35, 71 | TYPE_MANAGEMENT_DEVICE_THRESHOLD_DATA = 36, 72 | TYPE_ONBOARD_DEVICES_EXTENDED_INFO = 41, 73 | }; 74 | 75 | struct BiosInfo 76 | { 77 | // 2.0+ 78 | SMBIOS_STRING(Vendor); 79 | SMBIOS_STRING(BIOSVersion); 80 | uint16_t BIOSStartingAddressSegment; 81 | SMBIOS_STRING(BIOSReleaseDate); 82 | uint8_t BIOSROMSize; 83 | uint8_t BIOSCharacteristics[8]; 84 | // 2.4+ 85 | uint8_t BIOSCharacteristicsExtensionBytes[2]; 86 | uint8_t SystemBIOSMajorRelease; 87 | uint8_t SystemBIOSMinorRelease; 88 | uint8_t EmbeddedControlerFirmwareMajorRelease; 89 | uint8_t EmbeddedControlerFirmwareMinorRelease; 90 | }; 91 | 92 | struct SystemInfo 93 | { 94 | // 2.0+ 95 | SMBIOS_STRING(Manufacturer); 96 | SMBIOS_STRING(ProductName); 97 | SMBIOS_STRING(Version); 98 | SMBIOS_STRING(SerialNumber); 99 | // 2.1+ 100 | uint8_t UUID[16]; 101 | uint8_t WakeupType; 102 | // 2.4+ 103 | SMBIOS_STRING(SKUNumber); 104 | SMBIOS_STRING(Family); 105 | }; 106 | 107 | struct BaseboardInfo 108 | { 109 | // 2.0+ 110 | SMBIOS_STRING(Manufacturer); 111 | SMBIOS_STRING(Product); 112 | SMBIOS_STRING(Version); 113 | SMBIOS_STRING(SerialNumber); 114 | SMBIOS_STRING(AssetTag); 115 | uint8_t FeatureFlags; 116 | SMBIOS_STRING(LocationInChassis); 117 | uint16_t ChassisHandle; 118 | uint8_t BoardType; 119 | uint8_t NumberOfContainedObjectHandles; 120 | uint16_t *ContainedObjectHandles; 121 | }; 122 | 123 | struct SystemEnclosure 124 | { 125 | // 2.0+ 126 | SMBIOS_STRING(Manufacturer); 127 | uint8_t Type; 128 | SMBIOS_STRING(Version); 129 | SMBIOS_STRING(SerialNumber); 130 | SMBIOS_STRING(AssetTag); 131 | // 2.1+ 132 | uint8_t BootupState; 133 | uint8_t PowerSupplyState; 134 | uint8_t ThermalState; 135 | uint8_t SecurityStatus; 136 | // 2.3+ 137 | uint32_t OEMdefined; 138 | uint8_t Height; 139 | uint8_t NumberOfPowerCords; 140 | uint8_t ContainedElementCount; 141 | uint8_t ContainedElementRecordLength; 142 | const uint8_t *ContainedElements; 143 | // 2.7+ 144 | SMBIOS_STRING(SKUNumber); 145 | }; 146 | 147 | struct ProcessorInfo 148 | { 149 | // 2.0+ 150 | SMBIOS_STRING(SocketDesignation); 151 | uint8_t ProcessorType; 152 | uint8_t ProcessorFamily; 153 | SMBIOS_STRING(ProcessorManufacturer); 154 | uint8_t ProcessorID[8]; 155 | SMBIOS_STRING(ProcessorVersion); 156 | uint8_t Voltage; 157 | uint16_t ExternalClock; 158 | uint16_t MaxSpeed; 159 | uint16_t CurrentSpeed; 160 | uint8_t Status; 161 | uint8_t ProcessorUpgrade; 162 | // 2.1+ 163 | uint16_t L1CacheHandle; 164 | uint16_t L2CacheHandle; 165 | uint16_t L3CacheHandle; 166 | // 2.3+ 167 | SMBIOS_STRING(SerialNumber); 168 | SMBIOS_STRING(AssetTagNumber); 169 | SMBIOS_STRING(PartNumber); 170 | // 2.5+ 171 | uint8_t CoreCount; 172 | uint8_t CoreEnabled; 173 | uint8_t ThreadCount; 174 | uint16_t ProcessorCharacteristics; 175 | // 2.6+ 176 | uint16_t ProcessorFamily2; 177 | // 3.0+ 178 | uint16_t CoreCount2; 179 | uint16_t CoreEnabled2; 180 | uint16_t ThreadCount2; 181 | }; 182 | 183 | struct PortConnector 184 | { 185 | SMBIOS_STRING(InternalReferenceDesignator); 186 | uint8_t InternalConnectorType; 187 | SMBIOS_STRING(ExternalReferenceDesignator); 188 | uint8_t ExternalConnectorType; 189 | uint8_t PortType; 190 | }; 191 | 192 | struct SystemSlot 193 | { 194 | // 2.0+ 195 | SMBIOS_STRING(SlotDesignation); 196 | uint8_t SlotType; 197 | uint8_t SlotDataBusWidth; 198 | uint8_t CurrentUsage; 199 | uint8_t SlotLength; 200 | uint16_t SlotID; 201 | uint8_t SlotCharacteristics1; 202 | // 2.1+ 203 | uint8_t SlotCharacteristics2; 204 | // 2.6+ 205 | uint16_t SegmentGroupNumber; 206 | uint8_t BusNumber; 207 | uint8_t DeviceOrFunctionNumber; 208 | }; 209 | 210 | struct OemStrings 211 | { 212 | // 2.0+ 213 | uint8_t Count; 214 | const char *Values; 215 | }; 216 | 217 | struct PhysicalMemoryArray 218 | { 219 | // 2.1+ 220 | uint8_t Location; 221 | uint8_t Use; 222 | uint8_t ErrorCorrection; 223 | uint32_t MaximumCapacity; 224 | uint16_t ErrorInformationHandle; 225 | uint16_t NumberDevices; 226 | // 2.7+ 227 | uint64_t ExtendedMaximumCapacity; 228 | }; 229 | 230 | struct MemoryDevice 231 | { 232 | // 2.1+ 233 | uint16_t PhysicalArrayHandle; 234 | uint16_t ErrorInformationHandle; 235 | uint16_t TotalWidth; 236 | uint16_t DataWidth; 237 | uint16_t Size; 238 | uint8_t FormFactor; 239 | uint8_t DeviceSet; 240 | SMBIOS_STRING(DeviceLocator); 241 | SMBIOS_STRING(BankLocator); 242 | uint8_t MemoryType; 243 | uint16_t TypeDetail; 244 | // 2.3+ 245 | uint16_t Speed; 246 | SMBIOS_STRING(Manufacturer); 247 | SMBIOS_STRING(SerialNumber); 248 | SMBIOS_STRING(AssetTagNumber); 249 | SMBIOS_STRING(PartNumber); 250 | // 2.6+ 251 | uint8_t Attributes; 252 | // 2.7+ 253 | uint32_t ExtendedSize; 254 | uint16_t ConfiguredClockSpeed; 255 | // 2.8+ 256 | uint16_t MinimumVoltage; 257 | uint16_t MaximumVoltage; 258 | uint16_t ConfiguredVoltage; 259 | }; 260 | 261 | struct MemoryArrayMappedAddress 262 | { 263 | // 2.1+ 264 | uint32_t StartingAddress; 265 | uint32_t EndingAddress; 266 | uint16_t MemoryArrayHandle; 267 | uint8_t PartitionWidth; 268 | // 2.7+ 269 | uint64_t ExtendedStartingAddress; 270 | uint64_t ExtendedEndingAddress; 271 | }; 272 | 273 | struct MemoryDeviceMappedAddress 274 | { 275 | // 2.1+ 276 | uint32_t StartingAddress; 277 | uint32_t EndingAddress; 278 | uint16_t MemoryDeviceHandle; 279 | uint16_t MemoryArrayMappedAddressHandle; 280 | uint8_t PartitionRowPosition; 281 | uint8_t InterleavePosition; 282 | uint8_t InterleavedDataDepth; 283 | // 2.7+ 284 | uint64_t ExtendedStartingAddress; 285 | uint64_t ExtendedEndingAddress; 286 | }; 287 | 288 | struct SystemBootInfo 289 | { 290 | // 2.0+ 291 | uint8_t Reserved[6]; 292 | const uint8_t *BootStatus; 293 | }; 294 | 295 | struct ManagementDevice 296 | { 297 | // 2.0+ 298 | SMBIOS_STRING(Description); 299 | uint8_t Type; 300 | uint32_t Address; 301 | uint8_t AddressType; 302 | }; 303 | 304 | struct ManagementDeviceComponent 305 | { 306 | // 2.0+ 307 | SMBIOS_STRING(Description); 308 | uint16_t ManagementDeviceHandle; 309 | uint16_t ComponentHandle; 310 | uint16_t ThresholdHandle; 311 | }; 312 | 313 | struct ManagementDeviceThresholdData 314 | { 315 | // 2.0+ 316 | uint16_t LowerThresholdNonCritical; 317 | uint16_t UpperThresholdNonCritical; 318 | uint16_t LowerThresholdCritical; 319 | uint16_t UpperThresholdCritical; 320 | uint16_t LowerThresholdNonRecoverable; 321 | uint16_t UpperThresholdNonRecoverable; 322 | }; 323 | 324 | struct OnboardDevicesExtendedInfo 325 | { 326 | // 2.0+ 327 | SMBIOS_STRING(ReferenceDesignation); 328 | uint8_t DeviceType; 329 | uint8_t DeviceTypeInstance; 330 | uint16_t SegmentGroupNumber; 331 | uint8_t BusNumber; 332 | uint8_t DeviceOrFunctionNumber; 333 | }; 334 | 335 | struct Entry 336 | { 337 | // Entry type, as defined in the SMBIOS specification. 338 | uint8_t type; 339 | 340 | // Length of the entry (SMBIOS header and data). 341 | uint8_t length; 342 | 343 | /** 344 | * Entry handle, a unique 16-bit number in the range 0 to 0FFFEh (for version 2.0) 345 | * or 0 to 0FEFFh (for version 2.1 and later). 346 | */ 347 | uint16_t handle; 348 | 349 | /** 350 | * Union with the actual formatted data of the entry for each supported type. Supported types 351 | * are listed in the `EntryType` enumeration. If the entry type is not supported, you can still 352 | * read the data from `rawdata` field. 353 | */ 354 | union 355 | { 356 | struct BiosInfo bios_info; 357 | struct SystemInfo system_info; 358 | struct BaseboardInfo baseboard_info; 359 | struct SystemEnclosure system_enclosure; 360 | struct ProcessorInfo processor_info; 361 | struct PortConnector port_connector; 362 | struct SystemSlot system_slot; 363 | struct OemStrings oem_strings; 364 | struct PhysicalMemoryArray physical_memory_array; 365 | struct MemoryDevice memory_device; 366 | struct MemoryArrayMappedAddress memory_array_mapped_address; 367 | struct MemoryDeviceMappedAddress memory_device_mapped_address; 368 | struct SystemBootInfo system_boot_info; 369 | struct ManagementDevice management_device; 370 | struct ManagementDeviceComponent management_device_component; 371 | struct ManagementDeviceThresholdData management_device_threshold_data; 372 | struct OnboardDevicesExtendedInfo onboard_devices_extended_info; 373 | } data; 374 | 375 | // Raw SMBIOS data of the entry (header and data itself). 376 | const uint8_t *rawdata; 377 | 378 | // Pointer to the start of the string table; 379 | const char *strings; 380 | 381 | // Number of strings in the string table. 382 | int string_count; 383 | }; 384 | 385 | enum SpecVersion 386 | { 387 | SMBIOS_ANY = 0, 388 | SMBIOS_2_0 = 0x0200, 389 | SMBIOS_2_1 = 0x0201, 390 | SMBIOS_2_2 = 0x0202, 391 | SMBIOS_2_3 = 0x0203, 392 | SMBIOS_2_4 = 0x0204, 393 | SMBIOS_2_5 = 0x0205, 394 | SMBIOS_2_6 = 0x0206, 395 | SMBIOS_2_7 = 0x0207, 396 | SMBIOS_2_8 = 0x0208, 397 | SMBIOS_3_0 = 0x0300, 398 | }; 399 | 400 | struct ParserContext 401 | { 402 | // Pointer to extarnal buffer containing the SMBIOS data 403 | const uint8_t *data; 404 | // Total size of the SMBIOS data 405 | size_t size; 406 | // Pointer to the current byte in the SMBIOS data 407 | const uint8_t *ptr; 408 | // Pointer to the entry start 409 | const uint8_t *estart; 410 | // Pointer to one byte past the last byte of the entry 411 | const uint8_t *eend; 412 | // Selected SMBIOS version 413 | int sversion; 414 | // Original SMBIOS version 415 | int oversion; 416 | // Content of the current SMBIOS entry 417 | struct Entry entry; 418 | // true if parsing failed (cannot be reset) 419 | bool failed; 420 | }; 421 | 422 | #ifdef __cplusplus 423 | extern "C" { 424 | #endif 425 | 426 | /** 427 | * Initialize the SMBIOS parser. 428 | * 429 | * If the actual version of the SMBIOS data is smaller than the value of the parameter 430 | * 'version', the parser will use the version of the SMBIOS data. Fields related to 431 | * SMBIOS versions not selected will be left blank. Valid values are the ones defined 432 | * in the enumeration 'SpecVersion'. 433 | * 434 | * @param context Parser context. 435 | * @param data SMBIOS data. 436 | * @param size Size of the SMBIOS data. 437 | * @param version Preferred SMBIOS version. 438 | * @return SMBERR_OK on success or a negative error code. 439 | */ 440 | SMBIOS_EXPORT int smbios_initialize(struct ParserContext *context, const uint8_t *data, size_t size, int version ); 441 | 442 | /** 443 | * Get the next SMBIOS entry. 444 | * 445 | * Calling this function invalidates any previously returned entry. 446 | * 447 | * @param context Parser context. 448 | * @param entry Pointer to the entry. 449 | * @return SMBERR_OK on success or a negative error code. 450 | */ 451 | SMBIOS_EXPORT int smbios_next(struct ParserContext *context, const struct Entry **entry); 452 | 453 | /** 454 | * Reset the SMBIOS parser and let it start from the beginning. 455 | * 456 | * If the parser failed (e.g. invalid SMBIOS data), calling this function will fail too. 457 | * 458 | * @param context Parser context. 459 | * @return SMBERR_OK on success or a negative error code. 460 | */ 461 | SMBIOS_EXPORT int smbios_reset(struct ParserContext * context); 462 | 463 | /** 464 | * Returns the selected and/or the original SMBIOS versions. 465 | * 466 | * @param context Parser context. 467 | * @param selected (optional) Selected version used to parse the SMBIOS data. 468 | * @param original (optional) Version of the SMBIOS data. 469 | * @return SMBERR_OK on success or a negative error code. 470 | */ 471 | SMBIOS_EXPORT int smbios_get_version(struct ParserContext *context, int *selected, int *original); 472 | 473 | /** 474 | * Returns a string from the SMBIOS entry. 475 | * 476 | * Fields in the entry that reference a string are automatically set with the corresponding string pointer. 477 | * However, some entry types have an arbitrary number of strings not pointed by entry fields (e.g. the 478 | * 'OEMStrings' entry type). In this case, you can use this function to retrieve them. 479 | * 480 | * This is a utility function to retrieve a string from the SMBIOS entry. The function will iterate over the 481 | * strings in the SMBIOS entry and return the string with the given index, starting from 1. If the index is 482 | * out of range, the function will return NULL. 483 | * 484 | * If you want to avoid the overhead of the iteration for each call, you can access the string table directly. 485 | * The start of the string table is set in the field 'strings' of the entry. Each string is terminated with a 486 | * null (00h) byte and the table is terminated with an additional null (00h) byte. The amount of strings is 487 | * given in the field 'string_count' of the entry. 488 | * 489 | * @param entry SMBIOS entry. 490 | * @param index Index of the string, starting from 1. 491 | * @return String associated with the given index or NULL in case of error. 492 | */ 493 | SMBIOS_EXPORT const char *smbios_get_string( const struct Entry *entry, int index ); 494 | 495 | #ifdef __cplusplus 496 | } // extern "C" 497 | #endif 498 | 499 | #undef SMBIOS_STRING 500 | #undef SMBIOS_WINDOWS 501 | #undef SMBIOS_EXPORT 502 | 503 | 504 | -------------------------------------------------------------------------------- /smbios_decode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2024 Bruno Costa 3 | * https://github.com/brunexgeek/smbios-parser 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include "smbios.h" 22 | 23 | #ifdef _WIN32 24 | 25 | #include 26 | 27 | static bool get_dmi_data( uint8_t **buffer, size_t *size ) 28 | { 29 | const BYTE byteSignature[] = { 'B', 'M', 'S', 'R' }; 30 | const DWORD signature = *((DWORD*)byteSignature); 31 | 32 | // get the size of SMBIOS table 33 | *size = GetSystemFirmwareTable(signature, 0, NULL, 0); 34 | if (*size == 0) 35 | return false; 36 | *buffer = (uint8_t*) malloc(*size); 37 | if (*buffer == NULL) 38 | return false; 39 | // retrieve the SMBIOS table 40 | if (*size != GetSystemFirmwareTable(signature, 0, *buffer, *size)) 41 | { 42 | free(*buffer); 43 | return false; 44 | } 45 | return true; 46 | } 47 | 48 | #else 49 | 50 | static bool get_dmi_data( const char *path, uint8_t **buffer, size_t *size ) 51 | { 52 | FILE *input; 53 | char fileName[128]; 54 | 55 | // get the SMBIOS structures size 56 | snprintf(fileName, sizeof(fileName), "%s/DMI", path); 57 | struct stat info; 58 | if (stat(fileName, &info) != 0) 59 | return false; 60 | *size = (size_t) info.st_size + 32; 61 | *buffer = (uint8_t*) malloc(*size); 62 | if (*buffer == NULL) 63 | return false; 64 | 65 | // read SMBIOS structures 66 | input = fopen(fileName, "rb"); 67 | if (input == NULL) 68 | { 69 | free(*buffer); 70 | return false; 71 | } 72 | fread((char*) *buffer + 32, (size_t) info.st_size, 1, input); 73 | fclose(input); 74 | 75 | // read SMBIOS entry point 76 | snprintf(fileName, sizeof(fileName), "%s/smbios_entry_point", path); 77 | input = fopen(fileName, "rb"); 78 | if (input == NULL) 79 | { 80 | free(*buffer); 81 | return false; 82 | } 83 | fread((char*) *buffer, 32, 1, input); 84 | fclose(input); 85 | 86 | return true; 87 | } 88 | 89 | #endif 90 | 91 | static void hexdump( FILE *output, const uint8_t *buffer, size_t size ) 92 | { 93 | size_t i = 0; 94 | fputs("\t\t", output); 95 | for (; i < size; ++i) 96 | { 97 | if (i > 0 && (i % 16) == 0) 98 | fputs("\n\t\t", output); 99 | fprintf(output, "%02X ", (int) buffer[i]); 100 | } 101 | if (i != 17) 102 | fputs("\n", output); 103 | } 104 | 105 | bool printSMBIOS( struct ParserContext *parser, FILE *output ) 106 | { 107 | int sversion, oversion; 108 | if (smbios_get_version(parser, &sversion, &oversion) != SMBERR_OK) 109 | return false; 110 | 111 | fprintf(output, "Selected version: %d.%d\n", sversion >> 8, sversion & 0xFF); 112 | fprintf(output, " SMBIOS version: %d.%d\n", oversion >> 8, oversion & 0xFF); 113 | 114 | const struct Entry *entry = NULL; 115 | int result = 0; 116 | while (true) 117 | { 118 | result = smbios_next(parser, &entry); 119 | if (result != SMBERR_OK) 120 | break; 121 | 122 | fprintf(output, "Handle 0x%04X, DMI type %d, %d bytes\n", (int) entry->handle, (int) entry->type, (int) entry->length); 123 | 124 | if (entry->type == TYPE_BIOS_INFO) 125 | { 126 | if (sversion >= SMBIOS_2_0) 127 | { 128 | fprintf(output, "\tVendor: %s\n", entry->data.bios_info.Vendor); 129 | fprintf(output, "\tBIOSVersion: %s\n", entry->data.bios_info.BIOSVersion); 130 | fprintf(output, "\tBIOSStartingSegment: %X\n", (int) entry->data.bios_info.BIOSStartingAddressSegment); 131 | fprintf(output, "\tBIOSReleaseDate: %s\n", entry->data.bios_info.BIOSReleaseDate); 132 | fprintf(output, "\tBIOSROMSize: %d KiB\n", ((int) entry->data.bios_info.BIOSROMSize + 1) * 64); 133 | } 134 | if (sversion >= SMBIOS_2_4) 135 | { 136 | fprintf(output, "\tSystemBIOSMajorRelease: %d\n", (int) entry->data.bios_info.SystemBIOSMajorRelease); 137 | fprintf(output, "\tSystemBIOSMinorRelease: %d\n", (int) entry->data.bios_info.SystemBIOSMinorRelease); 138 | fprintf(output, "\tEmbeddedFirmwareMajorRelease: %d\n", (int) entry->data.bios_info.EmbeddedControlerFirmwareMajorRelease); 139 | fprintf(output, "\tEmbeddedFirmwareMinorRelease: %d\n", (int) entry->data.bios_info.EmbeddedControlerFirmwareMinorRelease); 140 | } 141 | fputs("\n", output); 142 | } 143 | else 144 | if (entry->type == TYPE_SYSTEM_INFO) 145 | { 146 | if (sversion >= SMBIOS_2_0) 147 | { 148 | fprintf(output, "\tManufacturer: %s\n", entry->data.system_info.Manufacturer); 149 | fprintf(output, "\tProductName: %s\n", entry->data.system_info.ProductName); 150 | fprintf(output, "\tVersion: %s\n", entry->data.system_info.Version); 151 | fprintf(output, "\tSerialNumber: %s\n", entry->data.system_info.SerialNumber); 152 | } 153 | if (sversion >= SMBIOS_2_1) 154 | { 155 | fputs("\tUUID:", output); 156 | for (int i = 0; i < 16; ++i) 157 | fprintf(output, " %02X", entry->data.system_info.UUID[i]); 158 | fputs("\n", output); 159 | } 160 | if (sversion >= SMBIOS_2_4) 161 | { 162 | fprintf(output, "\tSKUNumber: %s\n", entry->data.system_info.SKUNumber); 163 | fprintf(output, "\tFamily: %s\n", entry->data.system_info.Family); 164 | } 165 | fputs("\n", output); 166 | } 167 | else 168 | if (entry->type == TYPE_BASEBOARD_INFO) 169 | { 170 | if (sversion >= SMBIOS_2_0) 171 | { 172 | fprintf(output, "\tManufacturer: %s\n", entry->data.baseboard_info.Manufacturer); 173 | fprintf(output, "\tProduct Name: %s\n", entry->data.baseboard_info.Product); 174 | fprintf(output, "\tVersion: %s\n", entry->data.baseboard_info.Version); 175 | fprintf(output, "\tSerial Number: %s\n", entry->data.baseboard_info.SerialNumber); 176 | fprintf(output, "\tAsset Tag: %s\n", entry->data.baseboard_info.AssetTag); 177 | fprintf(output, "\tLocation In Chassis: %s\n", entry->data.baseboard_info.LocationInChassis); 178 | fprintf(output, "\tChassis Handle: %d\n", entry->data.baseboard_info.ChassisHandle); 179 | fprintf(output, "\tType: %d\n", (int) entry->data.baseboard_info.BoardType); 180 | } 181 | fputs("\n", output); 182 | } 183 | else 184 | if (entry->type == TYPE_SYSTEM_ENCLOSURE) 185 | { 186 | if (sversion >= SMBIOS_2_0) 187 | { 188 | fprintf(output, "\tManufacturer: %s\n", entry->data.system_enclosure.Manufacturer); 189 | fprintf(output, "\tVersion: %s\n", entry->data.system_enclosure.Version); 190 | fprintf(output, "\tSerialNumber: %s\n", entry->data.system_enclosure.SerialNumber); 191 | fprintf(output, "\tAssetTag: %s\n", entry->data.system_enclosure.AssetTag); 192 | } 193 | if (sversion >= SMBIOS_2_3) 194 | { 195 | fprintf(output, "\tContainedCount: %d\n", (int) entry->data.system_enclosure.ContainedElementCount); 196 | fprintf(output, "\tContainedLength: %d\n", (int) entry->data.system_enclosure.ContainedElementRecordLength); 197 | } 198 | if (sversion >= SMBIOS_2_7) 199 | { 200 | fprintf(output, "\tSKUNumber: %s\n", entry->data.system_enclosure.SKUNumber); 201 | } 202 | fputs("\n", output); 203 | } 204 | else 205 | if (entry->type == TYPE_PROCESSOR_INFO) 206 | { 207 | if (sversion >= SMBIOS_2_0) 208 | { 209 | fprintf(output, "\tSocketDesignation: %s\n", entry->data.processor_info.SocketDesignation); 210 | fprintf(output, "\tProcessorType: %d\n", (int) entry->data.processor_info.ProcessorType); 211 | fprintf(output, "\tProcessorFamily: %d\n", (int) entry->data.processor_info.ProcessorFamily); 212 | fprintf(output, "\tProcessorManufacturer: %s\n", entry->data.processor_info.ProcessorManufacturer); 213 | fprintf(output, "\tProcessorVersion: %s\n", entry->data.processor_info.ProcessorVersion); 214 | fputs("ProcessorID:", output); 215 | for (int i = 0; i < 8; ++i) 216 | fprintf(output, " %02X", entry->data.processor_info.ProcessorID[i]); 217 | fputs("\n", output); 218 | fprintf(output, "\tVoltage: %d\n", entry->data.processor_info.Voltage); 219 | fprintf(output, "\tExternalClock: %d\n", entry->data.processor_info.ExternalClock); 220 | fprintf(output, "\tMaxSpeed: %d\n", entry->data.processor_info.MaxSpeed); 221 | fprintf(output, "\tCurrentSpeed: %d\n", entry->data.processor_info.CurrentSpeed); 222 | fprintf(output, "\tStatus: %d\n", entry->data.processor_info.Status); 223 | fprintf(output, "\tProcessorUpgrade: %d\n", entry->data.processor_info.ProcessorUpgrade); 224 | } 225 | if (sversion >= SMBIOS_2_1) 226 | { 227 | fprintf(output, "\tL1CacheHandle: %d\n", entry->data.processor_info.L1CacheHandle); 228 | fprintf(output, "\tL2CacheHandle: %d\n", entry->data.processor_info.L2CacheHandle); 229 | fprintf(output, "\tL3CacheHandle: %d\n", entry->data.processor_info.L3CacheHandle); 230 | } 231 | if (sversion >= SMBIOS_2_3) 232 | { 233 | fprintf(output, "\tSerialNumber: %s\n", entry->data.processor_info.SerialNumber); 234 | fprintf(output, "\tAssetTagNumber: %s\n", entry->data.processor_info.AssetTagNumber); 235 | fprintf(output, "\tPartNumber: %s\n", entry->data.processor_info.PartNumber); 236 | } 237 | if (sversion >= SMBIOS_2_3) 238 | { 239 | fprintf(output, "\tSerialNumber: %s\n", entry->data.processor_info.SerialNumber); 240 | fprintf(output, "\tAssetTagNumber: %s\n", entry->data.processor_info.AssetTagNumber); 241 | fprintf(output, "\tPartNumber: %s\n", entry->data.processor_info.PartNumber); 242 | } 243 | if (sversion >= SMBIOS_2_6) 244 | { 245 | fprintf(output, "\tProcessorFamily2: %d\n", entry->data.processor_info.ProcessorFamily2); 246 | } 247 | if (sversion >= SMBIOS_3_0) 248 | { 249 | fprintf(output, "\tCoreCount2: %d\n", entry->data.processor_info.CoreCount2); 250 | fprintf(output, "\tCoreEnabled2: %d\n", entry->data.processor_info.CoreEnabled2); 251 | fprintf(output, "\tThreadCount2: %d\n", entry->data.processor_info.ThreadCount2); 252 | } 253 | fputs("\n", output); 254 | } 255 | else 256 | if (entry->type == TYPE_SYSTEM_SLOT) 257 | { 258 | if (sversion >= SMBIOS_2_0) 259 | { 260 | fprintf(output, "\tSlotDesignation: %s\n", entry->data.system_slot.SlotDesignation); 261 | fprintf(output, "\tSlotType: %d\n", (int) entry->data.system_slot.SlotType); 262 | fprintf(output, "\tSlotDataBusWidth: %d\n", (int) entry->data.system_slot.SlotDataBusWidth); 263 | fprintf(output, "\tSlotID: %d\n", (int) entry->data.system_slot.SlotID); 264 | } 265 | if (sversion >= SMBIOS_2_6) 266 | { 267 | fprintf(output, "\tSegmentGroupNumber: %d\n", entry->data.system_slot.SegmentGroupNumber); 268 | fprintf(output, "\tBusNumber: %d\n", (int) entry->data.system_slot.BusNumber); 269 | } 270 | fputs("\n", output); 271 | } 272 | else 273 | if (entry->type == TYPE_PHYSICAL_MEMORY_ARRAY) 274 | { 275 | if (sversion >= SMBIOS_2_1) 276 | { 277 | fprintf(output, "\tUse: %d\n", (int) entry->data.physical_memory_array.Use); 278 | fprintf(output, "\tNumberDevices: %d\n", entry->data.physical_memory_array.NumberDevices); 279 | fprintf(output, "\tMaximumCapacity: %d KiB\n", entry->data.physical_memory_array.MaximumCapacity); 280 | fprintf(output, "\tExtMaximumCapacity: %ld KiB\n", entry->data.physical_memory_array.ExtendedMaximumCapacity); 281 | } 282 | fputs("\n", output); 283 | } 284 | else 285 | if (entry->type == TYPE_MEMORY_DEVICE) 286 | { 287 | if (sversion >= SMBIOS_2_1) 288 | { 289 | fprintf(output, "\tDeviceLocator: %s\n", entry->data.memory_device.DeviceLocator); 290 | fprintf(output, "\tBankLocator: %s\n", entry->data.memory_device.BankLocator); 291 | } 292 | if (sversion >= SMBIOS_2_3) 293 | { 294 | fprintf(output, "\tSpeed: %d MHz\n", entry->data.memory_device.Speed); 295 | fprintf(output, "\tManufacturer: %s\n", entry->data.memory_device.Manufacturer); 296 | fprintf(output, "\tSerialNumber: %s\n", entry->data.memory_device.SerialNumber); 297 | fprintf(output, "\tAssetTagNumber: %s\n", entry->data.memory_device.AssetTagNumber); 298 | fprintf(output, "\tPartNumber: %s\n", entry->data.memory_device.PartNumber); 299 | fprintf(output, "\tSize: %d MiB\n", entry->data.memory_device.Size); 300 | fprintf(output, "\tExtendedSize: %d MiB\n", entry->data.memory_device.ExtendedSize); 301 | } 302 | if (sversion >= SMBIOS_2_7) 303 | { 304 | fprintf(output, "\tConfiguredClockSpeed: %d\n", entry->data.memory_device.ConfiguredClockSpeed); 305 | } 306 | fputs("\n", output); 307 | } 308 | else 309 | if (entry->type == TYPE_OEM_STRINGS) 310 | { 311 | if (sversion >= SMBIOS_2_0) 312 | { 313 | fprintf(output, "Count: %d\n", (int) entry->data.oem_strings.Count); 314 | fputs("\tStrings:\n", output); 315 | for (int i = 0; i < entry->data.oem_strings.Count; ++i) 316 | fprintf(output, "\t\t\"%s\"\n", smbios_get_string(entry, i)); 317 | } 318 | fputs("\n", output); 319 | } 320 | else 321 | if (entry->type == TYPE_PORT_CONNECTOR) 322 | { 323 | if (sversion >= SMBIOS_2_0) 324 | { 325 | fprintf(output, "\tInternalReferenceDesignator: %s\n", entry->data.port_connector.InternalReferenceDesignator); 326 | fprintf(output, "\tInternalConnectorType: %d\n", (int) entry->data.port_connector.InternalConnectorType); 327 | fprintf(output, "\tExternalReferenceDesignator: %s\n", entry->data.port_connector.ExternalReferenceDesignator); 328 | fprintf(output, "\tExternalConnectorType: %d\n", (int) entry->data.port_connector.ExternalConnectorType); 329 | fprintf(output, "\tPortType: %d\n", (int) entry->data.port_connector.PortType); 330 | } 331 | fputs("\n", output); 332 | } 333 | else 334 | if (entry->type == TYPE_MEMORY_ARRAY_MAPPED_ADDRESS) 335 | { 336 | if (sversion >= SMBIOS_2_1) 337 | { 338 | fprintf(output, "\tStartingAddress: %0X\n", entry->data.memory_array_mapped_address.StartingAddress); 339 | fprintf(output, "\tEndingAddress: %0X\n", entry->data.memory_array_mapped_address.EndingAddress); 340 | fprintf(output, "\tMemoryArrayHandle: %0X\n", entry->data.memory_array_mapped_address.MemoryArrayHandle); 341 | fprintf(output, "\tPartitionWidth: %0X\n", (int) entry->data.memory_array_mapped_address.PartitionWidth); 342 | } 343 | if (sversion >= SMBIOS_2_7) 344 | { 345 | fprintf(output, "\tExtendedStartingAddress: %lX\n", entry->data.memory_array_mapped_address.ExtendedStartingAddress); 346 | fprintf(output, "\tExtendedEndingAddress: %lX\n", entry->data.memory_array_mapped_address.ExtendedEndingAddress); 347 | } 348 | fputs("\n", output); 349 | } 350 | else 351 | if (entry->type == TYPE_MEMORY_DEVICE_MAPPED_ADDRESS) 352 | { 353 | if (sversion >= SMBIOS_2_1) 354 | { 355 | fprintf(output, "\tStartingAddress: %d\n", entry->data.memory_device_mapped_address.StartingAddress); 356 | fprintf(output, "\tEndingAddress: %d\n", entry->data.memory_device_mapped_address.EndingAddress); 357 | fprintf(output, "\tMemoryArrayHandle: %d\n", entry->data.memory_device_mapped_address.MemoryDeviceHandle); 358 | fprintf(output, "\tMemoryArrayMappedAddressHandle: %d\n", entry->data.memory_device_mapped_address.MemoryArrayMappedAddressHandle); 359 | fprintf(output, "\tPartitionRowPosition: %d\n", (int) entry->data.memory_device_mapped_address.PartitionRowPosition); 360 | fprintf(output, "\tInterleavePosition: %d\n", (int) entry->data.memory_device_mapped_address.InterleavePosition); 361 | fprintf(output, "\tInterleavedDataDepth: %d\n", (int) entry->data.memory_device_mapped_address.InterleavedDataDepth); 362 | } 363 | if (sversion >= SMBIOS_2_7) 364 | { 365 | fprintf(output, "\tExtendedStartingAddress: %ld\n", entry->data.memory_device_mapped_address.ExtendedStartingAddress); 366 | fprintf(output, "\tExtendedEndingAddress: %ld\n", entry->data.memory_device_mapped_address.ExtendedEndingAddress); 367 | } 368 | fputs("\n", output); 369 | } 370 | else 371 | if (entry->type == TYPE_MANAGEMENT_DEVICE) 372 | { 373 | if (sversion >= SMBIOS_2_0) 374 | { 375 | fprintf(output, "\tDescription: %s\n", entry->data.management_device.Description); 376 | fprintf(output, "\tType: %d\n", (int) entry->data.management_device.Type); 377 | fprintf(output, "\tAddress: %d\n", entry->data.management_device.Address); 378 | fprintf(output, "\tAddressType: %d\n", (int) entry->data.management_device.AddressType); 379 | } 380 | fputs("\n", output); 381 | } 382 | else 383 | if (entry->type == TYPE_MANAGEMENT_DEVICE_COMPONENT) 384 | { 385 | if (sversion >= SMBIOS_2_0) 386 | { 387 | fprintf(output, "\tDescription: %s\n", entry->data.management_device_component.Description); 388 | fprintf(output, "\tManagementDeviceHandle: %d\n", (int) entry->data.management_device_component.ManagementDeviceHandle); 389 | fprintf(output, "\tComponentHandle: %d\n", entry->data.management_device_component.ComponentHandle); 390 | fprintf(output, "\tThresholdHandle: %d\n", (int) entry->data.management_device_component.ThresholdHandle); 391 | } 392 | fputs("\n", output); 393 | } 394 | else 395 | if (entry->type == TYPE_MANAGEMENT_DEVICE_THRESHOLD_DATA) 396 | { 397 | if (sversion >= SMBIOS_2_0) 398 | { 399 | fprintf(output, "\tLowerThresholdNonCritical: %d\n", entry->data.management_device_threshold_data.LowerThresholdNonCritical); 400 | fprintf(output, "\tUpperThresholdNonCritical: %d\n", entry->data.management_device_threshold_data.UpperThresholdNonCritical); 401 | fprintf(output, "\tLowerThresholdCritical: %d\n", entry->data.management_device_threshold_data.LowerThresholdCritical); 402 | fprintf(output, "\tUpperThresholdCritical: %d\n", entry->data.management_device_threshold_data.UpperThresholdCritical); 403 | fprintf(output, "\tLowerThresholdNonRecoverable: %d\n", entry->data.management_device_threshold_data.LowerThresholdNonRecoverable); 404 | fprintf(output, "\tUpperThresholdNonRecoverable: %d\n", entry->data.management_device_threshold_data.UpperThresholdNonRecoverable); 405 | } 406 | fputs("\n", output); 407 | } 408 | else 409 | if (entry->type == TYPE_ONBOARD_DEVICES_EXTENDED_INFO) 410 | { 411 | if (sversion >= SMBIOS_2_0) 412 | { 413 | fprintf(output, "\tReferenceDesignation: %s\n", entry->data.onboard_devices_extended_info.ReferenceDesignation); 414 | fprintf(output, "\tDeviceType: %d\n", (int) entry->data.onboard_devices_extended_info.DeviceType); 415 | fprintf(output, "\tDeviceTypeInstance: %d\n", (int) entry->data.onboard_devices_extended_info.DeviceTypeInstance); 416 | fprintf(output, "\tSegmentGroupNumber: %d\n", entry->data.onboard_devices_extended_info.SegmentGroupNumber); 417 | fprintf(output, "\tBusNumber: %d\n", (int) entry->data.onboard_devices_extended_info.BusNumber); 418 | fprintf(output, "\tDeviceOrFunctionNumber: %d\n", (int) entry->data.onboard_devices_extended_info.DeviceOrFunctionNumber); 419 | } 420 | fputs("\n", output); 421 | } 422 | else 423 | if (entry->type == TYPE_SYSTEM_BOOT_INFO) 424 | { 425 | if (sversion >= SMBIOS_2_0) 426 | { 427 | fprintf(output, "\tBootStatus:\n\t\t"); 428 | if ((entry->length - 10) > 0) 429 | { 430 | int i = 0; 431 | for (; i < (entry->length - 10); ++i) 432 | { 433 | if (i > 0 && (i % 16) == 0) 434 | fputs("\n\t\t", output); 435 | fprintf(output, "%02X ", (int)entry->data.system_boot_info.BootStatus[i]); 436 | } 437 | if ((i % 16) != 0) 438 | fputs("\n", output); 439 | } 440 | } 441 | fputs("\n", output); 442 | } 443 | else 444 | { 445 | fputs("\tHeader and data:\n", output); 446 | if (entry->length > 0) 447 | hexdump(output, entry->rawdata, entry->length); 448 | 449 | const char *str = entry->strings; 450 | if (*str != 0) 451 | { 452 | fputs("\tStrings:\n", output); 453 | while (*str != 0) 454 | { 455 | fprintf(output, "\t\t\"%s\"\n", str); 456 | while (*str != 0) ++str; 457 | ++str; 458 | } 459 | } 460 | 461 | fputs("\n", output); 462 | } 463 | } 464 | 465 | if (result != SMBERR_END_OF_STREAM) 466 | { 467 | fputs("Invalid SMBIOS data", output); 468 | } 469 | 470 | return true; 471 | } 472 | 473 | int main(int argc, char ** argv) 474 | { 475 | uint8_t *buffer = NULL; 476 | size_t size = 0; 477 | bool result = false; 478 | 479 | #ifdef _WIN32 480 | 481 | result = get_dmi_data(&buffer, &size); 482 | 483 | #else 484 | 485 | const char *path = "/sys/firmware/dmi/tables"; 486 | if (argc == 2) 487 | path = argv[1]; 488 | printf("Using SMBIOS tables from %s\n", path); 489 | result = get_dmi_data(path, &buffer, &size); 490 | 491 | #endif 492 | 493 | if (!result) 494 | { 495 | fputs("Unable to open SMBIOS tables\n", stderr); 496 | return 1; 497 | } 498 | 499 | struct ParserContext parser; 500 | if (smbios_initialize(&parser, buffer, size, SMBIOS_ANY) == SMBERR_OK) 501 | printSMBIOS(&parser, stdout); 502 | else 503 | fputs("Invalid SMBIOS data\n", stderr); 504 | 505 | free(buffer); 506 | return 0; 507 | } 508 | -------------------------------------------------------------------------------- /smbios.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-2024 Bruno Costa 3 | * https://github.com/brunexgeek/smbios-parser 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "smbios.h" 19 | #include 20 | 21 | #define VALID_VERSION(x) (((x) >= SMBIOS_2_0 && (x) <= SMBIOS_2_8) || (x) == SMBIOS_3_0) 22 | 23 | static SMBIOS_CONSTEXPR size_t SMBIOS_HEADER_SIZE = 32; 24 | static SMBIOS_CONSTEXPR size_t SMBIOS_ENTRY_HEADER_SIZE = 4; 25 | 26 | #ifdef _WIN32 27 | 28 | #include 29 | 30 | struct RawSMBIOSData 31 | { 32 | BYTE Used20CallingMethod; 33 | BYTE SMBIOSMajorVersion; 34 | BYTE SMBIOSMinorVersion; 35 | BYTE DmiRevision; 36 | DWORD Length; 37 | BYTE SMBIOSTableData[]; 38 | }; 39 | #endif 40 | 41 | int smbios_initialize(struct ParserContext *context, const uint8_t *data, size_t size, int version ) 42 | { 43 | // we need at least the smbios header for now 44 | if (size < SMBIOS_HEADER_SIZE) 45 | return SMBERR_INVALID_DATA; 46 | 47 | memset(context, 0, sizeof(struct ParserContext)); 48 | context->ptr = NULL; 49 | context->sversion = VALID_VERSION(version) ? version : SMBIOS_3_0; 50 | 51 | // we have a valid SMBIOS entry point? 52 | #ifndef _WIN32 53 | context->data = data + SMBIOS_HEADER_SIZE; 54 | context->size = size - SMBIOS_HEADER_SIZE; 55 | 56 | if (data[0] == '_' && data[1] == 'S' && data[2] == 'M' && data[3] == '_') 57 | { 58 | // version 2.x 59 | 60 | // entry point length 61 | if (data[5] != 0x1F) 62 | return SMBERR_INVALID_DATA; 63 | // entry point revision 64 | if (data[10] != 0) 65 | return SMBERR_INVALID_DATA; 66 | // intermediate anchor string 67 | if (data[16] != '_' || data[17] != 'D' || data[18] != 'M' || data[19] != 'I' || data[20] != '_') 68 | return SMBERR_INVALID_DATA; 69 | 70 | // get the SMBIOS version 71 | context->oversion = data[6] << 8 | data[7]; 72 | } 73 | else 74 | if (data[0] == '_' && data[1] == 'S' && data[2] == 'M' && data[3] == '3' && data[4] == '_') 75 | { 76 | // version 3.x 77 | 78 | // entry point length 79 | if (data[6] != 0x18) 80 | return SMBERR_INVALID_DATA; 81 | // entry point revision 82 | if (data[10] != 0x01) 83 | return SMBERR_INVALID_DATA; 84 | 85 | // get the SMBIOS version 86 | context->oversion = (data[7] << 8 | data[8]); 87 | } 88 | else 89 | return SMBERR_INVALID_DATA; 90 | #else 91 | 92 | struct RawSMBIOSData *smBiosData = NULL; 93 | smBiosData = (struct RawSMBIOSData*) data; 94 | 95 | // get the SMBIOS version 96 | context->oversion = smBiosData->SMBIOSMajorVersion << 8 | smBiosData->SMBIOSMinorVersion; 97 | context->data = smBiosData->SMBIOSTableData; 98 | context->size = smBiosData->Length; 99 | #endif 100 | 101 | if (context->sversion > context->oversion) 102 | { 103 | if (!VALID_VERSION(context->oversion)) 104 | return SMBERR_INVALID_DATA; 105 | context->sversion = context->oversion; 106 | } 107 | 108 | return SMBERR_OK; 109 | } 110 | 111 | const char *smbios_get_string( const struct Entry *entry, int index ) 112 | { 113 | if (entry == NULL || index <= 0 || index > entry->string_count) 114 | return NULL; 115 | 116 | const char *ptr = entry->strings; 117 | for (int i = 1; *ptr != 0 && i < index; ++i) 118 | { 119 | while (*ptr != 0) ++ptr; 120 | ++ptr; 121 | } 122 | return ptr; 123 | } 124 | 125 | static const char *get_string( struct ParserContext *context, int index ) 126 | { 127 | return smbios_get_string(&context->entry, index); 128 | } 129 | 130 | int smbios_reset( struct ParserContext *context ) 131 | { 132 | if (context == NULL) 133 | return SMBERR_INVALID_ARGUMENT; 134 | if (context->data == NULL || context->failed) 135 | return SMBERR_INVALID_DATA; 136 | context->ptr = context->estart = context->eend = NULL; 137 | return SMBERR_OK; 138 | } 139 | 140 | static uint8_t read_uint8(struct ParserContext *context) 141 | { 142 | if (context->ptr + 1 >= context->eend) 143 | { 144 | context->failed = true; 145 | return 0; 146 | } 147 | return *context->ptr++; 148 | } 149 | 150 | static uint16_t read_uint16(struct ParserContext *context) 151 | { 152 | if (context->ptr + 2 >= context->eend) 153 | { 154 | context->failed = true; 155 | return 0; 156 | } 157 | 158 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 159 | uint16_t low = (uint16_t)context->ptr[0]; 160 | uint16_t high = (uint16_t)(context->ptr[1] << 8); 161 | #else 162 | uint16_t low = (uint16_t)context->ptr[1]; 163 | uint16_t high = (uint16_t)(context->ptr[0] << 8); 164 | #endif 165 | uint16_t value = high | low; 166 | 167 | context->ptr += 2; 168 | return value; 169 | } 170 | 171 | static uint32_t read_uint32(struct ParserContext *context) 172 | { 173 | if (context->ptr + 4 >= context->eend) 174 | { 175 | context->failed = true; 176 | return 0; 177 | } 178 | 179 | uint32_t value = 0; 180 | for (int i = 0; i < 4; ++i) 181 | { 182 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 183 | uint32_t v = (uint32_t)(context->ptr[i] << (i * 8)); 184 | #else 185 | uint32_t v = (uint32_t)(context->ptr[i] << ((3 - i) * 8)); 186 | #endif 187 | value |= v; 188 | } 189 | context->ptr += 4; 190 | return value; 191 | } 192 | 193 | static uint64_t read_uint64(struct ParserContext *context) 194 | { 195 | if (context->ptr + 8 >= context->eend) 196 | { 197 | context->failed = true; 198 | return 0; 199 | } 200 | 201 | uint64_t value = 0; 202 | for (int i = 0; i < 8; ++i) 203 | { 204 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 205 | uint64_t v = (uint64_t)(context->ptr[i] << (i * 8)); 206 | #else 207 | uint64_t v = (uint64_t)(context->ptr[i] << ((7 - i) * 8)); 208 | #endif 209 | value |= v; 210 | } 211 | 212 | context->ptr += 8; 213 | return value; 214 | } 215 | 216 | static void parse_bios_info(struct ParserContext *context) 217 | { 218 | // 2.0+ 219 | if (context->sversion >= SMBIOS_2_0) 220 | { 221 | context->entry.data.bios_info.Vendor_ = read_uint8(context); 222 | context->entry.data.bios_info.BIOSVersion_ = read_uint8(context); 223 | context->entry.data.bios_info.BIOSStartingAddressSegment = read_uint16(context); 224 | context->entry.data.bios_info.BIOSReleaseDate_ = read_uint8(context); 225 | context->entry.data.bios_info.BIOSROMSize = read_uint8(context); 226 | for (size_t i = 0; i < 8; ++i) 227 | context->entry.data.bios_info.BIOSCharacteristics[i] = read_uint8(context); 228 | 229 | context->entry.data.bios_info.Vendor = get_string(context, context->entry.data.bios_info.Vendor_); 230 | context->entry.data.bios_info.BIOSVersion = get_string(context, context->entry.data.bios_info.BIOSVersion_); 231 | context->entry.data.bios_info.BIOSReleaseDate = get_string(context, context->entry.data.bios_info.BIOSReleaseDate_); 232 | } 233 | // 2.4+ 234 | if (context->sversion >= SMBIOS_2_4) 235 | { 236 | context->entry.data.bios_info.BIOSCharacteristicsExtensionBytes[0] = read_uint8(context); 237 | context->entry.data.bios_info.BIOSCharacteristicsExtensionBytes[1] = read_uint8(context); 238 | context->entry.data.bios_info.SystemBIOSMajorRelease = read_uint8(context); 239 | context->entry.data.bios_info.SystemBIOSMinorRelease = read_uint8(context); 240 | context->entry.data.bios_info.EmbeddedControlerFirmwareMajorRelease = read_uint8(context); 241 | context->entry.data.bios_info.EmbeddedControlerFirmwareMinorRelease = read_uint8(context); 242 | } 243 | } 244 | 245 | static void parse_system_info(struct ParserContext *context) 246 | { 247 | // 2.0+ 248 | if (context->sversion >= SMBIOS_2_0) 249 | { 250 | context->entry.data.system_info.Manufacturer_ = read_uint8(context); 251 | context->entry.data.system_info.ProductName_ = read_uint8(context); 252 | context->entry.data.system_info.Version_ = read_uint8(context); 253 | context->entry.data.system_info.SerialNumber_ = read_uint8(context); 254 | 255 | context->entry.data.system_info.Manufacturer = get_string(context, context->entry.data.system_info.Manufacturer_); 256 | context->entry.data.system_info.ProductName = get_string(context, context->entry.data.system_info.ProductName_); 257 | context->entry.data.system_info.Version = get_string(context, context->entry.data.system_info.Version_); 258 | context->entry.data.system_info.SerialNumber = get_string(context, context->entry.data.system_info.SerialNumber_); 259 | } 260 | // 2.1+ 261 | if (context->sversion >= SMBIOS_2_1) 262 | { 263 | for(int i = 0 ; i < 16; ++i) 264 | context->entry.data.system_info.UUID[i] = read_uint8(context); 265 | context->entry.data.system_info.WakeupType = read_uint8(context); 266 | } 267 | // 2.4+ 268 | if (context->sversion >= SMBIOS_2_4) 269 | { 270 | context->entry.data.system_info.SKUNumber_ = read_uint8(context); 271 | context->entry.data.system_info.Family_ = read_uint8(context); 272 | 273 | context->entry.data.system_info.SKUNumber = get_string(context, context->entry.data.system_info.SKUNumber_); 274 | context->entry.data.system_info.Family = get_string(context, context->entry.data.system_info.Family_); 275 | } 276 | } 277 | 278 | static void parse_baseboard_info(struct ParserContext *context) 279 | { 280 | // 2.0+ 281 | if (context->sversion >= SMBIOS_2_0) 282 | { 283 | context->entry.data.baseboard_info.Manufacturer_ = read_uint8(context); 284 | context->entry.data.baseboard_info.Product_ = read_uint8(context); 285 | context->entry.data.baseboard_info.Version_ = read_uint8(context); 286 | context->entry.data.baseboard_info.SerialNumber_ = read_uint8(context); 287 | context->entry.data.baseboard_info.AssetTag_ = read_uint8(context); 288 | context->entry.data.baseboard_info.FeatureFlags = read_uint8(context); 289 | context->entry.data.baseboard_info.LocationInChassis_ = read_uint8(context); 290 | context->entry.data.baseboard_info.ChassisHandle = read_uint16(context); 291 | context->entry.data.baseboard_info.BoardType = read_uint8(context); 292 | context->entry.data.baseboard_info.NumberOfContainedObjectHandles = read_uint8(context); 293 | context->entry.data.baseboard_info.ContainedObjectHandles = (uint16_t*) context->ptr; 294 | context->ptr += context->entry.data.baseboard_info.NumberOfContainedObjectHandles * sizeof(uint16_t); 295 | 296 | context->entry.data.baseboard_info.Manufacturer = get_string(context, context->entry.data.baseboard_info.Manufacturer_); 297 | context->entry.data.baseboard_info.Product = get_string(context, context->entry.data.baseboard_info.Product_); 298 | context->entry.data.baseboard_info.Version = get_string(context, context->entry.data.baseboard_info.Version_); 299 | context->entry.data.baseboard_info.SerialNumber = get_string(context, context->entry.data.baseboard_info.SerialNumber_); 300 | context->entry.data.baseboard_info.AssetTag = get_string(context, context->entry.data.baseboard_info.AssetTag_); 301 | context->entry.data.baseboard_info.LocationInChassis = get_string(context, context->entry.data.baseboard_info.LocationInChassis_); 302 | } 303 | } 304 | 305 | static void parse_system_enclosure(struct ParserContext *context) 306 | { 307 | // 2.0+ 308 | if (context->sversion >= SMBIOS_2_0) 309 | { 310 | context->entry.data.system_enclosure.Manufacturer_ = read_uint8(context); 311 | context->entry.data.system_enclosure.Type = read_uint8(context); 312 | context->entry.data.system_enclosure.Version_ = read_uint8(context); 313 | context->entry.data.system_enclosure.SerialNumber_ = read_uint8(context); 314 | context->entry.data.system_enclosure.AssetTag_ = read_uint8(context); 315 | 316 | context->entry.data.system_enclosure.Manufacturer = get_string(context, context->entry.data.system_enclosure.Manufacturer_); 317 | context->entry.data.system_enclosure.Version = get_string(context, context->entry.data.system_enclosure.Version_); 318 | context->entry.data.system_enclosure.SerialNumber = get_string(context, context->entry.data.system_enclosure.SerialNumber_); 319 | context->entry.data.system_enclosure.AssetTag = get_string(context, context->entry.data.system_enclosure.AssetTag_); 320 | } 321 | // 2.1+ 322 | if (context->sversion >= SMBIOS_2_1) 323 | { 324 | context->entry.data.system_enclosure.BootupState = read_uint8(context); 325 | context->entry.data.system_enclosure.PowerSupplyState = read_uint8(context); 326 | context->entry.data.system_enclosure.ThermalState = read_uint8(context); 327 | context->entry.data.system_enclosure.SecurityStatus = read_uint8(context); 328 | } 329 | // 2.3+ 330 | if (context->sversion >= SMBIOS_2_3) 331 | { 332 | context->entry.data.system_enclosure.OEMdefined = read_uint32(context); 333 | context->entry.data.system_enclosure.Height = read_uint8(context); 334 | context->entry.data.system_enclosure.NumberOfPowerCords = read_uint8(context); 335 | context->entry.data.system_enclosure.ContainedElementCount = read_uint8(context); 336 | context->entry.data.system_enclosure.ContainedElementRecordLength = read_uint8(context); 337 | context->entry.data.system_enclosure.ContainedElements = context->ptr; 338 | context->ptr += context->entry.data.system_enclosure.ContainedElementCount * context->entry.data.system_enclosure.ContainedElementRecordLength; 339 | } 340 | // 2.7+ 341 | if (context->sversion >= SMBIOS_2_7) 342 | { 343 | context->entry.data.system_enclosure.SKUNumber_ = read_uint8(context); 344 | 345 | context->entry.data.system_enclosure.SKUNumber = get_string(context, context->entry.data.system_enclosure.SKUNumber_); 346 | } 347 | } 348 | 349 | static void parse_processor_info(struct ParserContext *context) 350 | { 351 | // 2.0+ 352 | if (context->sversion >= SMBIOS_2_0) 353 | { 354 | context->entry.data.processor_info.SocketDesignation_ = read_uint8(context); 355 | context->entry.data.processor_info.ProcessorType = read_uint8(context); 356 | context->entry.data.processor_info.ProcessorFamily = read_uint8(context); 357 | context->entry.data.processor_info.ProcessorManufacturer_ = read_uint8(context); 358 | for(int i = 0 ; i < 8; ++i) 359 | context->entry.data.processor_info.ProcessorID[i] = read_uint8(context); 360 | context->entry.data.processor_info.ProcessorVersion_ = read_uint8(context); 361 | context->entry.data.processor_info.Voltage = read_uint8(context); 362 | context->entry.data.processor_info.ExternalClock = read_uint16(context); 363 | context->entry.data.processor_info.MaxSpeed = read_uint16(context); 364 | context->entry.data.processor_info.CurrentSpeed = read_uint16(context); 365 | context->entry.data.processor_info.Status = read_uint8(context); 366 | context->entry.data.processor_info.ProcessorUpgrade = read_uint8(context); 367 | 368 | context->entry.data.processor_info.SocketDesignation = get_string(context, context->entry.data.processor_info.SocketDesignation_); 369 | context->entry.data.processor_info.ProcessorManufacturer = get_string(context, context->entry.data.processor_info.ProcessorManufacturer_); 370 | context->entry.data.processor_info.ProcessorVersion = get_string(context, context->entry.data.processor_info.ProcessorVersion_); 371 | } 372 | // 2.1+ 373 | if (context->sversion >= SMBIOS_2_1) 374 | { 375 | context->entry.data.processor_info.L1CacheHandle = read_uint16(context); 376 | context->entry.data.processor_info.L2CacheHandle = read_uint16(context); 377 | context->entry.data.processor_info.L3CacheHandle = read_uint16(context); 378 | } 379 | // 2.3+ 380 | if (context->sversion >= SMBIOS_2_3) 381 | { 382 | context->entry.data.processor_info.SerialNumber_ = read_uint8(context); 383 | context->entry.data.processor_info.AssetTagNumber_ = read_uint8(context); 384 | context->entry.data.processor_info.PartNumber_ = read_uint8(context); 385 | 386 | context->entry.data.processor_info.SerialNumber = get_string(context, context->entry.data.processor_info.SerialNumber_); 387 | context->entry.data.processor_info.AssetTagNumber = get_string(context, context->entry.data.processor_info.AssetTagNumber_); 388 | context->entry.data.processor_info.PartNumber = get_string(context, context->entry.data.processor_info.PartNumber_); 389 | } 390 | // 2.5+ 391 | if (context->sversion >= SMBIOS_2_5) 392 | { 393 | context->entry.data.processor_info.CoreCount = read_uint8(context); 394 | context->entry.data.processor_info.CoreEnabled = read_uint8(context); 395 | context->entry.data.processor_info.ThreadCount = read_uint8(context); 396 | context->entry.data.processor_info.ProcessorCharacteristics = read_uint16(context); 397 | } 398 | //2.6+ 399 | if (context->sversion >= SMBIOS_2_6) 400 | { 401 | context->entry.data.processor_info.ProcessorFamily2 = read_uint16(context); 402 | } 403 | //3.0+ 404 | if (context->sversion >= SMBIOS_3_0) 405 | { 406 | context->entry.data.processor_info.CoreCount2 = read_uint16(context); 407 | context->entry.data.processor_info.CoreEnabled2 = read_uint16(context); 408 | context->entry.data.processor_info.ThreadCount2 = read_uint16(context); 409 | } 410 | } 411 | 412 | static void parse_system_slot(struct ParserContext *context) 413 | { 414 | // 2.0+ 415 | if (context->sversion >= SMBIOS_2_0) 416 | { 417 | context->entry.data.system_slot.SlotDesignation_ = read_uint8(context); 418 | context->entry.data.system_slot.SlotType = read_uint8(context); 419 | context->entry.data.system_slot.SlotDataBusWidth = read_uint8(context); 420 | context->entry.data.system_slot.CurrentUsage = read_uint8(context); 421 | context->entry.data.system_slot.SlotLength = read_uint8(context); 422 | context->entry.data.system_slot.SlotID = read_uint16(context); 423 | context->entry.data.system_slot.SlotCharacteristics1 = read_uint8(context); 424 | 425 | context->entry.data.system_slot.SlotDesignation = get_string(context, context->entry.data.system_slot.SlotDesignation_); 426 | } 427 | // 2.1+ 428 | if (context->sversion >= SMBIOS_2_1) 429 | { 430 | context->entry.data.system_slot.SlotCharacteristics2 = read_uint8(context); 431 | } 432 | // 2.6+ 433 | if (context->sversion >= SMBIOS_2_6) 434 | { 435 | context->entry.data.system_slot.SegmentGroupNumber = read_uint16(context); 436 | context->entry.data.system_slot.BusNumber = read_uint8(context); 437 | context->entry.data.system_slot.DeviceOrFunctionNumber = read_uint8(context); 438 | } 439 | } 440 | 441 | static void parse_physical_memory_array(struct ParserContext *context) 442 | { 443 | // 2.1+ 444 | if (context->sversion >= SMBIOS_2_1) 445 | { 446 | context->entry.data.physical_memory_array.Location = read_uint8(context); 447 | context->entry.data.physical_memory_array.Use = read_uint8(context); 448 | context->entry.data.physical_memory_array.ErrorCorrection = read_uint8(context); 449 | context->entry.data.physical_memory_array.MaximumCapacity = read_uint32(context); 450 | context->entry.data.physical_memory_array.ErrorInformationHandle = read_uint16(context); 451 | context->entry.data.physical_memory_array.NumberDevices = read_uint16(context); 452 | } 453 | // 2.7+ 454 | if (context->sversion >= SMBIOS_2_7) 455 | { 456 | context->entry.data.physical_memory_array.ExtendedMaximumCapacity = read_uint64(context); 457 | } 458 | } 459 | 460 | static void parse_memory_device(struct ParserContext *context) 461 | { 462 | // 2.1+ 463 | if (context->sversion >= SMBIOS_2_1) 464 | { 465 | context->entry.data.memory_device.PhysicalArrayHandle = read_uint16(context); 466 | context->entry.data.memory_device.ErrorInformationHandle = read_uint16(context); 467 | context->entry.data.memory_device.TotalWidth = read_uint16(context); 468 | context->entry.data.memory_device.DataWidth = read_uint16(context); 469 | context->entry.data.memory_device.Size = read_uint16(context); 470 | context->entry.data.memory_device.FormFactor = read_uint8(context); 471 | context->entry.data.memory_device.DeviceSet = read_uint8(context); 472 | context->entry.data.memory_device.DeviceLocator_ = read_uint8(context); 473 | context->entry.data.memory_device.BankLocator_ = read_uint8(context); 474 | context->entry.data.memory_device.MemoryType = read_uint8(context); 475 | context->entry.data.memory_device.TypeDetail = read_uint16(context); 476 | 477 | context->entry.data.memory_device.DeviceLocator = get_string(context, context->entry.data.memory_device.DeviceLocator_); 478 | context->entry.data.memory_device.BankLocator = get_string(context, context->entry.data.memory_device.BankLocator_); 479 | } 480 | // 2.3+ 481 | if (context->sversion >= SMBIOS_2_3) 482 | { 483 | context->entry.data.memory_device.Speed = read_uint16(context); 484 | context->entry.data.memory_device.Manufacturer_ = read_uint8(context); 485 | context->entry.data.memory_device.SerialNumber_ = read_uint8(context); 486 | context->entry.data.memory_device.AssetTagNumber_ = read_uint8(context); 487 | context->entry.data.memory_device.PartNumber_ = read_uint8(context); 488 | 489 | context->entry.data.memory_device.Manufacturer = get_string(context, context->entry.data.memory_device.Manufacturer_); 490 | context->entry.data.memory_device.SerialNumber = get_string(context, context->entry.data.memory_device.SerialNumber_); 491 | context->entry.data.memory_device.AssetTagNumber = get_string(context, context->entry.data.memory_device.AssetTagNumber_); 492 | context->entry.data.memory_device.PartNumber = get_string(context, context->entry.data.memory_device.PartNumber_); 493 | } 494 | // 2.6+ 495 | if (context->sversion >= SMBIOS_2_6) 496 | { 497 | context->entry.data.memory_device.Attributes = read_uint8(context); 498 | } 499 | // 2.7+ 500 | if (context->sversion >= SMBIOS_2_7) 501 | { 502 | context->entry.data.memory_device.ExtendedSize = read_uint32(context); 503 | context->entry.data.memory_device.ConfiguredClockSpeed = read_uint16(context); 504 | } 505 | // 2.8+ 506 | if (context->sversion >= SMBIOS_2_8) 507 | { 508 | context->entry.data.memory_device.MinimumVoltage = read_uint16(context); 509 | context->entry.data.memory_device.MaximumVoltage = read_uint16(context); 510 | context->entry.data.memory_device.ConfiguredVoltage = read_uint16(context); 511 | } 512 | } 513 | 514 | static void parse_oem_strings(struct ParserContext *context) 515 | { 516 | // 2.0+ 517 | if (context->sversion >= SMBIOS_2_0) 518 | { 519 | context->entry.data.oem_strings.Count = read_uint8(context); 520 | context->entry.data.oem_strings.Values = (const char*) context->ptr; 521 | } 522 | } 523 | 524 | static void parse_port_connector(struct ParserContext *context) 525 | { 526 | // 2.0+ 527 | if (context->sversion >= SMBIOS_2_0) 528 | { 529 | context->entry.data.port_connector.InternalReferenceDesignator_ = read_uint8(context); 530 | context->entry.data.port_connector.InternalConnectorType = read_uint8(context); 531 | context->entry.data.port_connector.ExternalReferenceDesignator_ = read_uint8(context); 532 | context->entry.data.port_connector.ExternalConnectorType = read_uint8(context); 533 | context->entry.data.port_connector.PortType = read_uint8(context); 534 | 535 | context->entry.data.port_connector.ExternalReferenceDesignator = get_string(context, context->entry.data.port_connector.ExternalReferenceDesignator_); 536 | context->entry.data.port_connector.InternalReferenceDesignator = get_string(context, context->entry.data.port_connector.InternalReferenceDesignator_); 537 | } 538 | } 539 | 540 | static void parse_memory_array_mapped_address(struct ParserContext *context) 541 | { 542 | if (context->sversion >= SMBIOS_2_1) 543 | { 544 | context->entry.data.memory_array_mapped_address.StartingAddress = read_uint32(context); 545 | context->entry.data.memory_array_mapped_address.EndingAddress = read_uint32(context); 546 | context->entry.data.memory_array_mapped_address.MemoryArrayHandle = read_uint16(context); 547 | context->entry.data.memory_array_mapped_address.PartitionWidth = read_uint8(context); 548 | } 549 | if (context->sversion >= SMBIOS_2_7) 550 | { 551 | context->entry.data.memory_array_mapped_address.ExtendedStartingAddress = read_uint64(context); 552 | context->entry.data.memory_array_mapped_address.ExtendedEndingAddress = read_uint64(context); 553 | } 554 | } 555 | 556 | static void parse_memory_device_mapped_address(struct ParserContext *context) 557 | { 558 | if (context->sversion >= SMBIOS_2_1) 559 | { 560 | context->entry.data.memory_device_mapped_address.StartingAddress = read_uint32(context); 561 | context->entry.data.memory_device_mapped_address.EndingAddress = read_uint32(context); 562 | context->entry.data.memory_device_mapped_address.MemoryDeviceHandle = read_uint16(context); 563 | context->entry.data.memory_device_mapped_address.MemoryArrayMappedAddressHandle = read_uint16(context); 564 | context->entry.data.memory_device_mapped_address.PartitionRowPosition = read_uint8(context); 565 | context->entry.data.memory_device_mapped_address.InterleavePosition = read_uint8(context); 566 | context->entry.data.memory_device_mapped_address.InterleavedDataDepth = read_uint8(context); 567 | } 568 | if (context->sversion >= SMBIOS_2_7) 569 | { 570 | context->entry.data.memory_device_mapped_address.ExtendedStartingAddress = read_uint64(context); 571 | context->entry.data.memory_device_mapped_address.ExtendedEndingAddress = read_uint64(context); 572 | } 573 | } 574 | 575 | 576 | static void parse_system_boot_info(struct ParserContext *context) 577 | { 578 | if (context->sversion >= SMBIOS_2_0) 579 | { 580 | context->ptr += sizeof(context->entry.data.system_boot_info.Reserved); 581 | context->entry.data.system_boot_info.BootStatus = context->ptr; 582 | } 583 | } 584 | 585 | static void parse_management_device(struct ParserContext *context) 586 | { 587 | if (context->sversion >= SMBIOS_2_0) 588 | { 589 | context->entry.data.management_device.Description_ = read_uint8(context); 590 | context->entry.data.management_device.Type = read_uint8(context); 591 | context->entry.data.management_device.Address = read_uint32(context); 592 | context->entry.data.management_device.AddressType = read_uint8(context); 593 | 594 | context->entry.data.management_device.Description = get_string(context, context->entry.data.management_device.Description_); 595 | } 596 | } 597 | 598 | static void parse_management_device_component(struct ParserContext *context) 599 | { 600 | if (context->sversion >= SMBIOS_2_0) 601 | { 602 | context->entry.data.management_device_component.Description_ = read_uint8(context); 603 | context->entry.data.management_device_component.ManagementDeviceHandle = read_uint16(context); 604 | context->entry.data.management_device_component.ComponentHandle = read_uint16(context); 605 | context->entry.data.management_device_component.ThresholdHandle = read_uint16(context); 606 | 607 | context->entry.data.management_device_component.Description = get_string(context, context->entry.data.management_device_component.Description_); 608 | } 609 | } 610 | 611 | static void parse_management_device_threshold_data(struct ParserContext *context) 612 | { 613 | if (context->sversion >= SMBIOS_2_0) 614 | { 615 | context->entry.data.management_device_threshold_data.LowerThresholdNonCritical = read_uint16(context); 616 | context->entry.data.management_device_threshold_data.UpperThresholdNonCritical = read_uint16(context); 617 | context->entry.data.management_device_threshold_data.LowerThresholdCritical = read_uint16(context); 618 | context->entry.data.management_device_threshold_data.UpperThresholdCritical = read_uint16(context); 619 | context->entry.data.management_device_threshold_data.LowerThresholdNonRecoverable = read_uint16(context); 620 | context->entry.data.management_device_threshold_data.UpperThresholdNonRecoverable = read_uint16(context); 621 | } 622 | } 623 | 624 | 625 | static void parse_onboard_devices_extended_info(struct ParserContext *context) 626 | { 627 | if (context->sversion >= SMBIOS_2_0) 628 | { 629 | context->entry.data.onboard_devices_extended_info.ReferenceDesignation_ = read_uint8(context); 630 | context->entry.data.onboard_devices_extended_info.DeviceType = read_uint8(context); 631 | context->entry.data.onboard_devices_extended_info.DeviceTypeInstance = read_uint8(context); 632 | context->entry.data.onboard_devices_extended_info.SegmentGroupNumber = read_uint16(context); 633 | context->entry.data.onboard_devices_extended_info.BusNumber = read_uint8(context); 634 | context->entry.data.onboard_devices_extended_info.DeviceOrFunctionNumber = read_uint8(context); 635 | 636 | context->entry.data.onboard_devices_extended_info.ReferenceDesignation = get_string(context, context->entry.data.onboard_devices_extended_info.ReferenceDesignation_); 637 | } 638 | } 639 | 640 | static int parse_entry(struct ParserContext *context, const struct Entry **entry) 641 | { 642 | if (entry == NULL) 643 | return SMBERR_INVALID_ARGUMENT; 644 | 645 | switch (context->entry.type) 646 | { 647 | case TYPE_BIOS_INFO: 648 | parse_bios_info(context); 649 | break; 650 | case TYPE_SYSTEM_INFO: 651 | parse_system_info(context); 652 | break; 653 | case TYPE_BASEBOARD_INFO: 654 | parse_baseboard_info(context); 655 | break; 656 | case TYPE_SYSTEM_ENCLOSURE: 657 | parse_system_enclosure(context); 658 | break; 659 | case TYPE_PROCESSOR_INFO: 660 | parse_processor_info(context); 661 | break; 662 | case TYPE_PORT_CONNECTOR: 663 | parse_port_connector(context); 664 | break; 665 | case TYPE_SYSTEM_SLOT: 666 | parse_system_slot(context); 667 | break; 668 | case TYPE_OEM_STRINGS: 669 | parse_oem_strings(context); 670 | break; 671 | case TYPE_PHYSICAL_MEMORY_ARRAY: 672 | parse_physical_memory_array(context); 673 | break; 674 | case TYPE_MEMORY_DEVICE: 675 | parse_memory_device(context); 676 | break; 677 | case TYPE_MEMORY_ARRAY_MAPPED_ADDRESS: 678 | parse_memory_array_mapped_address(context); 679 | break; 680 | case TYPE_MEMORY_DEVICE_MAPPED_ADDRESS: 681 | parse_memory_device_mapped_address(context); 682 | break; 683 | case TYPE_SYSTEM_BOOT_INFO: 684 | parse_system_boot_info(context); 685 | break; 686 | case TYPE_MANAGEMENT_DEVICE: 687 | parse_management_device(context); 688 | break; 689 | case TYPE_MANAGEMENT_DEVICE_COMPONENT: 690 | parse_management_device_component(context); 691 | break; 692 | case TYPE_MANAGEMENT_DEVICE_THRESHOLD_DATA: 693 | parse_management_device_threshold_data(context); 694 | break; 695 | case TYPE_ONBOARD_DEVICES_EXTENDED_INFO: 696 | parse_onboard_devices_extended_info(context); 697 | break; 698 | } 699 | 700 | if (context->failed) 701 | return SMBERR_INVALID_DATA; 702 | *entry = &context->entry; 703 | return SMBERR_OK; 704 | } 705 | 706 | int smbios_next(struct ParserContext *context, const struct Entry **entry) 707 | { 708 | if (context == NULL || entry == NULL) 709 | return SMBERR_INVALID_ARGUMENT; 710 | if (context->data == NULL || context->failed) 711 | return SMBERR_INVALID_DATA; 712 | 713 | // jump to the next field 714 | if (context->estart == NULL) 715 | context->estart = context->ptr = context->data; 716 | else 717 | context->estart = context->ptr = context->eend; 718 | 719 | memset(&context->entry, 0, sizeof(context->entry)); 720 | 721 | if (context->estart + SMBIOS_ENTRY_HEADER_SIZE >= context->data + context->size) 722 | return SMBERR_INVALID_DATA; 723 | 724 | // entry header 725 | context->entry.type = *context->ptr++; 726 | context->entry.length = *context->ptr++; 727 | context->entry.handle = *context->ptr++; 728 | context->entry.handle |= (uint16_t) ((*context->ptr++) << 8); 729 | context->entry.rawdata = context->estart; 730 | context->entry.strings = (const char *) context->estart + context->entry.length; 731 | 732 | // compute the end of the entry skipping all strings 733 | context->eend = (uint8_t*) context->entry.strings; 734 | int nulls = 0; 735 | while (context->eend < context->data + context->size) 736 | { 737 | if (*context->eend++ != 0) 738 | nulls = 0; 739 | else 740 | { 741 | if (nulls++ > 0) 742 | break; 743 | context->entry.string_count++; 744 | } 745 | } 746 | if (nulls != 2) 747 | return SMBERR_INVALID_DATA; 748 | 749 | if (context->entry.type == 127) 750 | { 751 | smbios_reset(context); 752 | return SMBERR_END_OF_STREAM; 753 | } 754 | 755 | return parse_entry(context, entry); 756 | } 757 | 758 | int smbios_get_version(struct ParserContext *context, int *selected, int *original) 759 | { 760 | if (context == NULL) 761 | return SMBERR_INVALID_ARGUMENT; 762 | if (context->data == NULL || context->failed) 763 | return SMBERR_INVALID_DATA; 764 | 765 | if (selected) 766 | *selected = context->sversion; 767 | if (original) 768 | *original = context->oversion; 769 | return SMBERR_OK; 770 | } 771 | 772 | --------------------------------------------------------------------------------