├── .github └── workflows │ └── main.yml ├── AUTHORS ├── Changelog.md ├── LICENSE ├── Makefile ├── NEWS ├── README.md ├── biosdecode.c ├── completion ├── biosdecode.bash ├── dmidecode.bash ├── ownership.bash └── vpddecode.bash ├── config.h ├── dmidecode.c ├── dmidecode.h ├── dmidecode.xcodeproj └── project.pbxproj ├── dmioem.c ├── dmioem.h ├── dmiopt.c ├── dmiopt.h ├── dmioutput.c ├── dmioutput.h ├── man ├── biosdecode.8 ├── dmidecode.8 ├── ownership.8 └── vpddecode.8 ├── ownership.c ├── types.h ├── util.c ├── util.h ├── version.h ├── vpddecode.c ├── vpdopt.c └── vpdopt.h /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | release: 8 | types: [published] 9 | 10 | env: 11 | PROJECT_TYPE: TOOL 12 | 13 | jobs: 14 | build: 15 | name: Build 16 | runs-on: macos-12 17 | env: 18 | JOB_TYPE: BUILD 19 | steps: 20 | - uses: actions/checkout@v3 21 | - name: CI Bootstrap 22 | run: | 23 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/ci-bootstrap.sh) && eval "$src" || exit 1 24 | 25 | - run: make 26 | - run: zip -qry -FS dmidecode-mac-$(cat version.h | cut -f2 -d'"').zip dmidecode 27 | 28 | - name: Upload to Artifacts 29 | uses: actions/upload-artifact@v3 30 | with: 31 | name: Artifacts 32 | path: dmidecode-mac-*.zip 33 | - name: Upload to Release 34 | if: github.event_name == 'release' 35 | uses: svenstaro/upload-release-action@e74ff71f7d8a4c4745b560a485cc5fdb9b5b999d 36 | with: 37 | repo_token: ${{ secrets.GITHUB_TOKEN }} 38 | file: dmidecode-mac-*.zip 39 | tag: ${{ github.ref }} 40 | file_glob: true 41 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | DEVELOPER AND MAINTAINER 2 | Jean Delvare 3 | 4 | ORIGINAL AUTHORS 5 | Alan Cox 6 | Jean Delvare 7 | 8 | CODE CONTRIBUTORS (IN CHRONOLOGICAL ORDER) 9 | Matt Domsch 10 | Arjan van de Ven 11 | Mark D. Studebaker 12 | Larry Lile 13 | Dave Johnson 14 | Petter Reinholdtsen 15 | Roberto Nibali 16 | John Cagle 17 | Jens Elkner 18 | Jarod Wilson 19 | Anton Arapov 20 | Roy Franz 21 | Tyler Bell 22 | Xie XiuQi 23 | Petr Oros 24 | Prabhakar Pujeri 25 | Erwan Velu 26 | Jerry Hoemann 27 | 28 | MANY THANKS TO (IN CHRONOLOGICAL ORDER) 29 | Werner Heuser 30 | Alexandre Duret-Lutz 31 | Xavier Roche 32 | Pamela Huntley 33 | Gael Stephan 34 | Sebastian Henschel 35 | Richard Sharpe 36 | David Wilson 37 | Glen Foster 38 | Chad Smith 39 | Joshua Goldenhar 40 | Luc Van de Velde 41 | Mario Lang 42 | Hugues Lepesant 43 | Sergey Leonovich 44 | Mike Cooper 45 | Marc Rieffel 46 | Jeff Moyer 47 | Josef Moellers 48 | Zing Zing Shishak 49 | Rafael Avila de Espindola 50 | Roger Koot 51 | Martin Pool 52 | Doug Brenner 53 | Alex Williamson 54 | Durval Menezes 55 | Raphael Raimbault 56 | Raul Nunez de Arenas Coronado 57 | Francois Revol 58 | Dominik Klein 59 | Erwan Velu 60 | Don Howard 61 | Frans Pop 62 | Tomek Mateja 63 | Myke Olson 64 | Torsten Seemann 65 | Garry Belka 66 | Klaus Muth 67 | Antoine Fuselier 68 | Matthew Garrett 69 | Landry Breuil 70 | Luke Suchocki 71 | Attila Nagy 72 | Alex Iribarren 73 | Sebastien Douche 74 | William Lallemand 75 | Olivier Guerrier 76 | Pascal Terjan 77 | Stuart Hayes 78 | Sofian Brabez 79 | Vincent Pelletier 80 | Andreas Gruenbacher 81 | Lin Li 82 | Thomas Hiller 83 | Paul Flo Williams 84 | Olof Johansson 85 | Alexandre Lissy 86 | Michal Svec 87 | Vojtech Pavlik 88 | Murlin Wenzel 89 | Harald Mueller-Ney 90 | Lars Mueller 91 | Thomas Mingarelli 92 | Andrey Matveyev 93 | Stefan Tauner 94 | Naga Chumbalkar 95 | Jens Rosenboom 96 | Lianbo Jiang 97 | Tianjia Zhang 98 | Ivan Tkachenko 99 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | Acidanthera dmidecode Changelog 2 | =============================== 3 | 4 | #### v3.6a 5 | - Synced with dmidecode 51b1ecc2 6 | 7 | #### v3.4a 8 | - Synced with dmidecode a1a2258f 9 | - Added Apple Silicon support 10 | 11 | #### v3.3c 12 | - Fixed compatibility for macOS 10.7+ 13 | 14 | #### v3.3b 15 | - Synced with dmidecode a4b31b2b 16 | - Added improved UUID dumping support 17 | 18 | #### v3.3a 19 | - Synced with dmidecode 3c111e4f with SMBIOS 3.3 support 20 | 21 | #### v3.2c 22 | - Synced with dmidecode 5b3c8e99 23 | 24 | #### v3.2b 25 | - Synced with dmidecode 62bce59f 26 | - Improved hexadecimal table dumping 27 | 28 | #### v3.2a 29 | - Initial release based on dmidecode 3.2 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # DMI Decode 3 | # BIOS Decode 4 | # VPD Decode 5 | # 6 | # Copyright (C) 2000-2002 Alan Cox 7 | # Copyright (C) 2002-2020 Jean Delvare 8 | # 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2 of the License, or 12 | # (at your option) any later version. 13 | # 14 | 15 | CC ?= gcc 16 | # Base CFLAGS can be overridden by environment 17 | CFLAGS ?= -O2 18 | # When debugging, disable -O2 and enable -g 19 | #CFLAGS ?= -g 20 | 21 | CFLAGS += -W -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual \ 22 | -Wcast-align -Wwrite-strings -Wmissing-prototypes -Winline -Wundef 23 | 24 | # Let lseek and mmap support 64-bit wide offsets 25 | CFLAGS += -D_FILE_OFFSET_BITS=64 26 | 27 | #CFLAGS += -DBIGENDIAN 28 | #CFLAGS += -DALIGNMENT_WORKAROUND 29 | 30 | # Pass linker flags here (can be set from environment too) 31 | LDFLAGS ?= 32 | 33 | UNAME_S := $(shell uname -s) 34 | ifeq ($(UNAME_S),Darwin) 35 | CFLAGS += -mmacosx-version-min=10.7 -arch arm64 -arch x86_64 36 | LDFLAGS += -Wl,-framework,CoreFoundation -Wl,-framework,IOKit -mmacosx-version-min=10.7 -arch arm64 -arch x86_64 37 | endif 38 | 39 | DESTDIR = 40 | prefix = /usr/local 41 | sbindir = $(prefix)/sbin 42 | mandir = $(prefix)/share/man 43 | man8dir = $(mandir)/man8 44 | docdir = $(prefix)/share/doc/dmidecode 45 | compdir = $(shell pkg-config --variable=completionsdir bash-completion 2>/dev/null || echo $(prefix)/etc/bash_completion.d) 46 | 47 | INSTALL := install 48 | INSTALL_DATA := $(INSTALL) -m 644 49 | INSTALL_DIR := $(INSTALL) -m 755 -d 50 | INSTALL_PROGRAM := $(INSTALL) -m 755 51 | RM := rm -f 52 | 53 | # BSD make provides $MACHINE, but GNU make doesn't 54 | MACHINE ?= $(shell uname -m 2>/dev/null) 55 | 56 | # These programs are only useful on x86 57 | PROGRAMS-i386 := biosdecode ownership vpddecode 58 | PROGRAMS-i486 := $(PROGRAMS-i386) 59 | PROGRAMS-i586 := $(PROGRAMS-i386) 60 | PROGRAMS-i686 := $(PROGRAMS-i386) 61 | PROGRAMS-x86_64 := biosdecode ownership vpddecode 62 | PROGRAMS-amd64 := $(PROGRAMS-x86_64) 63 | 64 | PROGRAMS := dmidecode $(PROGRAMS-$(MACHINE)) 65 | 66 | all : $(PROGRAMS) 67 | 68 | # 69 | # Programs 70 | # 71 | 72 | dmidecode : dmidecode.o dmiopt.o dmioem.o dmioutput.o util.o 73 | $(CC) $(LDFLAGS) dmidecode.o dmiopt.o dmioem.o dmioutput.o util.o -o $@ 74 | 75 | biosdecode : biosdecode.o util.o 76 | $(CC) $(LDFLAGS) biosdecode.o util.o -o $@ 77 | 78 | ownership : ownership.o util.o 79 | $(CC) $(LDFLAGS) ownership.o util.o -o $@ 80 | 81 | vpddecode : vpddecode.o vpdopt.o util.o 82 | $(CC) $(LDFLAGS) vpddecode.o vpdopt.o util.o -o $@ 83 | 84 | # 85 | # Objects 86 | # 87 | 88 | dmidecode.o : dmidecode.c version.h types.h util.h config.h dmidecode.h \ 89 | dmiopt.h dmioem.h dmioutput.h 90 | $(CC) $(CFLAGS) -c $< -o $@ 91 | 92 | dmiopt.o : dmiopt.c config.h types.h util.h dmidecode.h dmiopt.h 93 | $(CC) $(CFLAGS) -c $< -o $@ 94 | 95 | dmioem.o : dmioem.c types.h dmidecode.h dmioem.h dmioutput.h 96 | $(CC) $(CFLAGS) -c $< -o $@ 97 | 98 | dmioutput.o : dmioutput.c types.h dmioutput.h 99 | $(CC) $(CFLAGS) -c $< -o $@ 100 | 101 | biosdecode.o : biosdecode.c version.h types.h util.h config.h 102 | $(CC) $(CFLAGS) -c $< -o $@ 103 | 104 | ownership.o : ownership.c version.h types.h util.h config.h 105 | $(CC) $(CFLAGS) -c $< -o $@ 106 | 107 | vpddecode.o : vpddecode.c version.h types.h util.h config.h vpdopt.h 108 | $(CC) $(CFLAGS) -c $< -o $@ 109 | 110 | vpdopt.o : vpdopt.c config.h util.h vpdopt.h 111 | $(CC) $(CFLAGS) -c $< -o $@ 112 | 113 | util.o : util.c types.h util.h config.h 114 | $(CC) $(CFLAGS) -c $< -o $@ 115 | 116 | # 117 | # Commands 118 | # 119 | 120 | strip : $(PROGRAMS) 121 | strip $(PROGRAMS) 122 | 123 | install : install-bin install-man install-doc install-completion 124 | 125 | uninstall : uninstall-bin uninstall-man uninstall-doc uninstall-completion 126 | 127 | install-bin : $(PROGRAMS) 128 | $(INSTALL_DIR) $(DESTDIR)$(sbindir) 129 | for program in $(PROGRAMS) ; do \ 130 | $(INSTALL_PROGRAM) $$program $(DESTDIR)$(sbindir) ; done 131 | 132 | uninstall-bin : 133 | for program in $(PROGRAMS) ; do \ 134 | $(RM) $(DESTDIR)$(sbindir)/$$program ; done 135 | 136 | install-man : 137 | $(INSTALL_DIR) $(DESTDIR)$(man8dir) 138 | for program in $(PROGRAMS) ; do \ 139 | $(INSTALL_DATA) man/$$program.8 $(DESTDIR)$(man8dir) ; done 140 | 141 | uninstall-man : 142 | for program in $(PROGRAMS) ; do \ 143 | $(RM) $(DESTDIR)$(man8dir)/$$program.8 ; done 144 | 145 | install-doc : 146 | $(INSTALL_DIR) $(DESTDIR)$(docdir) 147 | $(INSTALL_DATA) README $(DESTDIR)$(docdir) 148 | $(INSTALL_DATA) NEWS $(DESTDIR)$(docdir) 149 | $(INSTALL_DATA) AUTHORS $(DESTDIR)$(docdir) 150 | 151 | uninstall-doc : 152 | $(RM) -r $(DESTDIR)$(docdir) 153 | 154 | clean : 155 | $(RM) *.o $(PROGRAMS) core 156 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Version 3.6 (Wed Apr 24 2024) 2 | - [PORTABILITY] Use -DALIGNMENT_WORKAROUND on arm. 3 | - [PORTABILITY] Read SMBIOS entry point via kenv on DragonFly BSD. 4 | - Support for SMBIOS 3.6.0. This includes new memory device types, new 5 | processor upgrades, and Loongarch support. 6 | - Support for SMBIOS 3.7.0. This includes new port types, new processor 7 | upgrades, new slot characteristics and new fields for memory modules. 8 | - Add bash completion. 9 | - Decode HPE OEM records 197, 239 and 245. 10 | - Implement options --list-strings and --list-types. 11 | - Update HPE OEM records 203, 212, 216, 221, 233, 236, 237, 238 and 242. 12 | - Update Redfish support. 13 | - Bug fixes: 14 | Fix option --from-dump for user root 15 | Fix enabled slot characteristics not being printed 16 | - Minor improvements: 17 | Print slot width on its own line 18 | Use standard strings for slot width 19 | 20 | Version 3.5 (Tue Mar 14 2023) 21 | - Decode HPE OEM records 216, 224, 230, 238 and 242. 22 | - Fortify entry point length checks. 23 | - Add a --no-quirks option. 24 | - Drop the CPUID exception list. 25 | - Do not let --dump-bin overwrite an existing file. 26 | - Ensure /dev/mem is a character device file. 27 | - Bug fixes: 28 | Fix segmentation fault in HPE OEM record 240 29 | - Minor improvements: 30 | Typo fixes 31 | Write the whole dump file at once 32 | Fix a build warning when USE_MMAP isn't set 33 | 34 | Version 3.4 (Mon Jun 27 2022) 35 | - Support for SMBIOS 3.4.0. This includes new memory device types, new 36 | processor upgrades, new slot types and characteristics, decoding of memory 37 | module extended speed, new system slot types, new processor characteristics 38 | and new format of Processor ID. 39 | - Support for SMBIOS 3.5.0. This includes new processor upgrades, BIOS 40 | characteristics, new slot characteristics, new on-board device types, new 41 | pointing device interface types, and a new record type (type 45 - 42 | Firmware Inventory Information). 43 | - Decode HPE OEM records 194, 199, 203, 236, 237, 238 and 240. 44 | - Bug fixes: 45 | Fix OEM vendor name matching 46 | Fix ASCII filtering of strings 47 | Fix crash with option -u 48 | - Minor improvements: 49 | Skip details of uninstalled memory modules 50 | Don't display the raw CPU ID in quiet mode 51 | Improve the formatting of the manual pages 52 | 53 | Version 3.3 (Wed Oct 14 2020) 54 | - [BUILD] Allow overriding build settings from the environment. 55 | - [COMPATIBILITY] Document how the UUID fields are interpreted. 56 | - [PORTABILITY] Don't use memcpy on /dev/mem on arm64. 57 | - [PORTABILITY] Only scan /dev/mem for entry point on x86. 58 | - Support for SMBIOS 3.3.0. This includes new processor names, new port 59 | connector types, and new memory device form factors, types and 60 | technologies. 61 | - Add bios-revision, firmware-revision and system-sku-number to -s option. 62 | - Use the most appropriate unit for cache size. 63 | - Decode system slot base bus width and peers. 64 | - Important bug fixes: 65 | Fix Redfish Hostname print length 66 | Fix formatting of TPM table output 67 | Fix System Slot Information for PCIe SSD 68 | Don't choke on invalid processor voltage 69 | - Use the most appropriate unit for cache size. 70 | 71 | Version 3.2 (Wed Sep 14 2018) 72 | - [COMPATIBILITY] The UUID is now displayed using lowercase letters, per 73 | RFC 4122 (#53569). You must ensure that any code parsing it is 74 | case-insensitive. 75 | - Support for SMBIOS 3.2.0. This includes new processor names, new socket 76 | and port connector types, new system slot state and property, and support 77 | for non-volatile memory (NVDIMM). 78 | - Support for Redfish management controllers. 79 | - A new command line option to query a specific structure by its handle. 80 | - A new command line option to query the system family string. 81 | - Support for 3 ThinkPad-specific structures (patch #9642). 82 | - Support for HPE's new company name. 83 | - Support UEFI on FreeBSD. 84 | - Important bug fixes: 85 | Fix firmware version of TPM device 86 | Fix the HPE UEFI feature flag check 87 | - (biosdecode) A new command line option to fully decode PIR information 88 | (support request #109339). 89 | 90 | Version 3.1 (Tue May 23 2017) 91 | - Support for SMBIOS 3.1.0 and 3.1.1. This includes new chassis types, new 92 | processor family names, new processor family upgrade names, and new slot 93 | types, as well as support of larger BIOS ROM sizes and cache sizes, and a 94 | new structure type (43, TPM Device.) 95 | - A new command line option to query OEM strings. 96 | - All error messages are now printed on stderr (#47274, #48158.) 97 | - Several bug fixes related to 64-bit entry points (#50037 and more.) 98 | - Important bug fixes: 99 | #46176 (Unexpected end of file error) 100 | #46066 (Crash with SIGBUS) 101 | - Various minor fixes, improvements and cleanups. 102 | 103 | Version 3.0 (Thu Sep 03 2015) 104 | - Support for SMBIOS 3.0. This includes new chassis types, new 105 | processor family names, new processor family upgrade names, new slot 106 | types, and new memory device types. 107 | - Support for the new 64-bit entry point (_SM3_) defined in SMBIOS 3.0. 108 | - Support for the new kernel interface (as of Linux v4.2) as an 109 | alternative to relying /dev/mem to access the entry point and DMI 110 | table. 111 | - Decoding of Acer-specific DMI type 170. 112 | - Decoding of HP-specific DMI types 212, 219 and 233. 113 | - Various minor fixes and output format cleanups. 114 | 115 | Version 2.12 (Wed Apr 17 2013) 116 | - Support of the SMBIOS 2.8.0 specification. 117 | 118 | Version 2.11 (Wed Jan 19 2011) 119 | - Support of the SMBIOS 2.7.0 specification: 120 | - UEFI support 121 | - Virtual machine flags in BIOS characteristics 122 | - Limited support for the Management Controller Host Interface 123 | - Various fixes that address stability. 124 | 125 | Version 2.10 (Sun Nov 23 2008) 126 | - Support for Solaris (x86 only, of course). 127 | - Possibility to dump the SMBIOS/DMI table to a small binary file 128 | (option --dump-bin). 129 | - Possibility to read the SMBIOS/DMI table from such binary files 130 | (option --from-dump). 131 | - Support for SMBIOS 2.6. This includes new chassis types, new 132 | processor family names, new processor family upgrade names, bus 133 | address for system slots, and a new entry type for on-board devices, 134 | amongst many other minor changes. 135 | - Support for DMI entry type 31 (Boot integrity services). 136 | - Many processor family names taken from the CIM Schema document. 137 | - (vpddecode) No longer ask users to report broken records. 138 | - (vpddecode) Fix --quiet option. 139 | 140 | Version 2.9 (Mon Feb 26 2007) 141 | - Support of the SMBIOS 2.5 specification. It adds many enumerated 142 | values for recent hardware, as well as CPU core and thread count 143 | reporting. 144 | - Decoding of 3 HP-specific entries. More vendor-specific entries can 145 | be supported later if vendors contribute code or documentation. 146 | - Run-time detection of EFI, so that a single binary can support 147 | Intel-based Macintosh machines and regular x86 machines. 148 | - Better IA-64 support. 149 | - Fixes to the decoding of individual fields, including the CPU 150 | signature of recent CPU models. 151 | - (biosdecode) Support of the FJKEYINF entry point type (for Fujitsu laptops). 152 | - (vpddecode) The product name look-up table was dropped. It was unreliable 153 | and a burden to maintain. 154 | - biosdecode, ownership and vpddecode are no longer built on IA-64. 155 | 156 | Version 2.8 (Sat Feb 04 2006) 157 | - Option --string has four additional keywords available: 158 | system-uuid, chassis-type, processor-family and processor-frequency. 159 | These needed additional work because, technically speaking, they are 160 | not DMI strings. 161 | - IPMI interface type SSIF was added. This is a new interface type 162 | defined by IPMI 2.0. 163 | - (vpddecode) New --string option, much similar in spirit to 164 | dmidecode's. Available keywords are bios-build-id, box-serial-number, 165 | motherboard-serial-number, machine-type-model and bios-release-date. 166 | - (vpddecode) 9 product names were added to the lookup table. 167 | - A few bug fixes, cleanups and minor improvements all around the place. 168 | 169 | Version 2.7 (Thu Aug 04 2005) 170 | - New command line interface. For example, it is now possible to limit 171 | the output of dmidecode to a given DMI type, or to extract a single 172 | string from the DMI table. The documentation has been updated 173 | accordingly. 174 | - The default output of dmidecode was slightly modified to be more 175 | easily readable by humans. This might break tools parsing its output. 176 | Such tools may benefit from the new command line interface, although 177 | this interface shouldn't be considered stable until version 2.8. 178 | - (vpddecode) New command line interface. 179 | - (vpddecode) 6 product names were added. 180 | 181 | Version 2.6 (Mon Feb 28 2005) 182 | - Fixes a 2 GB memory limit regression. 183 | - Basic command-line handling. 184 | - BeOS and Cygwin support. 185 | 186 | Version 2.5 (Thu Nov 11 2004) 187 | - Code cleanups. 188 | - Compatibility fixes. 189 | - Documentation updates. 190 | 191 | Version 2.4 (Fri Mar 19 2004) 192 | - Manual pages added. 193 | - (vpddecode) Many improvements. 194 | - A few fixes and minor improvements. 195 | 196 | Version 2.3 (Sun Oct 19 2003) 197 | - Support of x86_64 systems. 198 | - Support of systems with 2 GB and more memory. 199 | - Loads of bug fixes and corrections. 200 | - New tool "vpddecode" added. 201 | 202 | Version 2.2 (Fri Aug 08 2003) 203 | - Support of IA-64 systems. 204 | - Support of IBM and Fujitsu-Siemens laptops. 205 | - Many minor bug fixes. 206 | - New tool "ownership" added. 207 | 208 | Version 2.1 (Tue Jun 10 2003) 209 | - Support of the SMBIOS 2.3.4 specification. 210 | - Better support of IPMI. 211 | - Minor bugs fixed. 212 | - Documentation added. 213 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dmidecode 2 | ========= 3 | 4 | [![Build Status](https://github.com/acidanthera/dmidecode/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/acidanthera/dmidecode/actions) 5 | 6 | **ACIDANTHERA NOTES** 7 | 8 | This dmidecode version supports Apple-specific table decoding as well 9 | as native macOS SMBIOS reading through I/O Registry. Synced with 10 | [upstream](git://git.savannah.gnu.org/dmidecode.git) up to 51b1ecc2. 11 | 12 | **INTRODUCTION** 13 | 14 | Dmidecode reports information about your system's hardware as described in 15 | your system BIOS according to the SMBIOS/DMI standard. This information 16 | typically includes system manufacturer, model name, serial number, BIOS 17 | version, asset tag as well as a lot of other details of varying level of 18 | interest and reliability depending on the manufacturer. This will often 19 | include usage status for the CPU sockets, expansion slots (e.g. AGP, PCI, 20 | ISA) and memory module slots, and the list of I/O ports (e.g. serial, 21 | parallel, USB). 22 | 23 | DMI data can be used to enable or disable specific portions of kernel code 24 | depending on the specific hardware. Thus, one use of dmidecode is for kernel 25 | developers to detect system "signatures" and add them to the kernel source 26 | code when needed. 27 | 28 | Beware that DMI data have proven to be too unreliable to be blindly trusted. 29 | Dmidecode does not scan your hardware, it only reports what the BIOS told it 30 | to. 31 | 32 | 33 | **INSTALLATION** 34 | 35 | The home web page for dmidecode is hosted on Savannah: 36 | http://www.nongnu.org/dmidecode/ 37 | You will find the latest version (including CVS) there, as well as fresh news 38 | and other interesting material, such as a list of related projects and 39 | articles. 40 | 41 | This program was first written for Linux, and has since been reported to work 42 | on FreeBSD, NetBSD, OpenBSD, BeOS and Solaris as well. 43 | 44 | There's no configure script, so simply run "make" to build dmidecode, and 45 | "make install" to install it. You also can use "make uninstall" to remove 46 | all the files you installed. By default, files are installed in /usr/local 47 | but you can change this behavior by editing the Makefile file and setting 48 | prefix to wherever you want. You may change the C compiler and the 49 | compilation flags as well. 50 | 51 | Optionally, you can run "make strip" prior to "make install" if you want 52 | smaller binaries. However, be aware that this will prevent any further 53 | attempt to debug the programs. 54 | 55 | Two parameters can be set in the Makefile file to make dmidecode work on 56 | non-i386 systems. They should be used if your system uses the big endian 57 | byte ordering (Motorola) or doesn't support unaligned memory accesses, 58 | respectively. For example, compiling for a SPARC processor would require 59 | both (but I am not aware of SPARC-based systems implementing SMBIOS). 60 | Compiling for an IA64 processor requires the memory alignment workaround, 61 | and it is enabled automatically. 62 | 63 | 64 | **DOCUMENTATION** 65 | 66 | Each tool has a manual page, found in the "man" subdirectory. Manual pages 67 | are installed by "make install". See these manual pages for command line 68 | interface details and tool specific information. 69 | 70 | For an history of the changes made to dmidecode, see the NEWS file. 71 | 72 | If you need help, your best chances are to visit the web page (see the 73 | INSTALLATION section above) or to get in touch with the developers directly. 74 | Have a look at the AUTHORS file and contact one of the maintainers. 75 | 76 | If you want to help with the development of dmidecode, please consider 77 | joining the dmidecode-devel discussion list: 78 | http://lists.nongnu.org/mailman/listinfo/dmidecode-devel 79 | 80 | 81 | **COMMON PROBLEMS** 82 | 83 | IA-64 84 | 85 | Non-Linux systems are not yet supported. 86 | 87 | MMAP 88 | 89 | Note that mmap() is now used by default wherever possible, since this seems 90 | to solve a number of problems. This default behavior can be changed in 91 | config.h. Just to make sure this is clear, mmap() is not used for performance 92 | reasons but to increase the number of systems on which dmidecode can be 93 | successfully run. 94 | 95 | CYGWIN 96 | 97 | Dmidecode used to work under Cygwin. However the /dev/mem interface was 98 | removed at some point in time so it no longer works. 99 | 100 | 101 | **MISCELLANEOUS TOOLS** 102 | 103 | Three other tools come along with dmidecode: biosdecode, ownership and 104 | vpddecode. These tools are only useful on systems with a BIOS, so they 105 | are not built on IA-64 by default. 106 | 107 | BIOSDECODE 108 | 109 | This one prints all BIOS related information it can find in /dev/mem. 110 | It used to be part of dmidecode itself, but as dmidecode was growing, 111 | we felt that the non-DMI part had to be moved to a separate tool. 112 | 113 | OWNERSHIP 114 | 115 | This tool was written on a request by Luc Van de Velde for use with Novell 116 | tools in his company. It retrieves the "ownership tag" that can be set on 117 | most Compaq computers. Since it uses the same mechanisms dmidecode and 118 | biosdecode use, and could be of some use for other people as well, we 119 | decided to make it part of the project. 120 | 121 | VPDDECODE 122 | 123 | This tool prints the contents of the "vital product data" structure as 124 | found in most IBM and Lenovo computers. It used to have a lookup table 125 | for the machine name, but it was unreliable and hard to maintain so it 126 | was ultimately dropped. It has a command line interface. 127 | 128 | Use -h flag for help. 129 | -------------------------------------------------------------------------------- /biosdecode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * BIOS Decode 3 | * 4 | * Copyright (C) 2000-2002 Alan Cox 5 | * Copyright (C) 2002-2017 Jean Delvare 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | * 21 | * For the avoidance of doubt the "preferred form" of this code is one which 22 | * is in an open unpatent encumbered format. Where cryptographic key signing 23 | * forms part of the process of creating an executable the information 24 | * including keys needed to generate an equivalently functional executable 25 | * are deemed to be part of the source code. 26 | * 27 | * References: 28 | * - DMTF "System Management BIOS (SMBIOS) Reference Specification" 29 | * Version 3.0.0 30 | * http://www.dmtf.org/standards/smbios 31 | * - Intel "Preboot Execution Environment (PXE) Specification" 32 | * Version 2.1 33 | * http://www.intel.com/labs/manage/wfm/wfmspecs.htm 34 | * - ACPI "Advanced Configuration and Power Interface Specification" 35 | * Revision 2.0 36 | * http://www.acpi.info/spec20.htm 37 | * - Phoenix "BIOS32 Service Directory" 38 | * Revision 0.4 39 | * http://www.phoenix.com/en/support/white+papers-specs/ 40 | * - Microsoft "Plug and Play BIOS Specification" 41 | * Version 1.0A 42 | * http://www.microsoft.com/hwdev/tech/PnP/ 43 | * - Microsoft "PCI IRQ Routing Table Specification" 44 | * Version 1.0 45 | * http://www.microsoft.com/hwdev/archive/BUSBIOS/pciirq.asp 46 | * - Compaq "Technical Reference Guide for Compaq Deskpro 4000 and 6000" 47 | * First Edition 48 | * http://h18000.www1.hp.com/support/techpubs/technical_reference_guides/113a1097.html 49 | * - IBM "Using the BIOS Build ID to identify Thinkpad systems" 50 | * Revision 2005-09-19 51 | * http://www-307.ibm.com/pc/support/site.wss/MIGR-45120.html 52 | * - Fujitsu application panel technical details 53 | * As of July 23rd, 2004 54 | * http://apanel.sourceforge.net/tech.php 55 | * - Intel Multiprocessor Specification 56 | * Version 1.4 57 | * http://www.intel.com/design/archives/processors/pro/docs/242016.htm 58 | */ 59 | 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | 66 | #include "version.h" 67 | #include "config.h" 68 | #include "types.h" 69 | #include "util.h" 70 | 71 | /* Options are global */ 72 | struct opt 73 | { 74 | const char *devmem; 75 | unsigned int flags; 76 | unsigned char pir; 77 | }; 78 | static struct opt opt; 79 | 80 | #define FLAG_VERSION (1 << 0) 81 | #define FLAG_HELP (1 << 1) 82 | 83 | #define PIR_SHORT 0 84 | #define PIR_FULL 1 85 | 86 | struct bios_entry { 87 | const char *anchor; 88 | size_t anchor_len; /* computed */ 89 | off_t low_address; 90 | off_t high_address; 91 | size_t (*length)(const u8 *); 92 | int (*decode)(const u8*, size_t); 93 | }; 94 | 95 | 96 | /* 97 | * SMBIOS 98 | */ 99 | 100 | static size_t smbios3_length(const u8 *p) 101 | { 102 | return p[0x06]; 103 | } 104 | 105 | static int smbios3_decode(const u8 *p, size_t len) 106 | { 107 | if (len < 0x18 || !checksum(p, p[0x06])) 108 | return 0; 109 | 110 | printf("SMBIOS %u.%u.%u present.\n", 111 | p[0x07], p[0x08], p[0x09]); 112 | printf("\tStructure Table Maximum Length: %u bytes\n", 113 | DWORD(p + 0x0C)); 114 | printf("\tStructure Table 64-bit Address: 0x%08X%08X\n", 115 | QWORD(p + 0x10).h, QWORD(p + 0x10).l); 116 | 117 | return 1; 118 | } 119 | 120 | static size_t smbios_length(const u8 *p) 121 | { 122 | return p[0x05] == 0x1E ? 0x1F : p[0x05]; 123 | } 124 | 125 | static int smbios_decode(const u8 *p, size_t len) 126 | { 127 | if (len < 0x1F || !checksum(p, p[0x05]) 128 | || memcmp("_DMI_", p + 0x10, 5) != 0 129 | || !checksum(p + 0x10, 0x0F)) 130 | return 0; 131 | 132 | printf("SMBIOS %u.%u present.\n", 133 | p[0x06], p[0x07]); 134 | printf("\tStructure Table Length: %u bytes\n", 135 | WORD(p + 0x16)); 136 | printf("\tStructure Table Address: 0x%08X\n", 137 | DWORD(p + 0x18)); 138 | printf("\tNumber Of Structures: %u\n", 139 | WORD(p + 0x1C)); 140 | printf("\tMaximum Structure Size: %u bytes\n", 141 | WORD(p + 0x08)); 142 | 143 | return 1; 144 | } 145 | 146 | static size_t dmi_length(const u8 *p) 147 | { 148 | (void) p; 149 | 150 | return 0x0F; 151 | } 152 | 153 | static int dmi_decode(const u8 *p, size_t len) 154 | { 155 | if (len < 0x0F || !checksum(p, len)) 156 | return 0; 157 | 158 | printf("Legacy DMI %u.%u present.\n", 159 | p[0x0E]>>4, p[0x0E] & 0x0F); 160 | printf("\tStructure Table Length: %u bytes\n", 161 | WORD(p + 0x06)); 162 | printf("\tStructure Table Address: 0x%08X\n", 163 | DWORD(p + 0x08)); 164 | printf("\tNumber Of Structures: %u\n", 165 | WORD(p + 0x0C)); 166 | 167 | return 1; 168 | } 169 | 170 | /* 171 | * SYSID 172 | */ 173 | 174 | static size_t sysid_length(const u8 *p) 175 | { 176 | return WORD(p + 0x08); 177 | } 178 | 179 | static int sysid_decode(const u8 *p, size_t len) 180 | { 181 | if (len < 0x11 || !checksum(p, WORD(p + 0x08))) 182 | return 0; 183 | 184 | printf("SYSID present.\n"); 185 | printf("\tRevision: %u\n", 186 | p[0x10]); 187 | printf("\tStructure Table Address: 0x%08X\n", 188 | DWORD(p + 0x0A)); 189 | printf("\tNumber Of Structures: %u\n", 190 | WORD(p + 0x0E)); 191 | 192 | return 1; 193 | } 194 | 195 | /* 196 | * PnP 197 | */ 198 | 199 | static size_t pnp_length(const u8 *p) 200 | { 201 | return p[0x05]; 202 | } 203 | 204 | static const char *pnp_event_notification(u8 code) 205 | { 206 | static const char *notification[] = { 207 | "Not Supported", /* 0x0 */ 208 | "Polling", 209 | "Asynchronous", 210 | "Unknown" /* 0x3 */ 211 | }; 212 | 213 | return notification[code]; 214 | } 215 | 216 | static int pnp_decode(const u8 *p, size_t len) 217 | { 218 | if (len < 0x21 || !checksum(p, p[0x05])) 219 | return 0; 220 | 221 | printf("PNP BIOS %u.%u present.\n", 222 | p[0x04] >> 4, p[0x04] & 0x0F); 223 | printf("\tEvent Notification: %s\n", 224 | pnp_event_notification(WORD(p + 0x06) & 0x03)); 225 | if ((WORD(p + 0x06) & 0x03) == 0x01) 226 | printf("\tEvent Notification Flag Address: 0x%08X\n", 227 | DWORD(p + 0x09)); 228 | printf("\tReal Mode 16-bit Code Address: %04X:%04X\n", 229 | WORD(p + 0x0F), WORD(p + 0x0D)); 230 | printf("\tReal Mode 16-bit Data Address: %04X:0000\n", 231 | WORD(p + 0x1B)); 232 | printf("\t16-bit Protected Mode Code Address: 0x%08X\n", 233 | DWORD(p + 0x13) + WORD(p + 0x11)); 234 | printf("\t16-bit Protected Mode Data Address: 0x%08X\n", 235 | DWORD(p + 0x1D)); 236 | if (DWORD(p + 0x17) != 0) 237 | printf("\tOEM Device Identifier: %c%c%c%02X%02X\n", 238 | 0x40 + ((p[0x17] >> 2) & 0x1F), 239 | 0x40 + ((p[0x17] & 0x03) << 3) + ((p[0x18] >> 5) & 0x07), 240 | 0x40 + (p[0x18] & 0x1F), p[0x19], p[0x20]); 241 | 242 | return 1; 243 | } 244 | 245 | /* 246 | * ACPI 247 | */ 248 | 249 | static size_t acpi_length(const u8 *p) 250 | { 251 | return p[15] == 2 ? 36 : 20; 252 | } 253 | 254 | static const char *acpi_revision(u8 code) 255 | { 256 | switch (code) 257 | { 258 | case 0: 259 | return " 1.0"; 260 | case 2: 261 | return " 2.0"; 262 | default: 263 | return ""; 264 | } 265 | } 266 | 267 | static int acpi_decode(const u8 *p, size_t len) 268 | { 269 | if (len < 20 || !checksum(p, 20)) 270 | return 0; 271 | 272 | printf("ACPI%s present.\n", 273 | acpi_revision(p[15])); 274 | printf("\tOEM Identifier: %c%c%c%c%c%c\n", 275 | p[9], p[10], p[11], p[12], p[13], p[14]); 276 | printf("\tRSD Table 32-bit Address: 0x%08X\n", 277 | DWORD(p + 16)); 278 | 279 | if (len < 36) 280 | return 1; 281 | 282 | if (DWORD(p + 20) > len || !checksum(p, DWORD(p + 20))) 283 | return 0; 284 | 285 | if (DWORD(p + 20) < 32) return 1; 286 | 287 | printf("\tXSD Table 64-bit Address: 0x%08X%08X\n", 288 | QWORD(p + 24).h, QWORD(p + 24).l); 289 | 290 | return 1; 291 | } 292 | 293 | /* 294 | * Sony 295 | */ 296 | 297 | static size_t sony_length(const u8 *p) 298 | { 299 | return p[0x05]; 300 | } 301 | 302 | static int sony_decode(const u8 *p, size_t len) 303 | { 304 | if (!checksum(p, len)) 305 | return 0; 306 | 307 | printf("Sony system detected.\n"); 308 | 309 | return 1; 310 | } 311 | 312 | /* 313 | * BIOS32 314 | */ 315 | 316 | static size_t bios32_length(const u8 *p) 317 | { 318 | return p[0x09] << 4; 319 | } 320 | 321 | static int bios32_decode(const u8 *p, size_t len) 322 | { 323 | if (len < 0x0A || !checksum(p, p[0x09] << 4)) 324 | return 0; 325 | 326 | printf("BIOS32 Service Directory present.\n"); 327 | printf("\tRevision: %u\n", 328 | p[0x08]); 329 | printf("\tCalling Interface Address: 0x%08X\n", 330 | DWORD(p + 0x04)); 331 | 332 | return 1; 333 | } 334 | 335 | /* 336 | * PIR 337 | */ 338 | 339 | static void pir_irqs(u16 code) 340 | { 341 | if (code == 0) 342 | printf(" None"); 343 | else 344 | { 345 | u8 i; 346 | 347 | for (i = 0; i < 16; i++) 348 | if (code & (1 << i)) 349 | printf(" %u", i); 350 | } 351 | } 352 | 353 | static void pir_slot_number(u8 code) 354 | { 355 | if (code == 0) 356 | printf(" on-board"); 357 | else 358 | printf(" slot %u", code); 359 | } 360 | 361 | static size_t pir_length(const u8 *p) 362 | { 363 | return WORD(p + 6); 364 | } 365 | 366 | static void pir_link_bitmap(char letter, const u8 *p) 367 | { 368 | if (p[0] == 0) /* Not connected */ 369 | return; 370 | 371 | printf("\t\tINT%c#: Link 0x%02x, IRQ Bitmap", letter, p[0]); 372 | pir_irqs(WORD(p + 1)); 373 | printf("\n"); 374 | } 375 | 376 | static int pir_decode(const u8 *p, size_t len) 377 | { 378 | int i, n; 379 | 380 | if (len < 32 || !checksum(p, WORD(p + 6))) 381 | return 0; 382 | 383 | printf("PCI Interrupt Routing %u.%u present.\n", 384 | p[5], p[4]); 385 | printf("\tRouter Device: %02x:%02x.%1x\n", 386 | p[8], p[9]>>3, p[9] & 0x07); 387 | printf("\tExclusive IRQs:"); 388 | pir_irqs(WORD(p + 10)); 389 | printf("\n"); 390 | if (DWORD(p + 12) != 0) 391 | printf("\tCompatible Router: %04x:%04x\n", 392 | WORD(p + 12), WORD(p + 14)); 393 | if (DWORD(p + 16) != 0) 394 | printf("\tMiniport Data: 0x%08X\n", 395 | DWORD(p + 16)); 396 | 397 | n = (len - 32) / 16; 398 | for (i = 1, p += 32; i <= n; i++, p += 16) 399 | { 400 | printf("\tDevice: %02x:%02x,", p[0], p[1] >> 3); 401 | pir_slot_number(p[14]); 402 | printf("\n"); 403 | if (opt.pir == PIR_FULL) 404 | { 405 | pir_link_bitmap('A', p + 2); 406 | pir_link_bitmap('B', p + 5); 407 | pir_link_bitmap('C', p + 8); 408 | pir_link_bitmap('D', p + 11); 409 | } 410 | } 411 | 412 | return 1; 413 | } 414 | 415 | /* 416 | * Compaq-specific entries 417 | */ 418 | 419 | static size_t compaq_length(const u8 *p) 420 | { 421 | return p[4] * 10 + 5; 422 | } 423 | 424 | static int compaq_decode(const u8 *p, size_t len) 425 | { 426 | unsigned int i; 427 | (void) len; 428 | 429 | printf("Compaq-specific entries present.\n"); 430 | 431 | /* integrity checking (lack of checksum) */ 432 | for (i = 0; i < p[4]; i++) 433 | { 434 | /* 435 | * We do not check for truncated entries, because the length 436 | * was computed from the number of records in compaq_length 437 | * right above, so it can't be wrong. 438 | */ 439 | if (p[5 + i * 10] != '$' 440 | || !(p[6 + i * 10] >= 'A' && p[6 + i * 10] <= 'Z') 441 | || !(p[7 + i * 10] >= 'A' && p[7 + i * 10] <= 'Z') 442 | || !(p[8 + i * 10] >= 'A' && p[8 + i * 10] <= 'Z')) 443 | { 444 | printf("\t Abnormal entry! Please report. [%02X %02X " 445 | "%02X %02X]\n", p[5 + i * 10], p[6 + i * 10], 446 | p[7 + i * 10], p[8 + i * 10]); 447 | return 0; 448 | } 449 | } 450 | 451 | for (i = 0; i < p[4]; i++) 452 | { 453 | printf("\tEntry %u: %c%c%c%c at 0x%08X (%u bytes)\n", 454 | i + 1, p[5 + i * 10], p[6 + i * 10], p[7 + i * 10], 455 | p[8 + i * 10], DWORD(p + 9 + i * 10), 456 | WORD(p + 13 + i * 10)); 457 | } 458 | 459 | return 1; 460 | } 461 | 462 | /* 463 | * VPD (vital product data, IBM-specific) 464 | */ 465 | 466 | static void vpd_print_entry(const char *name, const u8 *p, size_t len) 467 | { 468 | size_t i; 469 | 470 | printf("\t%s: ", name); 471 | for (i = 0; i < len; i++) 472 | if (p[i] >= 32 && p[i] < 127) 473 | printf("%c", p[i]); 474 | printf("\n"); 475 | } 476 | 477 | static size_t vpd_length(const u8 *p) 478 | { 479 | return p[5]; 480 | } 481 | 482 | static int vpd_decode(const u8 *p, size_t len) 483 | { 484 | if (len < 0x30) 485 | return 0; 486 | 487 | /* XSeries have longer records. */ 488 | if (!(len >= 0x45 && checksum(p, len)) 489 | /* Some Netvista seem to work with this. */ 490 | && !checksum(p, 0x30) 491 | /* The Thinkpad checksum does *not* include the first 13 bytes. */ 492 | && !checksum(p + 0x0D, 0x30 - 0x0D)) 493 | return 0; 494 | 495 | printf("VPD present.\n"); 496 | 497 | vpd_print_entry("BIOS Build ID", p + 0x0D, 9); 498 | vpd_print_entry("Box Serial Number", p + 0x16, 7); 499 | vpd_print_entry("Motherboard Serial Number", p + 0x1D, 11); 500 | vpd_print_entry("Machine Type/Model", p + 0x28, 7); 501 | 502 | if (len < 0x45) 503 | return 1; 504 | 505 | vpd_print_entry("BIOS Release Date", p + 0x30, 8); 506 | 507 | return 1; 508 | } 509 | 510 | /* 511 | * Fujitsu application panel 512 | */ 513 | 514 | static size_t fjkeyinf_length(const u8 *p) 515 | { 516 | (void) p; 517 | /* 518 | * We don't know at this point, it's somewhere between 12 and 32. 519 | * So we return the max, it shouldn't hurt. 520 | */ 521 | return 32; 522 | } 523 | 524 | static int fjkeyinf_decode(const u8 *p, size_t len) 525 | { 526 | int i; 527 | (void) len; 528 | 529 | printf("Fujitsu application panel present.\n"); 530 | 531 | for (i = 0; i < 6; i++) 532 | { 533 | if (*(p + 8 + i * 4) == 0) 534 | return 1; 535 | printf("\tDevice %d: type %u, chip %u", i + 1, 536 | *(p + 8 + i * 4), *(p + 8 + i * 4 + 2)); 537 | if (*(p + 8 + i * 4 + 1)) /* Access method */ 538 | printf(", SMBus address 0x%x", 539 | *(p + 8 + i * 4 + 3) >> 1); 540 | printf("\n"); 541 | } 542 | 543 | return 1; 544 | } 545 | 546 | /* 547 | * Intel Multiprocessor 548 | */ 549 | 550 | static size_t mp_length(const u8 *p) 551 | { 552 | return 16 * p[8]; 553 | } 554 | 555 | static int mp_decode(const u8 *p, size_t len) 556 | { 557 | if (!checksum(p, len)) 558 | return 0; 559 | 560 | printf("Intel Multiprocessor present.\n"); 561 | printf("\tSpecification Revision: %s\n", 562 | p[9] == 0x01 ? "1.1" : p[9] == 0x04 ? "1.4" : "Invalid"); 563 | if (p[11]) 564 | printf("\tDefault Configuration: #%d\n", p[11]); 565 | else 566 | printf("\tConfiguration Table Address: 0x%08X\n", 567 | DWORD(p + 4)); 568 | printf("\tMode: %s\n", p[12] & (1 << 7) ? 569 | "IMCR and PIC" : "Virtual Wire"); 570 | 571 | return 1; 572 | } 573 | 574 | /* 575 | * Main 576 | */ 577 | 578 | static struct bios_entry bios_entries[] = { 579 | { "_SM3_", 0, 0xF0000, 0xFFFFF, smbios3_length, smbios3_decode }, 580 | { "_SM_", 0, 0xF0000, 0xFFFFF, smbios_length, smbios_decode }, 581 | { "_DMI_", 0, 0xF0000, 0xFFFFF, dmi_length, dmi_decode }, 582 | { "_SYSID_", 0, 0xE0000, 0xFFFFF, sysid_length, sysid_decode }, 583 | { "$PnP", 0, 0xF0000, 0xFFFFF, pnp_length, pnp_decode }, 584 | { "RSD PTR ", 0, 0xE0000, 0xFFFFF, acpi_length, acpi_decode }, 585 | { "$SNY", 0, 0xE0000, 0xFFFFF, sony_length, sony_decode }, 586 | { "_32_", 0, 0xE0000, 0xFFFFF, bios32_length, bios32_decode }, 587 | { "$PIR", 0, 0xF0000, 0xFFFFF, pir_length, pir_decode }, 588 | { "32OS", 0, 0xE0000, 0xFFFFF, compaq_length, compaq_decode }, 589 | { "\252\125VPD", 0, 0xF0000, 0xFFFFF, vpd_length, vpd_decode }, 590 | { "FJKEYINF", 0, 0xF0000, 0xFFFFF, fjkeyinf_length, fjkeyinf_decode }, 591 | { "_MP_", 0, 0xE0000, 0xFFFFF, mp_length, mp_decode }, 592 | { NULL, 0, 0, 0, NULL, NULL } 593 | }; 594 | 595 | /* Believe it or not, this is significantly faster than memcmp */ 596 | static int anchor_match(const struct bios_entry *entry, const char *p) 597 | { 598 | size_t i; 599 | 600 | for (i = 0; i < entry->anchor_len; i++) 601 | if (entry->anchor[i] != p[i]) 602 | return 0; 603 | 604 | return 1; 605 | } 606 | 607 | /* Return -1 on error, 0 on success */ 608 | static int parse_command_line(int argc, char * const argv[]) 609 | { 610 | int option; 611 | const char *optstring = "d:hV"; 612 | struct option longopts[] = { 613 | { "dev-mem", required_argument, NULL, 'd' }, 614 | { "pir", required_argument, NULL, 'P' }, 615 | { "help", no_argument, NULL, 'h' }, 616 | { "version", no_argument, NULL, 'V' }, 617 | { NULL, 0, NULL, 0 } 618 | }; 619 | 620 | while ((option = getopt_long(argc, argv, optstring, longopts, NULL)) != -1) 621 | switch (option) 622 | { 623 | case 'd': 624 | opt.devmem = optarg; 625 | break; 626 | case 'P': 627 | if (strcmp(optarg, "full") == 0) 628 | opt.pir = PIR_FULL; 629 | break; 630 | case 'h': 631 | opt.flags |= FLAG_HELP; 632 | break; 633 | case 'V': 634 | opt.flags |= FLAG_VERSION; 635 | break; 636 | case '?': 637 | return -1; 638 | } 639 | 640 | return 0; 641 | } 642 | 643 | static void print_help(void) 644 | { 645 | static const char *help = 646 | "Usage: biosdecode [OPTIONS]\n" 647 | "Options are:\n" 648 | " -d, --dev-mem FILE Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n" 649 | " --pir full Decode the details of the PCI IRQ routing table\n" 650 | " -h, --help Display this help text and exit\n" 651 | " -V, --version Display the version and exit\n"; 652 | 653 | printf("%s", help); 654 | } 655 | 656 | int main(int argc, char * const argv[]) 657 | { 658 | u8 *buf; 659 | off_t fp; 660 | int i; 661 | 662 | if (sizeof(u8) != 1 || sizeof(u16) != 2 || sizeof(u32) != 4) 663 | { 664 | fprintf(stderr, "%s: compiler incompatibility\n", argv[0]); 665 | exit(255); 666 | } 667 | 668 | /* Set default option values */ 669 | opt.devmem = DEFAULT_MEM_DEV; 670 | opt.flags = 0; 671 | 672 | if (parse_command_line(argc, argv) < 0) 673 | exit(2); 674 | 675 | if (opt.flags & FLAG_HELP) 676 | { 677 | print_help(); 678 | return 0; 679 | } 680 | 681 | if (opt.flags & FLAG_VERSION) 682 | { 683 | printf("%s\n", VERSION); 684 | return 0; 685 | } 686 | 687 | printf("# biosdecode %s\n", VERSION); 688 | 689 | if ((buf = mem_chunk(0xE0000, 0x20000, opt.devmem)) == NULL) 690 | exit(1); 691 | 692 | /* Compute anchor lengths once and for all */ 693 | for (i = 0; bios_entries[i].anchor != NULL; i++) 694 | bios_entries[i].anchor_len = strlen(bios_entries[i].anchor); 695 | 696 | for (fp = 0xE0000; fp <= 0xFFFF0; fp += 16) 697 | { 698 | u8 *p = buf + fp - 0xE0000; 699 | 700 | for (i = 0; bios_entries[i].anchor != NULL; i++) 701 | { 702 | if (anchor_match(&bios_entries[i], (char *)p) 703 | && fp >= bios_entries[i].low_address 704 | && fp < bios_entries[i].high_address) 705 | { 706 | off_t len = bios_entries[i].length(p); 707 | 708 | if (fp + len - 1 <= bios_entries[i].high_address) 709 | { 710 | if (bios_entries[i].decode(p, len)) 711 | { 712 | fp += (((len - 1) >> 4) << 4); 713 | break; 714 | } 715 | } 716 | } 717 | } 718 | } 719 | 720 | free(buf); 721 | 722 | return 0; 723 | } 724 | -------------------------------------------------------------------------------- /completion/biosdecode.bash: -------------------------------------------------------------------------------- 1 | # bash completion for biosdecode -*- shell-script -*- 2 | 3 | _comp_cmd_biosdecode() { 4 | local cur prev 5 | COMPREPLY=() 6 | cur=${COMP_WORDS[COMP_CWORD]} 7 | prev=${COMP_WORDS[COMP_CWORD - 1]} 8 | 9 | case $prev in 10 | -d | --dev-mem) 11 | : "${cur:=/dev/}" 12 | local IFS=$'\n' 13 | compopt -o filenames 14 | COMPREPLY=($(compgen -f -- "$cur")) 15 | return 0 16 | ;; 17 | --pir) 18 | COMPREPLY=($(compgen -W ' 19 | full 20 | ' -- "$cur")) 21 | return 0 22 | ;; 23 | -[hV] | --help | --version) 24 | return 0 25 | ;; 26 | esac 27 | 28 | if [[ $cur == -* ]]; then 29 | COMPREPLY=($(compgen -W ' 30 | --dev-mem 31 | --pir 32 | --help 33 | --version 34 | ' -- "$cur")) 35 | return 0 36 | fi 37 | 38 | } && complete -F _comp_cmd_biosdecode biosdecode 39 | 40 | # ex: filetype=sh 41 | -------------------------------------------------------------------------------- /completion/dmidecode.bash: -------------------------------------------------------------------------------- 1 | # bash completion for dmidecode -*- shell-script -*- 2 | 3 | _comp_cmd_dmidecode() { 4 | local cur prev 5 | COMPREPLY=() 6 | cur=${COMP_WORDS[COMP_CWORD]} 7 | prev=${COMP_WORDS[COMP_CWORD - 1]} 8 | 9 | case $prev in 10 | -d | --dev-mem | --dump-bin | --from-dump) 11 | if [[ $prev == -d || $prev == --dev-mem ]]; then 12 | : "${cur:=/dev/}" 13 | fi 14 | local IFS=$'\n' 15 | compopt -o filenames 16 | COMPREPLY=($(compgen -f -- "$cur")) 17 | return 0 18 | ;; 19 | -s | --string) 20 | COMPREPLY=($(compgen -W '$("$1" --list-strings)' -- "$cur")) 21 | return 0 22 | ;; 23 | -t | --type) 24 | COMPREPLY=($(compgen -W '$("$1" --list-types)' -- "$cur")) 25 | return 0 26 | ;; 27 | --dump-bin | --from-dump) 28 | local IFS=$'\n' 29 | compopt -o filenames 30 | COMPREPLY=($(compgen -f -- "$cur")) 31 | return 0 32 | ;; 33 | -[hVH] | --help | --version | --handle | --oem-string) 34 | return 0 35 | ;; 36 | esac 37 | 38 | if [[ $cur == -* ]]; then 39 | COMPREPLY=($(compgen -W ' 40 | --dev-mem 41 | --help 42 | --quiet 43 | --string 44 | --list-strings 45 | --type 46 | --list-types 47 | --handle 48 | --dump 49 | --dump-bin 50 | --from-dump 51 | --no-sysfs 52 | --oem-string 53 | --version 54 | ' -- "$cur")) 55 | return 0 56 | fi 57 | 58 | } && complete -F _comp_cmd_dmidecode dmidecode 59 | 60 | # ex: filetype=sh 61 | -------------------------------------------------------------------------------- /completion/ownership.bash: -------------------------------------------------------------------------------- 1 | # bash completion for ownership -*- shell-script -*- 2 | 3 | _comp_cmd_ownership() { 4 | local cur prev 5 | COMPREPLY=() 6 | cur=${COMP_WORDS[COMP_CWORD]} 7 | prev=${COMP_WORDS[COMP_CWORD - 1]} 8 | 9 | case $prev in 10 | -d | --dev-mem) 11 | : "${cur:=/dev/}" 12 | local IFS=$'\n' 13 | compopt -o filenames 14 | COMPREPLY=($(compgen -f -- "$cur")) 15 | return 0 16 | ;; 17 | -[hV] | --help | --version) 18 | return 0 19 | ;; 20 | esac 21 | 22 | if [[ $cur == -* ]]; then 23 | COMPREPLY=($(compgen -W ' 24 | --dev-mem 25 | --help 26 | --version 27 | ' -- "$cur")) 28 | return 0 29 | fi 30 | 31 | } && complete -F _comp_cmd_ownership ownership 32 | 33 | # ex: filetype=sh 34 | -------------------------------------------------------------------------------- /completion/vpddecode.bash: -------------------------------------------------------------------------------- 1 | # bash completion for vpddecode -*- shell-script -*- 2 | 3 | _comp_cmd_vpddecode() { 4 | local cur prev 5 | COMPREPLY=() 6 | cur=${COMP_WORDS[COMP_CWORD]} 7 | prev=${COMP_WORDS[COMP_CWORD - 1]} 8 | 9 | case $prev in 10 | -d | --dev-mem) 11 | : "${cur:=/dev/}" 12 | local IFS=$'\n' 13 | compopt -o filenames 14 | COMPREPLY=($(compgen -f -- "$cur")) 15 | return 0 16 | ;; 17 | -s | --string) 18 | COMPREPLY=($(compgen -W '$( 19 | "$1" --string 2>&1 | while IFS=\$'\\n' read -r line ; do 20 | [[ $line == " "* ]] && printf "%s\n" "$line" 21 | done 22 | ' -- "$cur")) 23 | return 0 24 | ;; 25 | -[hV] | --help | --version) 26 | return 0 27 | ;; 28 | esac 29 | 30 | if [[ $cur == -* ]]; then 31 | COMPREPLY=($(compgen -W ' 32 | --dev-mem 33 | --help 34 | --string 35 | --dump 36 | --version 37 | ' -- "$cur")) 38 | return 0 39 | fi 40 | 41 | } && complete -F _comp_cmd_vpddecode vpddecode 42 | 43 | # ex: filetype=sh 44 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Configuration 3 | */ 4 | 5 | #ifndef CONFIG_H 6 | #define CONFIG_H 7 | 8 | /* Default memory device file */ 9 | #if defined(__BEOS__) || defined(__HAIKU__) 10 | #define DEFAULT_MEM_DEV "/dev/misc/mem" 11 | #elif defined(__sun) 12 | #define DEFAULT_MEM_DEV "/dev/xsvc" 13 | #elif defined(__APPLE__) 14 | #define DEFAULT_MEM_DEV "I/O Registry" 15 | #else 16 | #define DEFAULT_MEM_DEV "/dev/mem" 17 | #endif 18 | 19 | /* Use mmap or not */ 20 | #ifndef __BEOS__ 21 | #define USE_MMAP 22 | #endif 23 | 24 | /* Use memory alignment workaround or not */ 25 | #ifndef FORCE_UNALIGNED_READ 26 | #define ALIGNMENT_WORKAROUND 27 | #endif 28 | 29 | /* Avoid unaligned memcpy on /dev/mem */ 30 | #ifdef __aarch64__ 31 | #define USE_SLOW_MEMCPY 32 | #endif 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /dmidecode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the dmidecode project. 3 | * 4 | * Copyright (C) 2005-2023 Jean Delvare 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #ifndef DMIDECODE_H 22 | #define DMIDECODE_H 23 | 24 | #include "types.h" 25 | 26 | struct dmi_header 27 | { 28 | u8 type; 29 | u8 length; 30 | u16 handle; 31 | u8 *data; 32 | }; 33 | 34 | enum cpuid_type 35 | { 36 | cpuid_none, 37 | cpuid_80386, 38 | cpuid_80486, 39 | cpuid_arm_legacy, 40 | cpuid_arm_soc_id, 41 | cpuid_x86_intel, 42 | cpuid_x86_amd, 43 | cpuid_loongarch, 44 | }; 45 | 46 | extern enum cpuid_type cpuid_type; 47 | 48 | int is_printable(const u8 *data, int len); 49 | const char *dmi_string(const struct dmi_header *dm, u8 s); 50 | void dmi_print_memory_size(const char *addr, u64 code, int shift); 51 | void dmi_print_cpuid(void (*print_cb)(const char *name, const char *format, ...), 52 | const char *label, enum cpuid_type sig, const u8 *p); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /dmidecode.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXFileReference section */ 10 | 12ECFB3F1852EADE0028E3A9 /* .DS_Store */ = {isa = PBXFileReference; lastKnownFileType = file; path = .DS_Store; sourceTree = ""; }; 11 | 12ECFB401852EADE0028E3A9 /* AUTHORS */ = {isa = PBXFileReference; lastKnownFileType = text; path = AUTHORS; sourceTree = ""; }; 12 | 12ECFB411852EADE0028E3A9 /* biosdecode */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = biosdecode; sourceTree = ""; }; 13 | 12ECFB421852EADE0028E3A9 /* biosdecode.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = biosdecode.c; sourceTree = ""; }; 14 | 12ECFB431852EADE0028E3A9 /* biosdecode.o */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.objfile"; path = biosdecode.o; sourceTree = ""; }; 15 | 12ECFB451852EADE0028E3A9 /* config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; 16 | 12ECFB461852EADE0028E3A9 /* dmidecode */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = dmidecode; sourceTree = ""; }; 17 | 12ECFB471852EADE0028E3A9 /* dmidecode.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dmidecode.c; sourceTree = ""; }; 18 | 12ECFB481852EADE0028E3A9 /* dmidecode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dmidecode.h; sourceTree = ""; }; 19 | 12ECFB491852EADE0028E3A9 /* dmidecode.o */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.objfile"; path = dmidecode.o; sourceTree = ""; }; 20 | 12ECFB4A1852EADE0028E3A9 /* dmioem.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dmioem.c; sourceTree = ""; }; 21 | 12ECFB4B1852EADE0028E3A9 /* dmioem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dmioem.h; sourceTree = ""; }; 22 | 12ECFB4C1852EADE0028E3A9 /* dmioem.o */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.objfile"; path = dmioem.o; sourceTree = ""; }; 23 | 12ECFB4D1852EADE0028E3A9 /* dmiopt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dmiopt.c; sourceTree = ""; }; 24 | 12ECFB4E1852EADE0028E3A9 /* dmiopt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dmiopt.h; sourceTree = ""; }; 25 | 12ECFB4F1852EADE0028E3A9 /* dmiopt.o */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.objfile"; path = dmiopt.o; sourceTree = ""; }; 26 | 12ECFB501852EADE0028E3A9 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 27 | 12ECFB511852EADE0028E3A9 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; 28 | 12ECFB521852EADE0028E3A9 /* man */ = {isa = PBXFileReference; lastKnownFileType = folder; path = man; sourceTree = ""; }; 29 | 12ECFB531852EADE0028E3A9 /* ownership */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = ownership; sourceTree = ""; }; 30 | 12ECFB541852EADE0028E3A9 /* ownership.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ownership.c; sourceTree = ""; }; 31 | 12ECFB551852EADE0028E3A9 /* ownership.o */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.objfile"; path = ownership.o; sourceTree = ""; }; 32 | 12ECFB571852EADE0028E3A9 /* types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = ""; }; 33 | 12ECFB581852EADE0028E3A9 /* util.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = ""; }; 34 | 12ECFB591852EADE0028E3A9 /* util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = ""; }; 35 | 12ECFB5A1852EADE0028E3A9 /* util.o */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.objfile"; path = util.o; sourceTree = ""; }; 36 | 12ECFB5B1852EADE0028E3A9 /* version.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = ""; }; 37 | 12ECFB5C1852EADE0028E3A9 /* vpddecode */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = vpddecode; sourceTree = ""; }; 38 | 12ECFB5D1852EADE0028E3A9 /* vpddecode.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vpddecode.c; sourceTree = ""; }; 39 | 12ECFB5E1852EADE0028E3A9 /* vpddecode.o */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.objfile"; path = vpddecode.o; sourceTree = ""; }; 40 | 12ECFB5F1852EADE0028E3A9 /* vpdopt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vpdopt.c; sourceTree = ""; }; 41 | 12ECFB601852EADE0028E3A9 /* vpdopt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vpdopt.h; sourceTree = ""; }; 42 | 12ECFB611852EADE0028E3A9 /* vpdopt.o */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.objfile"; path = vpdopt.o; sourceTree = ""; }; 43 | /* End PBXFileReference section */ 44 | 45 | /* Begin PBXGroup section */ 46 | 12ECFB391852EADE0028E3A9 = { 47 | isa = PBXGroup; 48 | children = ( 49 | 12ECFB3F1852EADE0028E3A9 /* .DS_Store */, 50 | 12ECFB401852EADE0028E3A9 /* AUTHORS */, 51 | 12ECFB411852EADE0028E3A9 /* biosdecode */, 52 | 12ECFB421852EADE0028E3A9 /* biosdecode.c */, 53 | 12ECFB431852EADE0028E3A9 /* biosdecode.o */, 54 | 12ECFB451852EADE0028E3A9 /* config.h */, 55 | 12ECFB461852EADE0028E3A9 /* dmidecode */, 56 | 12ECFB471852EADE0028E3A9 /* dmidecode.c */, 57 | 12ECFB481852EADE0028E3A9 /* dmidecode.h */, 58 | 12ECFB491852EADE0028E3A9 /* dmidecode.o */, 59 | 12ECFB4A1852EADE0028E3A9 /* dmioem.c */, 60 | 12ECFB4B1852EADE0028E3A9 /* dmioem.h */, 61 | 12ECFB4C1852EADE0028E3A9 /* dmioem.o */, 62 | 12ECFB4D1852EADE0028E3A9 /* dmiopt.c */, 63 | 12ECFB4E1852EADE0028E3A9 /* dmiopt.h */, 64 | 12ECFB4F1852EADE0028E3A9 /* dmiopt.o */, 65 | 12ECFB501852EADE0028E3A9 /* LICENSE */, 66 | 12ECFB511852EADE0028E3A9 /* Makefile */, 67 | 12ECFB521852EADE0028E3A9 /* man */, 68 | 12ECFB531852EADE0028E3A9 /* ownership */, 69 | 12ECFB541852EADE0028E3A9 /* ownership.c */, 70 | 12ECFB551852EADE0028E3A9 /* ownership.o */, 71 | 12ECFB571852EADE0028E3A9 /* types.h */, 72 | 12ECFB581852EADE0028E3A9 /* util.c */, 73 | 12ECFB591852EADE0028E3A9 /* util.h */, 74 | 12ECFB5A1852EADE0028E3A9 /* util.o */, 75 | 12ECFB5B1852EADE0028E3A9 /* version.h */, 76 | 12ECFB5C1852EADE0028E3A9 /* vpddecode */, 77 | 12ECFB5D1852EADE0028E3A9 /* vpddecode.c */, 78 | 12ECFB5E1852EADE0028E3A9 /* vpddecode.o */, 79 | 12ECFB5F1852EADE0028E3A9 /* vpdopt.c */, 80 | 12ECFB601852EADE0028E3A9 /* vpdopt.h */, 81 | 12ECFB611852EADE0028E3A9 /* vpdopt.o */, 82 | ); 83 | sourceTree = ""; 84 | }; 85 | /* End PBXGroup section */ 86 | 87 | /* Begin PBXLegacyTarget section */ 88 | 12ECFB3E1852EADE0028E3A9 /* dmidecode */ = { 89 | isa = PBXLegacyTarget; 90 | buildArgumentsString = "$(ACTION)"; 91 | buildConfigurationList = 12ECFB621852EADE0028E3A9 /* Build configuration list for PBXLegacyTarget "dmidecode" */; 92 | buildPhases = ( 93 | ); 94 | buildToolPath = /usr/bin/make; 95 | buildWorkingDirectory = "$(PROJECT_DIR)"; 96 | dependencies = ( 97 | ); 98 | name = dmidecode; 99 | passBuildSettingsInEnvironment = 1; 100 | productName = dmidecode; 101 | }; 102 | /* End PBXLegacyTarget section */ 103 | 104 | /* Begin PBXProject section */ 105 | 12ECFB3A1852EADE0028E3A9 /* Project object */ = { 106 | isa = PBXProject; 107 | attributes = { 108 | LastUpgradeCheck = 1530; 109 | }; 110 | buildConfigurationList = 12ECFB3D1852EADE0028E3A9 /* Build configuration list for PBXProject "dmidecode" */; 111 | compatibilityVersion = "Xcode 3.2"; 112 | developmentRegion = en; 113 | hasScannedForEncodings = 0; 114 | knownRegions = ( 115 | en, 116 | Base, 117 | ); 118 | mainGroup = 12ECFB391852EADE0028E3A9; 119 | projectDirPath = ""; 120 | projectRoot = ""; 121 | targets = ( 122 | 12ECFB3E1852EADE0028E3A9 /* dmidecode */, 123 | ); 124 | }; 125 | /* End PBXProject section */ 126 | 127 | /* Begin XCBuildConfiguration section */ 128 | 12ECFB3B1852EADE0028E3A9 /* Debug */ = { 129 | isa = XCBuildConfiguration; 130 | buildSettings = { 131 | COPY_PHASE_STRIP = NO; 132 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 133 | GCC_WARN_UNUSED_VARIABLE = YES; 134 | ONLY_ACTIVE_ARCH = YES; 135 | }; 136 | name = Debug; 137 | }; 138 | 12ECFB3C1852EADE0028E3A9 /* Release */ = { 139 | isa = XCBuildConfiguration; 140 | buildSettings = { 141 | COPY_PHASE_STRIP = YES; 142 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 143 | GCC_WARN_UNUSED_VARIABLE = YES; 144 | }; 145 | name = Release; 146 | }; 147 | 12ECFB631852EADE0028E3A9 /* Debug */ = { 148 | isa = XCBuildConfiguration; 149 | buildSettings = { 150 | COPY_PHASE_STRIP = NO; 151 | DEBUGGING_SYMBOLS = YES; 152 | GCC_DYNAMIC_NO_PIC = NO; 153 | GCC_ENABLE_FIX_AND_CONTINUE = YES; 154 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES; 155 | GCC_OPTIMIZATION_LEVEL = 0; 156 | OTHER_CFLAGS = ""; 157 | OTHER_LDFLAGS = ""; 158 | PRODUCT_NAME = dmidecode; 159 | }; 160 | name = Debug; 161 | }; 162 | 12ECFB641852EADE0028E3A9 /* Release */ = { 163 | isa = XCBuildConfiguration; 164 | buildSettings = { 165 | COPY_PHASE_STRIP = YES; 166 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 167 | GCC_ENABLE_FIX_AND_CONTINUE = NO; 168 | OTHER_CFLAGS = ""; 169 | OTHER_LDFLAGS = ""; 170 | PRODUCT_NAME = dmidecode; 171 | }; 172 | name = Release; 173 | }; 174 | /* End XCBuildConfiguration section */ 175 | 176 | /* Begin XCConfigurationList section */ 177 | 12ECFB3D1852EADE0028E3A9 /* Build configuration list for PBXProject "dmidecode" */ = { 178 | isa = XCConfigurationList; 179 | buildConfigurations = ( 180 | 12ECFB3B1852EADE0028E3A9 /* Debug */, 181 | 12ECFB3C1852EADE0028E3A9 /* Release */, 182 | ); 183 | defaultConfigurationIsVisible = 0; 184 | defaultConfigurationName = Release; 185 | }; 186 | 12ECFB621852EADE0028E3A9 /* Build configuration list for PBXLegacyTarget "dmidecode" */ = { 187 | isa = XCConfigurationList; 188 | buildConfigurations = ( 189 | 12ECFB631852EADE0028E3A9 /* Debug */, 190 | 12ECFB641852EADE0028E3A9 /* Release */, 191 | ); 192 | defaultConfigurationIsVisible = 0; 193 | defaultConfigurationName = Release; 194 | }; 195 | /* End XCConfigurationList section */ 196 | }; 197 | rootObject = 12ECFB3A1852EADE0028E3A9 /* Project object */; 198 | } 199 | -------------------------------------------------------------------------------- /dmioem.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Decoding of OEM-specific entries 3 | * This file is part of the dmidecode project. 4 | * 5 | * Copyright (C) 2007-2024 Jean Delvare 6 | * Copyright (C) 2017-2024 Jerry Hoemann 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "types.h" 27 | #include "util.h" 28 | #include "dmidecode.h" 29 | #include "dmioem.h" 30 | #include "dmiopt.h" 31 | #include "dmioutput.h" 32 | 33 | /* 34 | * Globals for vendor-specific decodes 35 | */ 36 | 37 | enum DMI_VENDORS 38 | { 39 | VENDOR_UNKNOWN, 40 | VENDOR_ACER, 41 | VENDOR_HP, 42 | VENDOR_HPE, 43 | VENDOR_IBM, 44 | VENDOR_LENOVO, 45 | }; 46 | 47 | static enum DMI_VENDORS dmi_vendor = VENDOR_UNKNOWN; 48 | static const char *dmi_product = NULL; 49 | 50 | /* 51 | * Remember the system vendor for later use. We only actually store the 52 | * value if we know how to decode at least one specific entry type for 53 | * that vendor. 54 | */ 55 | void dmi_set_vendor(const char *v, const char *p) 56 | { 57 | const struct { const char *str; enum DMI_VENDORS id; } vendor[] = { 58 | { "Acer", VENDOR_ACER }, 59 | { "HP", VENDOR_HP }, 60 | { "Hewlett-Packard", VENDOR_HP }, 61 | { "HPE", VENDOR_HPE }, 62 | { "Hewlett Packard Enterprise", VENDOR_HPE }, 63 | { "IBM", VENDOR_IBM }, 64 | { "LENOVO", VENDOR_LENOVO }, 65 | }; 66 | unsigned int i; 67 | size_t len; 68 | 69 | /* 70 | * Often DMI strings have trailing spaces. Ignore these 71 | * when checking for known vendor names. 72 | */ 73 | len = v ? strlen(v) : 0; 74 | while (len && v[len - 1] == ' ') 75 | len--; 76 | 77 | for (i = 0; i < ARRAY_SIZE(vendor); i++) 78 | { 79 | if (strlen(vendor[i].str) == len && 80 | strncmp(v, vendor[i].str, len) == 0) 81 | { 82 | dmi_vendor = vendor[i].id; 83 | break; 84 | } 85 | } 86 | 87 | dmi_product = p; 88 | } 89 | 90 | /* 91 | * Acer-specific data structures are decoded here. 92 | */ 93 | 94 | static int dmi_decode_acer(const struct dmi_header *h) 95 | { 96 | u8 *data = h->data; 97 | u16 cap; 98 | 99 | switch (h->type) 100 | { 101 | case 170: 102 | /* 103 | * Vendor Specific: Acer Hotkey Function 104 | * 105 | * Source: acer-wmi kernel driver 106 | * 107 | * Probably applies to some laptop models of other 108 | * brands, including Fujitsu-Siemens, Medion, Lenovo, 109 | * and eMachines. 110 | */ 111 | pr_handle_name("Acer Hotkey Function"); 112 | if (h->length < 0x0F) break; 113 | cap = WORD(data + 0x04); 114 | pr_attr("Function bitmap for Communication Button", "0x%04hx", cap); 115 | pr_subattr("WiFi", "%s", cap & 0x0001 ? "Yes" : "No"); 116 | pr_subattr("3G", "%s", cap & 0x0040 ? "Yes" : "No"); 117 | pr_subattr("WiMAX", "%s", cap & 0x0080 ? "Yes" : "No"); 118 | pr_subattr("Bluetooth", "%s", cap & 0x0800 ? "Yes" : "No"); 119 | pr_attr("Function bitmap for Application Button", "0x%04hx", WORD(data + 0x06)); 120 | pr_attr("Function bitmap for Media Button", "0x%04hx", WORD(data + 0x08)); 121 | pr_attr("Function bitmap for Display Button", "0x%04hx", WORD(data + 0x0A)); 122 | pr_attr("Function bitmap for Others Button", "0x%04hx", WORD(data + 0x0C)); 123 | pr_attr("Communication Function Key Number", "%d", data[0x0E]); 124 | break; 125 | 126 | default: 127 | return 0; 128 | } 129 | return 1; 130 | } 131 | 132 | /* 133 | * HPE-specific data structures are decoded here. 134 | * 135 | * Code contributed by John Cagle and Tyler Bell. 136 | */ 137 | 138 | static void dmi_print_hp_net_iface_rec(u8 id, u8 bus, u8 dev, const u8 *mac) 139 | { 140 | /* Some systems do not provide an id. nic_ctr provides an artificial 141 | * id, and assumes the records will be provided "in order". Also, 142 | * using 0xFF marker is not future proof. 256 NICs is a lot, but 143 | * 640K ought to be enough for anybody(said no one, ever). 144 | * */ 145 | static u8 nic_ctr; 146 | char attr[8]; 147 | 148 | if (id == 0xFF) 149 | id = ++nic_ctr; 150 | 151 | sprintf(attr, "NIC %hhu", id); 152 | if (dev == 0x00 && bus == 0x00) 153 | pr_attr(attr, "Disabled"); 154 | else if (dev == 0xFF && bus == 0xFF) 155 | pr_attr(attr, "Not Installed"); 156 | else 157 | { 158 | pr_attr(attr, "PCI device %02x:%02x.%x, " 159 | "MAC address %02X:%02X:%02X:%02X:%02X:%02X", 160 | bus, dev >> 3, dev & 7, 161 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 162 | } 163 | } 164 | 165 | typedef enum { G6 = 6, G7, G8, G9, G10, G10P, G11 } dmi_hpegen_t; 166 | 167 | static int dmi_hpegen(const char *s) 168 | { 169 | struct { const char *name; dmi_hpegen_t gen; } table[] = { 170 | { "Gen11", G11 }, 171 | { "Gen10 Plus", G10P }, 172 | { "Gen10", G10 }, 173 | { "Gen9", G9 }, 174 | { "Gen8", G8 }, 175 | { "G7", G7 }, 176 | { "G6", G6 }, 177 | }; 178 | unsigned int i; 179 | 180 | if (!strstr(s, "ProLiant") && !strstr(s, "Apollo") && 181 | !strstr(s, "Synergy") && !strstr(s, "Edgeline")) 182 | return -1; 183 | 184 | for (i = 0; i < ARRAY_SIZE(table); i++) { 185 | if (strstr(s, table[i].name)) 186 | return(table[i].gen); 187 | } 188 | 189 | return (dmi_vendor == VENDOR_HPE) ? G10P : G6; 190 | } 191 | 192 | static void dmi_hp_197_qdf(const u8 *qdf) 193 | { 194 | char str[7]; 195 | int i, j, len = 6; 196 | 197 | if (!is_printable(qdf, len)) 198 | return; 199 | 200 | for (i = 0, j = 0; i < len; i++) 201 | { 202 | if (qdf[i] != ' ') 203 | str[j++] = qdf[i]; 204 | } 205 | str[j] = '\0'; 206 | pr_attr("QDF/S-SPEC", "%s", str); 207 | } 208 | 209 | static void dmi_hp_203_assoc_hndl(const char *fname, u16 num) 210 | { 211 | if (opt.flags & FLAG_QUIET) 212 | return; 213 | 214 | if (num == 0xFFFE) 215 | pr_attr(fname, "N/A"); 216 | else 217 | pr_attr(fname, "0x%04X", num); 218 | } 219 | 220 | static void dmi_hp_203_pciinfo(const char *fname, u16 num) 221 | { 222 | if (num == 0xFFFF) 223 | pr_attr(fname, "Device Not Present"); 224 | else 225 | pr_attr(fname, "0x%04x", num); 226 | } 227 | 228 | static void dmi_hp_203_bayenc(const char *fname, u8 num) 229 | { 230 | switch (num) 231 | { 232 | case 0x00: 233 | pr_attr(fname, "Unknown"); 234 | break; 235 | case 0xff: 236 | pr_attr(fname, "Do Not Display"); 237 | break; 238 | default: 239 | pr_attr(fname, "%d", num); 240 | } 241 | } 242 | 243 | static void dmi_hp_203_devtyp(const char *fname, unsigned int code) 244 | { 245 | const char *str = "Reserved"; 246 | static const char *type[] = { 247 | "Unknown", /* 0x00 */ 248 | "Reserved", 249 | "Reserved", 250 | "Flexible LOM", 251 | "Embedded LOM", 252 | "NIC in a Slot", 253 | "Storage Controller", 254 | "Smart Array Storage Controller", 255 | "USB Hard Disk", 256 | "Other PCI Device", 257 | "RAM Disk", 258 | "Firmware Volume", 259 | "UEFI Shell", 260 | "Generic UEFI USB Boot Entry", 261 | "Dynamic Smart Array Controller", 262 | "File", 263 | "NVME Hard Drive", 264 | "NVDIMM" /* 0x11 */ 265 | }; 266 | 267 | if (code < ARRAY_SIZE(type)) 268 | str = type[code]; 269 | 270 | pr_attr(fname, "%s", str); 271 | } 272 | 273 | static void dmi_hp_203_devloc(const char *fname, unsigned int code) 274 | { 275 | const char *str = "Reserved"; 276 | static const char *location[] = { 277 | "Unknown", /* 0x00 */ 278 | "Embedded", 279 | "iLO Virtual Media", 280 | "Front USB Port", 281 | "Rear USB Port", 282 | "Internal USB", 283 | "Internal SD Card", 284 | "Internal Virtual USB (Embedded NAND)", 285 | "Embedded SATA Port", 286 | "Embedded Smart Array", 287 | "PCI Slot", 288 | "RAM Memory", 289 | "USB", 290 | "Dynamic Smart Array Controller", 291 | "URL", 292 | "NVMe Drive Bay", /* 0x0F */ 293 | "NVDIMM Processor", 294 | "NVDIMM Board", 295 | "NVMe Riser", 296 | "NVDIMM Name Space", 297 | "VROC SATA", 298 | "VROC NVMe", /* 0x15 */ 299 | }; 300 | 301 | if (code < ARRAY_SIZE(location)) 302 | str = location[code]; 303 | 304 | pr_attr(fname, "%s", str); 305 | } 306 | 307 | static void dmi_hp_216_fw_type(u16 code) 308 | { 309 | const char *str = "Reserved"; 310 | static const char * const type[] = { 311 | "Reserved", /* 0x00 */ 312 | "System ROM", 313 | "Redundant System ROM", 314 | "System ROM Bootblock", 315 | "Power Management Controller Firmware", 316 | "Power Management Controller Firmware Bootloader", 317 | "SL Chassis Firmware", 318 | "SL Chassis Firmware Bootloader", 319 | "Hardware PAL/CPLD", 320 | "SPS Firmware (ME Firmware)", 321 | "SL Chassis PAL/CPLD", 322 | "Compatibility Support Module (CSM)", 323 | "APML", 324 | "Smart Storage Battery (Megacell) Firmware", 325 | "Trusted Module (TPM or TCM) Firmware Version", 326 | "NVMe Backplane Firmware", 327 | "Intelligent Provisioning", 328 | "SPI Descriptor Version", 329 | "Innovation Engine Firmware (IE Firmware)", 330 | "UMB Backplane Firmware", 331 | "Reserved", /* 0x14 */ 332 | "Reserved", 333 | "Reserved", 334 | "Reserved", 335 | "Reserved", 336 | "Reserved", 337 | "Reserved", 338 | "Reserved", 339 | "Reserved", 340 | "Reserved", 341 | "Reserved", 342 | "Reserved", /* 0x1F */ 343 | "EL Chassis Abstraction Revision", 344 | "EL Chassis Firmware Revision", 345 | "EL Chassis PAL/CPLD", 346 | "EL Cartride Abstraction Revision", 347 | "Reserved", /* 0x24 */ 348 | "Reserved", 349 | "Reserved", 350 | "Reserved", 351 | "Reserved", 352 | "Reserved", 353 | "Reserved", 354 | "Reserved", 355 | "Reserved", 356 | "Reserved", 357 | "Reserved", 358 | "Reserved", /* 0x2F */ 359 | "Embedded Video Controller", 360 | "PCIe Riser Programmable Logic Device", 361 | "PCIe cards that contain a CPLD", 362 | "Intel NVMe VROC", 363 | "Intel SATA VROC", 364 | "Intel SPS Firmware", 365 | "Secondary System Programmable Logic Device", 366 | "CPU MEZZ Programmable Logic Device", /* 0x37 */ 367 | "Intel Artic Sound -M Accelerator Models Firmware", 368 | "Ampere System Control Processor (SCP - PMPro+SMPro)", 369 | "Intel CFR information", /* 0x3A */ 370 | "OCP cards", 371 | "DC-SCM CPLD", 372 | }; 373 | 374 | if (code < ARRAY_SIZE(type)) 375 | str = type[code]; 376 | 377 | pr_attr("Firmware Type", "%s", str); 378 | } 379 | 380 | static void dmi_hp_216_version(u8 format, u8 *data) 381 | { 382 | const char * const name = "Version Data"; 383 | const char * const reserved = "Reserved"; 384 | int gen; 385 | 386 | gen = dmi_hpegen(dmi_product); 387 | 388 | switch (format) { 389 | case 0: 390 | pr_attr(name, "No Version Data"); 391 | break; 392 | case 1: 393 | if (data[0] >> 7) 394 | pr_attr(name, "0x%02X B.0x%02X", data[1] & 0x7F, data[0] & 0x7F); 395 | else 396 | pr_attr(name, "0x%02X", data[1] & 0x7F); 397 | break; 398 | case 2: 399 | pr_attr(name, "%d.%d", data[0] >> 4, data[0] & 0x0f); 400 | break; 401 | case 4: 402 | pr_attr(name, "%d.%d.%d", data[0] >> 4, data[0] & 0x0f, data[1] & 0x7f); 403 | break; 404 | case 5: 405 | if (gen == G9) { 406 | pr_attr(name, "%d.%d.%d", data[0] >> 4, data[0] & 0x0f, data[1] & 0x7f); 407 | } else if (gen == G10 || gen == G10P) { 408 | pr_attr(name, "%d.%d.%d.%d", data[1] & 0x0f, data[3] & 0x0f, 409 | data[5] & 0x0f, data[6] & 0x0f); 410 | } else { 411 | pr_attr(name, "%s", reserved); 412 | } 413 | break; 414 | case 6: 415 | pr_attr(name, "%d.%d", data[1], data[0]); 416 | break; 417 | case 7: 418 | pr_attr(name, "v%d.%.2d (%.2d/%.2d/%d)", data[0], data[1], 419 | data[2], data[3], WORD(data + 4)); 420 | break; 421 | case 8: 422 | pr_attr(name, "%d.%d", WORD(data + 4), WORD(data)); 423 | break; 424 | case 9: 425 | pr_attr(name, "%d.%d.%d", data[0], data[1], WORD(data + 2)); 426 | break; 427 | case 10: 428 | pr_attr(name, "%d.%d.%d Build %d", data[0], data[1], data[2], data[3]); 429 | break; 430 | case 11: 431 | pr_attr(name, "%d.%d %d", WORD(data + 2), WORD(data), DWORD(data + 4)); 432 | break; 433 | case 12: 434 | pr_attr(name, "%d.%d.%d.%d", WORD(data), WORD(data + 2), 435 | WORD(data + 4), WORD(data + 6)); 436 | break; 437 | case 13: 438 | pr_attr(name, "%d", data[0]); 439 | break; 440 | case 14: 441 | pr_attr(name, "%d.%d.%d.%d", data[0], data[1], data[2], data[3]); 442 | break; 443 | case 15: 444 | pr_attr(name, "%d.%d.%d.%d (%.2d/%.2d/%d)", 445 | WORD(data), WORD(data + 2), WORD(data + 4), WORD(data + 6), 446 | data[8], data[9], WORD(data + 10)); 447 | break; 448 | case 16: 449 | pr_attr(name, "%c%c%c%c.%d%d", 450 | data[0], data[1], data[2], data[3], data[4], data[5]); 451 | break; 452 | case 17: 453 | pr_attr(name, "%08X", DWORD(data)); 454 | break; 455 | case 18: 456 | pr_attr(name, "%d.%2d", data[0], data[1]); 457 | break; 458 | case 3: /* fall through */ 459 | default: 460 | pr_attr(name, "%s", reserved); 461 | } 462 | } 463 | 464 | static int dmi_hp_224_status(u8 code) 465 | { 466 | static const char * const present[] = { 467 | "Not Present", /* 0x00 */ 468 | "Present/Enabled", 469 | "Present/Disabled", 470 | "Reserved" /* 0x03 */ 471 | }; 472 | 473 | pr_attr("Status", "%s", present[code & 0x03]); 474 | if ((code & 0x03) == 0x00) 475 | return 0; 476 | pr_attr("Option ROM Measuring", "%s", (code & (1 << 2)) ? "Yes" : "No"); 477 | pr_attr("Hidden", "%s", (code & (1 << 3)) ? "Yes" : "No"); 478 | return 1; 479 | } 480 | 481 | static void dmi_hp_224_ex_status(u8 status, u8 code) 482 | { 483 | const char *str = "Reserved"; 484 | static const char * const disable_reason[] = { 485 | "Not Specified", /* 0x00 */ 486 | "User Disabled", 487 | "Error Condition", 488 | "Reserved" /* 0x03 */ 489 | }; 490 | static const char * const error_condition[] = { 491 | "Not Specified", /* 0x00 */ 492 | "Self-Test", /* 0x01 */ 493 | }; 494 | if ((status & 0x03) == 0x02) 495 | pr_attr("Disable Reason", "%s", disable_reason[code & 0x03]); 496 | if ((code & 0x03) == 0x02) { 497 | u8 error = (code >> 2) & 0x0f; 498 | if (error < ARRAY_SIZE(error_condition)) 499 | str = error_condition[error]; 500 | pr_attr("Error Condition", "%s", str); 501 | } 502 | } 503 | 504 | static void dmi_hp_224_module_type(u8 code) 505 | { 506 | const char *str = "Reserved"; 507 | static const char * const type[] = { 508 | "Not Specified", /* 0x00 */ 509 | "TPM 1.2", 510 | "TPM 2.0", 511 | "Intel PTT fTPM" /* 0x03 */ 512 | }; 513 | if ((code & 0x0f) < ARRAY_SIZE(type)) 514 | str = type[code & 0x0f]; 515 | pr_attr("Type", "%s", str); 516 | pr_attr("Standard Algorithm Supported", "%s", (code & (1 << 4)) ? "Yes" : "No"); 517 | pr_attr("Chinese Algorithm Supported", "%s", (code & (1 << 5)) ? "Yes" : "No"); 518 | } 519 | 520 | static void dmi_hp_224_module_attr(u8 code) 521 | { 522 | static const char * const phys_attr[] = { 523 | "Not Specified", /* 0x00 */ 524 | "Pluggable and Optional", 525 | "Pluggable but Standard", 526 | "Soldered Down on System Board" /* 0x03 */ 527 | }; 528 | static const char * const fips_attr[] = { 529 | "Not Specified", /* 0x00 */ 530 | "Not FIPS Certified", 531 | "FIPS Certified", 532 | "Reserved" /* 0x03 */ 533 | }; 534 | pr_attr("Trusted Module Attributes", "%s", phys_attr[code & 0x3]); 535 | pr_attr("FIPS Certification", "%s", fips_attr[((code >> 2) & 0x03)]); 536 | } 537 | 538 | static void dmi_hp_224_chipid(u16 code) 539 | { 540 | const char *str = "Reserved"; 541 | static const char * const chipid[] = { 542 | "None", /* 0x00 */ 543 | "STMicroGen10 TPM", 544 | "Intel firmware TPM (PTT)", 545 | "Nationz TPM", 546 | "STMicroGen10 Plus TPM", 547 | "STMicroGen11 TPM", /* 0x05 */ 548 | }; 549 | if ((code & 0xff) < ARRAY_SIZE(chipid)) 550 | str = chipid[code & 0xff]; 551 | pr_attr("Chip Identifier", "%s", str); 552 | } 553 | 554 | static void dmi_hp_230_method_bus_seg_addr(u8 code, u8 bus_seg, u8 addr) 555 | { 556 | const char *str = "Reserved"; 557 | static const char * const method[] = { 558 | "Not Available", /* 0x00 */ 559 | "IPMI I2C", 560 | "iLO", 561 | "Chassis Manager", /* 0x03 */ 562 | }; 563 | if (code < ARRAY_SIZE(method)) 564 | str = method[code]; 565 | pr_attr("Access Method", "%s", str); 566 | if (code == 0 || code >= ARRAY_SIZE(method)) 567 | return; 568 | if (bus_seg != 0xFF) 569 | { 570 | if (code == 2) 571 | pr_attr("I2C Segment Number", "%d", bus_seg); 572 | else 573 | pr_attr("I2C Bus Number", "%d", bus_seg); 574 | } 575 | if (addr != 0xFF) 576 | pr_attr("I2C Address", "0x%02x", addr >> 1); 577 | } 578 | 579 | static void dmi_hp_238_loc(const char *fname, unsigned int code) 580 | { 581 | const char *str = "Reserved"; 582 | static const char *location[] = { 583 | "Internal", /* 0x00 */ 584 | "Front of Server", 585 | "Rear of Server", 586 | "Embedded internal SD Card", 587 | "iLO USB", 588 | "USB Hub for NAND Controller", 589 | "Reserved", 590 | "Debug Port", /* 0x07 */ 591 | "Reserved", 592 | "OCP USB", /* 0x09 */ 593 | }; 594 | 595 | if (code < ARRAY_SIZE(location)) 596 | str = location[code]; 597 | 598 | pr_attr(fname, "%s", str); 599 | } 600 | 601 | static void dmi_hp_238_flags(const char *fname, unsigned int code) 602 | { 603 | const char *str = "Reserved"; 604 | static const char *flags[] = { 605 | "Not Shared", /* 0x00 */ 606 | "Shared with physical switch", 607 | "Shared with automatic control", /* 0x02 */ 608 | }; 609 | 610 | if (code < ARRAY_SIZE(flags)) 611 | str = flags[code]; 612 | 613 | pr_attr(fname, "%s", str); 614 | } 615 | 616 | static void dmi_hp_238_speed(const char *fname, unsigned int code) 617 | { 618 | const char *str = "Reserved"; 619 | static const char *speed[] = { 620 | "Reserved", /* 0x00 */ 621 | "USB 1.1 Full Speed", 622 | "USB 2.0 High Speed", 623 | "USB 3.0 Super Speed" /* 0x03 */ 624 | }; 625 | 626 | if (code < ARRAY_SIZE(speed)) 627 | str = speed[code]; 628 | 629 | pr_attr(fname, "%s", str); 630 | } 631 | 632 | static void dmi_hp_239_usb_device(u8 class, u8 subclass, u8 protocol) 633 | { 634 | /* https://www.usb.org/defined-class-codes */ 635 | /* https://www.usb.org/sites/default/files/Mass_Storage_Specification_Overview_v1.4_2-19-2010.pdf */ 636 | const char *str = "Reserved"; 637 | if (class == 0x08) 638 | { 639 | static const char * const sub_class_name[] = { 640 | "SCSI command set not reported", /* 0x00 */ 641 | "RBC", 642 | "ATAPI", 643 | "Obsolete", 644 | "UFI", 645 | "Obsolete", 646 | "SCSI", 647 | "LSD FS", 648 | "IEEE 1667" /* 0x08 */ 649 | }; 650 | pr_attr("USB Class", "%s", "Mass Storage"); 651 | if (subclass == 0xFF) 652 | { 653 | str = "Vendor Specific"; 654 | } 655 | else if (subclass < ARRAY_SIZE(sub_class_name)) 656 | { 657 | str = sub_class_name[subclass]; 658 | } 659 | pr_attr("USB SubClass", "%s", str); 660 | 661 | switch (protocol) { 662 | case 0x00: 663 | str = "CBI w/ completion interrupt"; 664 | break; 665 | case 0x01: 666 | str = "CBI w/o completion interrupt"; 667 | break; 668 | case 0x02: 669 | str = "Obsolete"; 670 | break; 671 | case 0x50: 672 | str = "Bulk-Only"; 673 | break; 674 | case 0x62: 675 | str = "UAS"; 676 | break; 677 | case 0xFF: 678 | str = "Vendor Specific"; 679 | break; 680 | default: 681 | str = "Reserved"; 682 | } 683 | pr_attr("USB Protocol", "%s", str); 684 | } 685 | else if (class == 0x09 && subclass == 0) 686 | { 687 | pr_attr("USB Class", "%s", "HUB"); 688 | switch (protocol) { 689 | case 0: 690 | str = "Full Speed"; 691 | break; 692 | case 1: 693 | str = "Hi-Speed w/ single TT"; 694 | break; 695 | case 2: 696 | str = "Hi-Speed w/ multiple TT"; 697 | break; 698 | default: 699 | str = "Reserved"; 700 | } 701 | pr_attr("USB Protocol", str); 702 | } 703 | else 704 | { 705 | pr_attr("USB Class", "0x%02x", class); 706 | pr_attr("USB SubClass", "0x%02x", subclass); 707 | pr_attr("USB Protocol", "0x%02x", protocol); 708 | } 709 | } 710 | 711 | static void dmi_hp_240_attr(u64 defined, u64 set) 712 | { 713 | static const char *attributes[] = { 714 | "Updatable", 715 | "Reset Required", 716 | "Authentication Required", 717 | "In Use", 718 | "UEFI Image", 719 | }; 720 | unsigned int i; 721 | 722 | pr_list_start("Attributes Defined/Set", NULL); 723 | for (i = 0; i < ARRAY_SIZE(attributes); i++) 724 | { 725 | if (!(defined.l & (1UL << i))) 726 | continue; 727 | pr_list_item("%s: %s", attributes[i], set.l & (1UL << i) ? "Yes" : "No"); 728 | } 729 | pr_list_end(); 730 | } 731 | 732 | static void dmi_hp_242_hdd_type(u8 code) 733 | { 734 | const char *str = "Reserved"; 735 | static const char * const type[] = { 736 | "Undetermined", /* 0x00 */ 737 | "NVMe SSD", 738 | "SATA", 739 | "SAS", 740 | "SATA SSD", 741 | "NVMe Manged by VROC/VMD", /* 0x05 */ 742 | }; 743 | if (code < ARRAY_SIZE(type)) 744 | str = type[code]; 745 | 746 | pr_attr("Hard Drive Type", "%s", str); 747 | } 748 | 749 | static void dmi_hp_242_form_factor(u8 code) 750 | { 751 | const char *str = "Reserved"; 752 | static const char * const form[] = { 753 | "Reserved", /* 0x00 */ 754 | "Reserved", 755 | "3.5\" form factor", 756 | "2.5\" form factor", 757 | "1.8\" form factor", 758 | "Less than 1.8\" form factor", 759 | "mSATA", 760 | "M.2", 761 | "MicroSSD", 762 | "CFast", /* 0x09 */ 763 | }; 764 | static const char * const form2[] = { 765 | "EDSFF Unknown", /* 0x20 */ 766 | "EDSFF 1U Short", 767 | "EDSFF 1U Long", 768 | "EDSFF E3 Short", 769 | "EDSFF E3 Long", /* 0x24 */ 770 | }; 771 | if (code < ARRAY_SIZE(form)) 772 | str = form[code]; 773 | else if (code >= 0x20 && code < 0x20 + ARRAY_SIZE(form2)) 774 | str = form2[code - 0x20]; 775 | 776 | pr_attr("Form Factor", "%s", str); 777 | } 778 | 779 | static void dmi_hp_242_speed(const char *attr, u16 speed) 780 | { 781 | if (speed) 782 | pr_attr(attr, "%hu Gbit/s", speed); 783 | else 784 | pr_attr(attr, "%s", "Unknown"); 785 | } 786 | 787 | static void dmi_hp_245_pcie_riser(const struct dmi_header *h) 788 | { 789 | const char *str = "Reserved"; 790 | u8 *data = h->data; 791 | 792 | pr_attr("Board Type", "PCIe Riser"); 793 | if (h->length < 0x09) return; 794 | switch (data[0x05]) 795 | { 796 | case 1: str = "Primary"; break; 797 | case 2: str = "Secondary"; break; 798 | case 3: str = "Tertiary"; break; 799 | case 4: str = "Quaternary"; break; 800 | case 10: str = "Front"; break; 801 | } 802 | pr_attr("Riser Position", "%s", str); 803 | pr_attr("Riser ID", "%d", data[0x06]); 804 | if (data[0x07]) 805 | { 806 | str = (data[0x07] >> 7) ? "B." : ""; 807 | pr_attr("CPLD Version", "%s0x%02X", str, (data[0x07] & 0x7F)); 808 | } 809 | pr_attr("Riser Name", dmi_string(h, data[0x08])); 810 | } 811 | 812 | static int dmi_decode_hp(const struct dmi_header *h) 813 | { 814 | u8 *data = h->data; 815 | int nic, ptr; 816 | u32 feat; 817 | const char *company = (dmi_vendor == VENDOR_HP) ? "HP" : "HPE"; 818 | int gen; 819 | 820 | gen = dmi_hpegen(dmi_product); 821 | if (gen < 0) 822 | return 0; 823 | 824 | switch (h->type) 825 | { 826 | case 194: 827 | /* 828 | * Vendor Specific: Super IO Enable/Disable Features 829 | * 830 | * Offset | Name | Width | Description 831 | * ------------------------------------- 832 | * 0x00 | Type | BYTE | 0xC2, Super IO Enable/Disable Indicator 833 | * 0x01 | Length | BYTE | Length of structure 834 | * 0x02 | Handle | WORD | Unique handle 835 | * 0x04 | Dev Status | BYTE | Device Status 836 | */ 837 | pr_handle_name("%s ProLiant Super IO Enable/Disable Indicator", company); 838 | if (h->length < 0x05) break; 839 | feat = data[0x04]; 840 | pr_attr("Serial Port A", "%s", feat & (1 << 0) ? "Enabled" : "Disabled"); 841 | pr_attr("Serial Port B", "%s", feat & (1 << 1) ? "Enabled" : "Disabled"); 842 | pr_attr("Parallel Port", "%s", feat & (1 << 2) ? "Enabled" : "Disabled"); 843 | pr_attr("Floppy Disk Port", "%s", feat & (1 << 3) ? "Enabled" : "Disabled"); 844 | pr_attr("Virtual Serial Port", "%s", feat & (1 << 4) ? "Enabled" : "Disabled"); 845 | break; 846 | 847 | case 197: 848 | /* 849 | * Vendor Specific: HPE Processor Specific Information 850 | * 851 | * Processor Information structure (Type 197) for each possibly installed 852 | * physical processor to go along with each standard Processor Info 853 | * Record (Type 4). The Type 197 record will be ignored for Processor 854 | * slots that are empty (specified in the Type 4 records). 855 | * 856 | * Processor Wattage value will be filled in with information gotten from 857 | * the CPUID instruction or possibly estimated based on CPU Family/Type. 858 | * 859 | * Designator bytes will be 0FFh if the location of the processor does not 860 | * use it. If a system has processor slots, but no sockets, then the value 861 | * in the Socket Designator will be 0FFh. A system would have one or the 862 | * other, or both. 863 | * 864 | * Offset | Name | Width | Description 865 | * -------+------------+-------+------------- 866 | * 0x00 | Type | BYTE | 0xC5, Processor Information 867 | * 0x01 | Length | BYTE | Length of structure 868 | * 0x02 | Handle | WORD | Unique handle 869 | * 0x04 | Assoc Dev | WORD | Handle of Associated Type 4 Record 870 | * 0x06 | APIC ID | BYTE | Processor local APIC ID 871 | * 0x07 | OEM Status | BYTE | Bits: 0: BSP, 1: x2APIC, 2: Therm Margining 872 | * 0x08 | Phys Slot | BYTE | Matches silk screen 873 | * 0x09 | Phys Socket| BYTE | Matches silk screen 874 | * 0x0A | Max Wattage| WORD | Rated max wattage of the processor 875 | * 0x0C | x2APIC ID | DWORD | Processor x2APIC (if OEM Status -> x2APIC) 876 | * 0x10 | Proc UUID | QWORD | Processor Unique Identifier 877 | * 0x18 | Conn Speed | WORD | Interconnect speed in MT/s 878 | * 0x1A | QDF/S-SPEC |6 BYTES| Processor QDF/S-SPEC Numbers (Intel only) 879 | * 0x20 | Reserved | DWORD | Gen11 Reserved 880 | */ 881 | pr_handle_name("%s Processor Specific Information", company); 882 | if (h->length < 0x0A) break; 883 | if (!(opt.flags & FLAG_QUIET)) 884 | pr_attr("Associated Handle", "0x%04X", WORD(data + 0x04)); 885 | pr_attr("APIC ID", "%u", data[0x06]); 886 | feat = data[0x07]; 887 | pr_attr("BSP", "%s", feat & 0x01 ? "Yes" : "No"); 888 | pr_attr("x2APIC", "%s", feat & 0x02 ? "Yes" : "No"); 889 | pr_attr("Advanced Thermal Margining", "%s", feat & 0x04 ? "Yes" : "No"); 890 | if (data[0x08] != 0xFF) 891 | pr_attr("Physical Slot", "%d", data[0x08]); 892 | if (data[0x09] != 0xFF) 893 | pr_attr("Physical Socket", "%d", data[0x09]); 894 | if (h->length < 0x0C) break; 895 | if (WORD(data + 0x0A)) 896 | pr_attr("Maximum Power", "%d W", WORD(data + 0x0A)); 897 | if (h->length < 0x10) break; 898 | if (feat & 0x02) 899 | pr_attr("x2APIC ID", "0x%08x", DWORD(data + 0x0C)); 900 | if (h->length < 0x18) break; 901 | if (DWORD(data + 0x10) || DWORD(data + 0x14)) 902 | pr_attr("UUID", "0x%08x%08x", DWORD(data + 0x14), DWORD(data + 0x10)); 903 | if (h->length < 0x1A) break; 904 | if (WORD(data + 0x18)) 905 | pr_attr("Interconnect Speed", "%d MT/s", WORD(data + 0x18)); 906 | if (h->length < 0x20) break; 907 | dmi_hp_197_qdf(data + 0x1A); 908 | break; 909 | 910 | case 199: 911 | /* 912 | * Vendor Specific: CPU Microcode Patch 913 | * 914 | * Offset | Name | Width | Description 915 | * ------------------------------------- 916 | * 0x00 | Type | BYTE | 0xC7, CPU Microcode Patch 917 | * 0x01 | Length | BYTE | Length of structure 918 | * 0x02 | Handle | WORD | Unique handle 919 | * 0x04 | Patch Info | Varies| { ...} 920 | */ 921 | if (gen < G9) return 0; 922 | pr_handle_name("%s ProLiant CPU Microcode Patch Support Info", company); 923 | 924 | for (ptr = 0x4; ptr + 12 <= h->length; ptr += 12) { 925 | u32 cpuid = DWORD(data + ptr + 2 * 4); 926 | u32 date; 927 | 928 | /* AMD omits BaseFamily. Reconstruction valid on family >= 15. */ 929 | if (cpuid_type == cpuid_x86_amd) 930 | cpuid = ((cpuid & 0xfff00) << 8) | 0x0f00 | (cpuid & 0xff); 931 | 932 | dmi_print_cpuid(pr_attr, "CPU ID", cpuid_type, (u8 *) &cpuid); 933 | 934 | date = DWORD(data + ptr + 4); 935 | pr_subattr("Date", "%04x-%02x-%02x", 936 | date & 0xffff, (date >> 24) & 0xff, (date >> 16) & 0xff); 937 | pr_subattr("Patch", "0x%X", DWORD(data + ptr)); 938 | } 939 | break; 940 | 941 | case 203: 942 | /* 943 | * Vendor Specific: HP Device Correlation Record 944 | * 945 | * Offset | Name | Width | Description 946 | * ------------------------------------- 947 | * 0x00 | Type | BYTE | 0xCB, Correlation Record 948 | * 0x01 | Length | BYTE | Length of structure 949 | * 0x02 | Handle | WORD | Unique handle 950 | * 0x04 | Assoc Device | WORD | Handle of Associated Type 9 or Type 41 Record 951 | * 0x06 | Assoc SMBus | WORD | Handle of Associated Type 228 SMBus Segment Record 952 | * 0x08 | PCI Vendor ID| WORD | PCI Vendor ID of device 0xFFFF -> not present 953 | * 0x0A | PCI Device ID| WORD | PCI Device ID of device 0xFFFF -> not present 954 | * 0x0C | PCI SubVendor| WORD | PCI Sub Vendor ID of device 0xFFFF -> not present 955 | * 0x0E | PCI SubDevice| WORD | PCI Sub Device ID of device 0xFFFF -> not present 956 | * 0x10 | Class Code | BYTE | PCI Class Code of Endpoint. 0xFF if device not present. 957 | * 0x11 | Class SubCode| BYTE | PCI Sub Class Code of Endpoint. 0xFF if device not present. 958 | * 0x12 | Parent Handle| WORD | 959 | * 0x14 | Flags | WORD | 960 | * 0x16 | Device Type | BYTE | UEFI only 961 | * 0x17 | Device Loc | BYTE | Device Location 962 | * 0x18 | Dev Instance | BYTE | Device Instance 963 | * 0x19 | Sub Instance | BYTE | NIC Port # or NVMe Drive Bay 964 | * 0x1A | Bay | BYTE | 965 | * 0x1B | Enclosure | BYTE | 966 | * 0x1C | UEFI Dev Path| STRING| String number for UEFI Device Path 967 | * 0x1D | Struct Name | STRING| String number for UEFI Device Structured Name 968 | * 0x1E | Device Name | STRING| String number for UEFI Device Name 969 | * 0x1F | UEFI Location| STRING| String number for UEFI Location 970 | * 0x20 | Assoc Handle | WORD | Type 9 Handle. Defined if Flags[0] == 1. 971 | * 0x22 | Part Number | STRING| PCI Device Part Number 972 | * 0x23 | Serial Number| STRING| PCI Device Serial Number 973 | * 0x24 | Seg Number | WORD | Segment Group number. 0 -> Single group topology 974 | * 0x26 | Bus Number | BYTE | PCI Device Bus Number 975 | * 0x27 | Func Number | BTYE | PCI Device and Function Number 976 | */ 977 | if (gen < G9) return 0; 978 | pr_handle_name("%s Device Correlation Record", company); 979 | if (h->length < 0x1F) break; 980 | dmi_hp_203_assoc_hndl("Associated Device Record", WORD(data + 0x04)); 981 | dmi_hp_203_assoc_hndl("Associated SMBus Record", WORD(data + 0x06)); 982 | if (WORD(data + 0x08) == 0xffff && WORD(data + 0x0A) == 0xffff && 983 | WORD(data + 0x0C) == 0xffff && WORD(data + 0x0E) == 0xffff && 984 | data[0x10] == 0xFF && data[0x11] == 0xFF) 985 | { 986 | pr_attr("PCI Device Info", "Device Not Present"); 987 | } 988 | else 989 | { 990 | dmi_hp_203_pciinfo("PCI Vendor ID", WORD(data + 0x08)); 991 | dmi_hp_203_pciinfo("PCI Device ID", WORD(data + 0x0A)); 992 | dmi_hp_203_pciinfo("PCI Sub Vendor ID", WORD(data + 0x0C)); 993 | dmi_hp_203_pciinfo("PCI Sub Device ID", WORD(data + 0x0E)); 994 | dmi_hp_203_pciinfo("PCI Class Code", (char)data[0x10]); 995 | dmi_hp_203_pciinfo("PCI Sub Class Code", (char)data[0x11]); 996 | } 997 | dmi_hp_203_assoc_hndl("Parent Handle", WORD(data + 0x12)); 998 | pr_attr("Flags", "0x%04X", WORD(data + 0x14)); 999 | if (WORD(data + 0x14) & 0x01) 1000 | pr_subattr("Peer Bifurcated Device", "Yes"); 1001 | if (WORD(data + 0x14) & 0x02) 1002 | pr_subattr("Upstream Device", "Yes"); 1003 | dmi_hp_203_devtyp("Device Type", data[0x16]); 1004 | dmi_hp_203_devloc("Device Location", data[0x17]); 1005 | pr_attr("Device Instance", "%d", data[0x18]); 1006 | pr_attr("Device Sub-Instance", "%d", data[0x19]); 1007 | dmi_hp_203_bayenc("Bay", data[0x1A]); 1008 | dmi_hp_203_bayenc("Enclosure", data[0x1B]); 1009 | pr_attr("Device Path", "%s", dmi_string(h, data[0x1C])); 1010 | pr_attr("Structured Name", "%s", dmi_string(h, data[0x1D])); 1011 | pr_attr("Device Name", "%s", dmi_string(h, data[0x1E])); 1012 | if (h->length < 0x22) break; 1013 | pr_attr("UEFI Location", "%s", dmi_string(h, data[0x1F])); 1014 | if (!(opt.flags & FLAG_QUIET)) 1015 | { 1016 | if (WORD(data + 0x14) & 1) 1017 | pr_attr("Associated Real/Phys Handle", "0x%04X", 1018 | WORD(data + 0x20)); 1019 | else 1020 | pr_attr("Associated Real/Phys Handle", "N/A"); 1021 | } 1022 | if (h->length < 0x24) break; 1023 | pr_attr("PCI Part Number", "%s", dmi_string(h, data[0x22])); 1024 | pr_attr("Serial Number", "%s", dmi_string(h, data[0x23])); 1025 | if (h->length < 0x28) break; 1026 | pr_attr("Segment Group Number", "0x%04x", WORD(data + 0x24)); 1027 | pr_attr("PCI Device", "%02x:%02x.%x", 1028 | data[0x26], data[0x27] >> 3, data[0x27] & 7); 1029 | break; 1030 | 1031 | case 204: 1032 | /* 1033 | * Vendor Specific: HPE ProLiant System/Rack Locator 1034 | */ 1035 | pr_handle_name("%s ProLiant System/Rack Locator", company); 1036 | if (h->length < 0x0B) break; 1037 | pr_attr("Rack Name", "%s", dmi_string(h, data[0x04])); 1038 | pr_attr("Enclosure Name", "%s", dmi_string(h, data[0x05])); 1039 | pr_attr("Enclosure Model", "%s", dmi_string(h, data[0x06])); 1040 | pr_attr("Enclosure Serial", "%s", dmi_string(h, data[0x0A])); 1041 | pr_attr("Enclosure Bays", "%d", data[0x08]); 1042 | pr_attr("Server Bay", "%s", dmi_string(h, data[0x07])); 1043 | pr_attr("Bays Filled", "%d", data[0x09]); 1044 | break; 1045 | 1046 | case 209: 1047 | case 221: 1048 | /* 1049 | * Vendor Specific: HPE ProLiant NIC MAC Information 1050 | * 1051 | * This prints the BIOS NIC number, 1052 | * PCI bus/device/function, and MAC address 1053 | * 1054 | * Type 209: 1055 | * Offset | Name | Width | Description 1056 | * ------------------------------------- 1057 | * 0x00 | Type | BYTE | 0xD1, MAC Info 1058 | * 0x01 | Length | BYTE | Length of structure 1059 | * 0x02 | Handle | WORD | Unique handle 1060 | * 0x04 | Dev No | BYTE | PCI Device/Function No 1061 | * 0x05 | Bus No | BYTE | PCI Bus 1062 | * 0x06 | MAC | 6B | MAC addr 1063 | * 0x0C | NIC #2 | 8B | Repeat 0x04-0x0B 1064 | * 1065 | * Type 221: is deprecated in the latest docs 1066 | */ 1067 | if (gen >= G8 && h->type == 221) return 0; 1068 | pr_handle_name("%s %s", company, h->type == 221 ? 1069 | "BIOS iSCSI NIC PCI and MAC Information" : 1070 | "BIOS PXE NIC PCI and MAC Information"); 1071 | nic = 1; 1072 | ptr = 4; 1073 | while (h->length >= ptr + 8) 1074 | { 1075 | dmi_print_hp_net_iface_rec(nic, 1076 | data[ptr + 0x01], 1077 | data[ptr], 1078 | &data[ptr + 0x02]); 1079 | nic++; 1080 | ptr += 8; 1081 | } 1082 | break; 1083 | 1084 | case 212: 1085 | /* 1086 | * Vendor Specific: HPE 64-bit CRU Information 1087 | * 1088 | * Source: hpwdt kernel driver 1089 | */ 1090 | if (gen >= G9) return 0; 1091 | pr_handle_name("%s 64-bit CRU Information", company); 1092 | if (h->length < 0x18) break; 1093 | if (is_printable(data + 0x04, 4)) 1094 | pr_attr("Signature", "0x%08x (%c%c%c%c)", 1095 | DWORD(data + 0x04), 1096 | data[0x04], data[0x05], 1097 | data[0x06], data[0x07]); 1098 | else 1099 | pr_attr("Signature", "0x%08x", DWORD(data + 0x04)); 1100 | if (DWORD(data + 0x04) == 0x55524324) 1101 | { 1102 | u64 paddr = QWORD(data + 0x08); 1103 | paddr.l += DWORD(data + 0x14); 1104 | if (paddr.l < DWORD(data + 0x14)) 1105 | paddr.h++; 1106 | pr_attr("Physical Address", "0x%08x%08x", 1107 | paddr.h, paddr.l); 1108 | pr_attr("Length", "0x%08x", DWORD(data + 0x10)); 1109 | } 1110 | break; 1111 | 1112 | case 216: 1113 | /* 1114 | * Vendor Specific: Version Indicator Record 1115 | * 1116 | * This record is used to allow determining Firmware and CPLD revisions for 1117 | * components in the system. The goal of this record is to provide a 1118 | * flexible method to communicate to software and firmware the revisions 1119 | * of these components. This record replaces much of the functionality of 1120 | * Record Type 193. OEM SMBIOS Record Type 193 was not scaling well with 1121 | * the large number of potential CPLD devices, power management controllers, 1122 | * etc. This record is flexible such that each instance of Type 216 1123 | * defines one firmware component. This record also includes the string 1124 | * name for which software should refer to the component. The record 1125 | * includes both data bytes to indicate the revision and a string value. A 1126 | * firmware component can implement either or both. If both are supported, 1127 | * it allows easy display of the revision, but prevents the need for 1128 | * software/firmware to parse strings when doing comparisons on revisions. 1129 | * As there is one Type 216 Record per firmware component, the Handle for 1130 | * the Record can be used to tie firmware components with other OEM SMBIOS 1131 | * Records in the future if needed (similar to how SMBIOS Type 17 is tied 1132 | * to other Record Types related to DIMMs) 1133 | * 1134 | * Offset | Name | Width | Description 1135 | * ------------------------------------------ 1136 | * 0x00 | Type | BYTE | 0xD8, Version Indicator Record 1137 | * 0x01 | Length | BYTE | Length of structure 1138 | * 0x02 | Handle | WORD | Unique handle 1139 | * 0x04 | FW Type | WORD | Type of Firmware 1140 | * 0x06 | FW Name | STRING | Name of Firmware 1141 | * 0x07 | FW Version | STRING | Firmware Version 1142 | * 0x08 | Data Format| BYTE | Format of the Version Data 1143 | * 0x09 |Version Data|12 BYTES| Version Data in Format from field 0x08 1144 | * 0x15 | Unique ID | WORD | Unique ID for Firmware flash 1145 | */ 1146 | if (gen < G8) return 0; 1147 | pr_handle_name("%s Version Indicator", company); 1148 | if (h->length < 23) break; 1149 | dmi_hp_216_fw_type(WORD(data + 0x04)); 1150 | pr_attr("Firmware Name String", "%s", dmi_string(h, data[0x06])); 1151 | pr_attr("Firmware Version String", "%s", dmi_string(h, data[0x07])); 1152 | dmi_hp_216_version(data[0x08], data + 0x09); 1153 | if (WORD(data + 0x15)) 1154 | pr_attr("Unique ID", "0x%04x", WORD(data + 0x15)); 1155 | break; 1156 | 1157 | case 219: 1158 | /* 1159 | * Vendor Specific: HPE ProLiant Information 1160 | * 1161 | * Source: hpwdt kernel driver 1162 | */ 1163 | pr_handle_name("%s ProLiant Information", company); 1164 | if (h->length < 0x08) break; 1165 | pr_attr("Power Features", "0x%08x", DWORD(data + 0x04)); 1166 | if (h->length < 0x0C) break; 1167 | pr_attr("Omega Features", "0x%08x", DWORD(data + 0x08)); 1168 | if (h->length < 0x14) break; 1169 | feat = DWORD(data + 0x10); 1170 | pr_attr("Misc. Features", "0x%08x", feat); 1171 | pr_subattr("iCRU", "%s", feat & 0x0001 ? "Yes" : "No"); 1172 | pr_subattr("UEFI", "%s", feat & 0x1400 ? "Yes" : "No"); 1173 | break; 1174 | 1175 | case 224: 1176 | /* 1177 | * Vendor Specific: Trusted Module (TPM or TCM) Status 1178 | * 1179 | * Offset | Name | Width | Description 1180 | * ------------------------------------- 1181 | * 0x00 | Type | BYTE | 0xE0, Trusted Module (TPM or TCM) Status 1182 | * 0x01 | Length | BYTE | Length of structure 1183 | * 0x02 | Handle | WORD | Unique handle 1184 | * 0x04 | Status | BYTE | Status Flag Byte 1185 | * 0x05 | Ex Stat| BYTE | TPM Extended Status 1186 | * 0x06 | Type | BYTE | Trusted Module Type 1187 | * 0x07 | Attrib | BYTE | Trusted Module Attributes 1188 | * 0x08 | Handle | WORD | Handle to map to Type 216 1189 | * 0x0A | Chip ID| WORD | Chip Identifier Values 1190 | */ 1191 | pr_handle_name("%s Trusted Module (TPM or TCM) Status", company); 1192 | if (h->length < 0x05) break; 1193 | if (!dmi_hp_224_status(data[0x04])) 1194 | break; 1195 | if (h->length < 0x0a) break; 1196 | dmi_hp_224_ex_status(data[0x04], data[0x05]); 1197 | dmi_hp_224_module_type(data[0x06]); 1198 | dmi_hp_224_module_attr(data[0x07]); 1199 | if (!(opt.flags & FLAG_QUIET)) 1200 | pr_attr("Associated Handle", "0x%04X", WORD(data + 0x8)); 1201 | if (h->length < 0x0c) break; 1202 | dmi_hp_224_chipid(WORD(data + 0x0a)); 1203 | break; 1204 | 1205 | case 230: 1206 | /* 1207 | * Vendor Specific: Power Supply Information OEM SMBIOS Record 1208 | * 1209 | * This record is used to communicate additional Power Supply Information 1210 | * beyond the Industry Standard System Power Supply (Type 39) Record. 1211 | * 1212 | * Offset| Name | Width | Description 1213 | * ----------------------------------------- 1214 | * 0x00 | Type | BYTE | 0xE6, Power Supply Information Indicator 1215 | * 0x01 | Length | BYTE | Length of structure 1216 | * 0x02 | Handle | WORD | Unique handle 1217 | * 0x04 | Assoc Handle| WORD | Associated Handle (Type 39) 1218 | * 0x06 | Manufacturer| STRING| Actual third party manufacturer 1219 | * 0x07 | Revision | STRING| Power Supply Revision Level 1220 | * 0x08 | FRU Access | BYTE | Power Supply FRU Access Method 1221 | * 0x09 | I2C Bus Num | BYTE | I2C Bus #. Value based upon context 1222 | * 0x0A | I2C Address | BYTE | I2C Address 1223 | */ 1224 | pr_handle_name("%s Power Supply Information", company); 1225 | if (h->length < 0x0B) break; 1226 | if (!(opt.flags & FLAG_QUIET)) 1227 | pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4)); 1228 | pr_attr("Manufacturer", "%s", dmi_string(h, data[0x06])); 1229 | pr_attr("Revision", "%s", dmi_string(h, data[0x07])); 1230 | dmi_hp_230_method_bus_seg_addr(data[0x08], data[0x09], data[0x0A]); 1231 | break; 1232 | 1233 | case 233: 1234 | /* 1235 | * Vendor Specific: HPE ProLiant NIC MAC Information 1236 | * 1237 | * This prints the BIOS NIC number, 1238 | * PCI bus/device/function, and MAC address 1239 | * 1240 | * Offset | Name | Width | Description 1241 | * ------------------------------------- 1242 | * 0x00 | Type | BYTE | 0xE9, NIC structure 1243 | * 0x01 | Length | BYTE | Length of structure 1244 | * 0x02 | Handle | WORD | Unique handle 1245 | * 0x04 | Grp No | WORD | 0 for single segment 1246 | * 0x06 | Bus No | BYTE | PCI Bus 1247 | * 0x07 | Dev No | BYTE | PCI Device/Function No 1248 | * 0x08 | MAC | 32B | MAC addr padded w/ 0s 1249 | * 0x28 | Port No| BYTE | Each NIC maps to a Port 1250 | * 0x29 | DevPath| STRING| UEFI Device Path of network port 1251 | */ 1252 | pr_handle_name("%s BIOS PXE NIC PCI and MAC Information", 1253 | company); 1254 | if (h->length < 0x0E) break; 1255 | /* If the record isn't long enough, we don't have an ID 1256 | * use 0xFF to use the internal counter. 1257 | * */ 1258 | nic = h->length > 0x28 ? data[0x28] : 0xFF; 1259 | dmi_print_hp_net_iface_rec(nic, data[0x06], data[0x07], 1260 | &data[0x08]); 1261 | if (h->length < 0x2A) break; 1262 | pr_attr("UEFI Device Path", "%s", dmi_string(h, data[0x29])); 1263 | break; 1264 | 1265 | case 236: 1266 | /* 1267 | * Vendor Specific: HPE ProLiant HDD Backplane 1268 | * 1269 | * Offset | Name | Width | Description 1270 | * --------------------------------------- 1271 | * 0x00 | Type | BYTE | 0xEC, HDD Backplane 1272 | * 0x01 | Length | BYTE | Length of structure 1273 | * 0x02 | Handle | WORD | Unique handle 1274 | * 0x04 | I2C Address| BYTE | Backplane FRU I2C Address 1275 | * 0x05 | Box Number | WORD | Backplane Box Number 1276 | * 0x07 | NVRAM ID | WORD | Backplane NVRAM ID 1277 | * 0x09 | WWID | QWORD | SAS Expander WWID 1278 | * 0x11 | Total Bays | BYTE | Total SAS Bays 1279 | * 0x12 | A0 Bays | BYTE | (deprecated) Number of SAS drive bays behind port 0xA0 1280 | * 0x13 | A2 Bays | BYTE | (deprecated) Number of SAS drive bays behind port 0xA2 1281 | * 0x14 | Name | STRING| (deprecated) Backplane Name 1282 | */ 1283 | if (gen >= G11) return 0; 1284 | pr_handle_name("%s HDD Backplane FRU Information", company); 1285 | if (h->length < 0x08) break; 1286 | pr_attr("FRU I2C Address", "0x%X raw(0x%X)", data[0x4] >> 1, data[0x4]); 1287 | pr_attr("Box Number", "%d", WORD(data + 0x5)); 1288 | pr_attr("NVRAM ID", "0x%X", WORD(data + 0x7)); 1289 | if (h->length < 0x11) break; 1290 | pr_attr("SAS Expander WWID", "0x%X", QWORD(data + 0x9)); 1291 | if (h->length < 0x12) break; 1292 | pr_attr("Total SAS Bays", "%d", data[0x11]); 1293 | if (h->length < 0x15) break; 1294 | if (gen < G10P) { 1295 | pr_attr("A0 Bay Count", "%d", data[0x12]); 1296 | pr_attr("A2 Bay Count", "%d", data[0x13]); 1297 | pr_attr("Backplane Name", "%s", dmi_string(h, data[0x14])); 1298 | } 1299 | break; 1300 | 1301 | case 237: 1302 | /* 1303 | * Vendor Specific: HPE DIMM Vendor Part Number Information 1304 | * 1305 | * Offset | Name | Width | Description 1306 | * --------------------------------------- 1307 | * 0x00 | Type | BYTE | 0xED, DIMM Vendor Part Number information record 1308 | * 0x01 | Length | BYTE | Length of structure 1309 | * 0x02 | Handle | WORD | Unique handle 1310 | * 0x04 | Hand Assoc | WORD | Handle to map to Type 17 1311 | * 0x06 | Manufacture|STRING | DIMM Manufacturer 1312 | * 0x07 | Part Number|STRING | DIMM Manufacturer's Part Number 1313 | * 0x08 | Serial Num |STRING | DIMM Vendor Serial Number 1314 | * 0x09 | Man Date | BYTE | DIMM Manufacture Date (YEAR) in BCD 1315 | * 0x0A | Man Date | BYTE | DIMM Manufacture Date (WEEK) in BCD 1316 | */ 1317 | if (gen < G9) return 0; 1318 | pr_handle_name("%s DIMM Vendor Information", company); 1319 | if (h->length < 0x08) break; 1320 | if (!(opt.flags & FLAG_QUIET)) 1321 | pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4)); 1322 | pr_attr("DIMM Manufacturer", "%s", dmi_string(h, data[0x06])); 1323 | pr_attr("DIMM Manufacturer Part Number", "%s", dmi_string(h, data[0x07])); 1324 | if (h->length < 0x09) break; 1325 | pr_attr("DIMM Vendor Serial Number", "%s", dmi_string(h, data[0x08])); 1326 | if (h->length < 0x0B) break; 1327 | if (WORD(data + 0x09)) 1328 | pr_attr("DIMM Manufacture Date", "20%02x-W%02x", data[0x09], data[0x0A]); 1329 | break; 1330 | 1331 | case 238: 1332 | /* 1333 | * Vendor Specific: HPE USB Port Connector Correlation Record 1334 | * 1335 | * Offset | Name | Width | Description 1336 | * --------------------------------------- 1337 | * 0x00 | Type | BYTE | 0xEE, HP Device Correlation Record 1338 | * 0x01 | Length | BYTE | Length of structure 1339 | * 0x02 | Handle | WORD | Unique handle 1340 | * 0x04 | Hand Assoc | WORD | Handle to map to Type 8 1341 | * 0x06 | Parent Bus | BYTE | PCI Bus number of USB controller of this port 1342 | * 0x07 | Par Dev/Fun| BYTE | PCI Dev/Fun of USB Controller of this port 1343 | * 0x08 | Location | BYTE | Enumerated value of location of USB port 1344 | * 0x09 | Flags | WORD | USB Shared Management Port 1345 | * 0x0B | Port Inst | BYTE | Instance number for this type of USB port 1346 | * 0x0C | Parent Hub | BYTE | Instance number of internal Hub 1347 | * 0x0D | Port Speed | BYTE | Enumerated value of speed configured by BIOS 1348 | * 0x0E | Device Path| STRING| UEFI Device Path of USB endpoint 1349 | */ 1350 | if (gen < G9) return 0; 1351 | pr_handle_name("%s Proliant USB Port Connector Correlation Record", company); 1352 | if (h->length < 0x0F) break; 1353 | if (!(opt.flags & FLAG_QUIET)) 1354 | pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4)); 1355 | pr_attr("PCI Device", "%02x:%02x.%x", data[0x6], 1356 | data[0x7] >> 3, data[0x7] & 0x7); 1357 | dmi_hp_238_loc("Location", data[0x8]); 1358 | dmi_hp_238_flags("Management Port", WORD(data + 0x9)); 1359 | pr_attr("Port Instance", "%d", data[0xB]); 1360 | if (data[0xC] != 0xFE) 1361 | pr_attr("Parent Hub Port Instance", "%d", data[0xC]); 1362 | else 1363 | pr_attr("Parent Hub Port Instance", "N/A"); 1364 | dmi_hp_238_speed("Port Speed Capability", data[0xD]); 1365 | pr_attr("Device Path", "%s", dmi_string(h, data[0xE])); 1366 | break; 1367 | 1368 | case 239: 1369 | /* 1370 | * Vendor Specific: HPE USB Device Correlation Record 1371 | * 1372 | * This record provides a mechanism for software to correlate USB device 1373 | * information provided in SMBIOS record Type 8 and Type 238. It 1374 | * additionally provides device specific data that is typically not 1375 | * available in SMBIOS to allow HP tools to understand how these device 1376 | * entries correlate to both UEFI and Legacy USB Boot entries. This record 1377 | * will only contain information for a device detected by the BIOS during 1378 | * POST and does not comprehend a hot plug event after the system has 1379 | * booted. This record will only be supported on UEFI Based systems. 1380 | * 1381 | * Offset | Name | Width | Description 1382 | * -------+------------+-------+------------ 1383 | * 0x00 | Type | BYTE | 0xEF, HP Device Correlation Record 1384 | * 0x01 | Length | BYTE | Length of structure 1385 | * 0x02 | Handle | WORD | Unique handle 1386 | * 0x04 | Hand Assoc | WORD | Handle to map to Type 238 1387 | * 0x06 | Vendor ID | WORD | Vendor ID of detected USB Device 1388 | * 0x08 | Flags | WORD | Bit[0] - Indicates presence of SD card 1389 | * 0x0A | Class | BYTE | USB Device Class per USB HID Dev Spec 1390 | * 0x0B | Sub Class | BYTE | USB Device SubClass per USB HID Dev Spec 1391 | * 0x0C | Protocol | BYTE | Device Protocol per USB HID Dev Spec 1392 | * 0x0D | Product ID | WORD | USB Product ID 1393 | * 0x0F | Capacity | DWORD | USB Device Capacity (if apropos) in Mbytes 1394 | * 0x13 | Device Path| STRING| UEFI Device Path 1395 | * 0x14 | Device Name| STRING| UEFI Device Structured Name 1396 | * 0x15 | UEFI Name | STRING| Device Name 1397 | * 0x16 | Location | STRING| USB Device Location 1398 | */ 1399 | if (gen < G9) return 0; 1400 | pr_handle_name("%s USB Device Correlation Record", company); 1401 | if (h->length < 0x17) break; 1402 | if (!(opt.flags & FLAG_QUIET)) 1403 | pr_attr("Associated Handle", "0x%04X", WORD(data + 0x04)); 1404 | pr_attr("USB Vendor ID", "0x%04x", WORD(data + 0x06)); 1405 | pr_attr("Embedded SD Card", "%s", data[0x08] & 0x01 ? "Present" : "Empty"); 1406 | dmi_hp_239_usb_device(data[0x0A], data[0x0B], data[0x0C]); 1407 | pr_attr("USB Product ID", "0x%04x", WORD(data + 0x0D)); 1408 | if (DWORD(data + 0x0F)) 1409 | pr_attr("USB Capacity", "%u MB", DWORD(data + 0x0F)); 1410 | pr_attr("UEFI Device Path", "%s", dmi_string(h, data[0x13])); 1411 | pr_attr("UEFI Device Name", "%s", dmi_string(h, data[0x14])); 1412 | pr_attr("Device Name", "%s", dmi_string(h, data[0x15])); 1413 | pr_attr("Device Location", "%s", dmi_string(h, data[0x16])); 1414 | break; 1415 | 1416 | case 240: 1417 | /* 1418 | * Vendor Specific: HPE Proliant Inventory Record 1419 | * 1420 | * Reports firmware version information for devices that report their 1421 | * firmware using their UEFI drivers. Additionally provides association 1422 | * with other SMBIOS records, such as Type 203 (which in turn is 1423 | * associated with Types 9, 41, and 228). 1424 | * 1425 | * Offset | Name | Width | Description 1426 | * --------------------------------------- 1427 | * 0x00 | Type | BYTE | 0xF0, HP Firmware Inventory Record 1428 | * 0x01 | Length | BYTE | Length of structure 1429 | * 0x02 | Handle | WORD | Unique handle 1430 | * 0x04 | Hndl Assoc | WORD | Handle to map to Type 203 1431 | * 0x06 | Pkg Vers | DWORD | FW Vers Release of All FW in Device 1432 | * 0x0A | Ver String | STRING| FW Version String 1433 | * 0x0B | Image Size | QWORD | FW image size (bytes) 1434 | * 0x13 | Attributes | QWORD | Bitfield: Is attribute defined? 1435 | * 0x1B | Attr Set | QWORD | BitField: If defined, is attribute set? 1436 | * 0x23 | Version | DWORD | Lowest supported version. 1437 | */ 1438 | pr_handle_name("%s Proliant Inventory Record", company); 1439 | if (h->length < 0x27) break; 1440 | if (!(opt.flags & FLAG_QUIET)) 1441 | pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4)); 1442 | pr_attr("Package Version", "0x%08X", DWORD(data + 0x6)); 1443 | pr_attr("Version String", "%s", dmi_string(h, data[0x0A])); 1444 | 1445 | if (DWORD(data + 0x0B)) 1446 | dmi_print_memory_size("Image Size", QWORD(data + 0xB), 0); 1447 | else 1448 | pr_attr("Image Size", "Not Available"); 1449 | 1450 | dmi_hp_240_attr(QWORD(data + 0x13), QWORD(data + 0x1B)); 1451 | 1452 | if (DWORD(data + 0x23)) 1453 | pr_attr("Lowest Supported Version", "0x%08X", DWORD(data + 0x23)); 1454 | else 1455 | pr_attr("Lowest Supported Version", "Not Available"); 1456 | break; 1457 | 1458 | case 242: 1459 | /* 1460 | * Vendor Specific: HPE Hard Drive Inventory Record 1461 | * 1462 | * This record provides a mechanism for software to gather information for 1463 | * NVMe and SATA drives that are directly attached to the system. This 1464 | * record does not contain drive information for drives attached to a HBA 1465 | * (i.e. a SmartArray controller). This record will only contain information 1466 | * for a hard drive detected by the BIOS during POST and does not 1467 | * comprehend a hot plug event after the system has booted. 1468 | * 1469 | * Offset | Name | Width | Description 1470 | * --------------------------------------- 1471 | * 0x00 | Type | BYTE | 0xF2, HPE Hard Drive Inventory Record 1472 | * 0x01 | Length | BYTE | Length of structure 1473 | * 0x02 | Handle | WORD | Unique handle 1474 | * 0x04 | Hndl Assoc | WORD | Handle to map to Type 203 1475 | * 0x06 | HDD Type | BYTE | Hard drive type 1476 | * 0x07 | HDD Uniq ID| QWORD | SATA-> WWID. NVMe -> IEEE Ext Uniq ID. 1477 | * 0x0F | Capacity | DWORD | Drive Capacity in Mbytes 1478 | * 0x13 | Hours | 16BYTE| Number of poweron hours 1479 | * 0x23 | Reserved | BYTE | Reserved 1480 | * 0x24 | Power | BTYE | Wattage 1481 | * 0x25 | Form Factor| BYTE | HDD Form Factor 1482 | * 0x26 | Health | BYTE | Hard Drive Health Status 1483 | * 0x27 | Serial Num | STRING| NVMe/SATA Serial Number 1484 | * 0x28 | Model Num | STRING| NVMe/SATA Model Number 1485 | * 0x29 | FW Rev | STRING| Firmware revision 1486 | * 0x2A | Location | STRING| Drive location 1487 | * 0x2B | Crypt Stat | BYTE | Drive encryption status from BIOS 1488 | * 0x2C | Capacity | QWORD | Hard Drive capacity in bytes 1489 | * 0x34 | Block Size | DWORD | Logical Block Size in bytes 1490 | * 0x38 | Rot Speed | WORD | Nominal Rotational Speed (RPM) 1491 | * 0x3A | Neg Speed | WORD | Current negotiated bus speed 1492 | * 0x3C | Cap Speed | WORD | Fastest Capable Bus Speed of drive 1493 | */ 1494 | if (gen < G10) return 0; 1495 | pr_handle_name("%s ProLiant Hard Drive Inventory Record", company); 1496 | if (h->length < 0x2C) break; 1497 | if (!(opt.flags & FLAG_QUIET)) 1498 | pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4)); 1499 | dmi_hp_242_hdd_type(data[0x06]); 1500 | pr_attr("ID", "%llx", QWORD(data + 0x07)); 1501 | if (h->length < 0x3E) 1502 | pr_attr("Capacity", "%u MB", DWORD(data + 0x0F)); 1503 | else 1504 | dmi_print_memory_size("Capacity", QWORD(data + 0x2C), 0); 1505 | /* NB: Poweron low QWORD good for 2,104,351,365,926,255 years */ 1506 | pr_attr("Poweron", "%ld hours", QWORD(data + 0x13)); 1507 | if (data[0x24]) 1508 | pr_attr("Power Wattage", "%hhu W", data[0x24]); 1509 | else 1510 | pr_attr("Power Wattage", "%s", "Unknown"); 1511 | dmi_hp_242_form_factor(data[0x25]); 1512 | feat = data[0x26]; 1513 | pr_attr("Health Status", "%s", (feat == 0x00) ? "OK" : 1514 | (feat == 0x01) ? "Warning" : 1515 | (feat == 0x02) ? "Critical" : 1516 | (feat == 0xFF) ? "Unknown" : "Reserved"); 1517 | pr_attr("Serial Number", dmi_string(h, data[0x27])); 1518 | pr_attr("Model Number", dmi_string(h, data[0x28])); 1519 | pr_attr("Firmware Revision", dmi_string(h, data[0x29])); 1520 | pr_attr("Location", dmi_string(h, data[0x2A])); 1521 | feat = data[0x2B]; 1522 | pr_attr("Encryption Status", "%s", (feat == 0) ? "Not Encrypted" : 1523 | (feat == 1) ? "Encrypted" : 1524 | (feat == 2) ? "Unknown" : 1525 | (feat == 3) ? "Not Supported" : "Reserved"); 1526 | if (h->length < 0x3E) break; 1527 | pr_attr("Block Size", "%u bytes", DWORD(data + 0x34)); 1528 | /* Rotational Speed: 0 -> Not Reported, 1 -> N/A (SSD) */ 1529 | if (data[0x38] > 1) 1530 | pr_attr("Rotational Speed", "%hhu RPM", data[0x38]); 1531 | dmi_hp_242_speed("Negotiated Speed", WORD(data + 0x3A)); 1532 | dmi_hp_242_speed("Capable Speed", WORD(data + 0x3C)); 1533 | break; 1534 | 1535 | case 245: 1536 | /* 1537 | * Vendor Specific: HPE Extension Board Inventory Record 1538 | * 1539 | * This record provides a mechanism for software to retrieve installed 1540 | * Extension Boards in system, such as Riser Cards, etc. Each extension 1541 | * board discovered at system boot time has a corresponding record 1542 | * produced in SMBIOS Type 245. This record is currently applicable 1543 | * for ML, DL and Alletra series servers in Gen11 and will be backward 1544 | * compatible with next generations 1545 | * 1546 | * This is a variant record. Definition of fields 0x05 ... vary based 1547 | * upon field 0x04 Board Type. 1548 | * 1549 | * Offset | Name | Width | Description 1550 | * --------------------------------------- 1551 | * 0x00 | Type | BYTE | 0xF5, Extension Board Inventory Record 1552 | * 0x01 | Length | BYTE | Length of structure 1553 | * 0x02 | Handle | WORD | Unique handle 1554 | * 0x04 | Board Type | WORD | 0: PCIe Riser, Other Reserved 1555 | * 1556 | * If Board Type == 0 1557 | * 0x05 | Riser Pos | WORD | 1558 | * 0x06 | Riser ID | BYTE | 1559 | * 0x07 | CPLD Vers | BTYE | 0-> No CPLD. Bits [7][6:0] Release:Vers 1560 | * 0x08 | Riser Name | STRING| 1561 | */ 1562 | pr_handle_name("%s ProLiant Extension Board Inventory Record", company); 1563 | if (h->length < 0x05) break; 1564 | if (data[0x04] == 0) 1565 | dmi_hp_245_pcie_riser(h); 1566 | break; 1567 | 1568 | default: 1569 | return 0; 1570 | } 1571 | return 1; 1572 | } 1573 | 1574 | static int dmi_decode_ibm_lenovo(const struct dmi_header *h) 1575 | { 1576 | u8 *data = h->data; 1577 | 1578 | switch (h->type) 1579 | { 1580 | case 131: 1581 | /* 1582 | * Vendor Specific: ThinkVantage Technologies feature bits 1583 | * 1584 | * Source: Compal hel81 Service Manual Software Specification, 1585 | * documented under "System Management BIOS(SM BIOS) 1586 | * version 2.4 or greater" 1587 | * 1588 | * Offset | Name | Width | Description 1589 | * ---------------------------------------------- 1590 | * 0x00 | Type | BYTE | 0x83 1591 | * 0x01 | Length | BYTE | 0x16 1592 | * 0x02 | Handle | WORD | Varies 1593 | * 0x04 | Version | BYTE | 0x01 1594 | * 0x05 | TVT Structure | BYTEx16 | Each of the 128 bits represents a TVT feature: 1595 | * | | | - bit 127 means diagnostics (PC Doctor) is available 1596 | * | | | (http://www.pc-doctor.com/company/pr-articles/45-lenovo-introduces-thinkvantage-toolbox) 1597 | * | | | - the rest (126-0) are reserved/unknown 1598 | * 1599 | * It must also be followed by a string containing 1600 | * "TVT-Enablement". There exist other type 131 records 1601 | * with different length and a different string, for 1602 | * other purposes. 1603 | */ 1604 | 1605 | if (h->length != 0x16 1606 | || strcmp(dmi_string(h, 1), "TVT-Enablement") != 0) 1607 | return 0; 1608 | 1609 | pr_handle_name("ThinkVantage Technologies"); 1610 | pr_attr("Version", "%u", data[0x04]); 1611 | pr_attr("Diagnostics", "%s", 1612 | data[0x14] & 0x80 ? "Available" : "No"); 1613 | break; 1614 | 1615 | case 135: 1616 | /* 1617 | * Vendor Specific: Device Presence Detection bits 1618 | * 1619 | * Source: Compal hel81 Service Manual Software Specification, 1620 | * documented as "SMBIOS Type 135: Bulk for Lenovo 1621 | * Mobile PC Unique OEM Data" under appendix D. 1622 | * 1623 | * Offset | Name | Width | Description 1624 | * --------------------------------------------------- 1625 | * 0x00 | Type | BYTE | 0x87 1626 | * 0x01 | Length | BYTE | 0x0A 1627 | * 0x02 | Handle | WORD | Varies 1628 | * 0x04 | Signature | WORD | 0x5054 (ASCII for "TP") 1629 | * 0x06 | OEM struct offset | BYTE | 0x07 1630 | * 0x07 | OEM struct number | BYTE | 0x03, for this structure 1631 | * 0x08 | OEM struct revision | BYTE | 0x01, for this format 1632 | * 0x09 | Device presence bits | BYTE | Each of the 8 bits indicates device presence: 1633 | * | | | - bit 0 indicates the presence of a fingerprint reader 1634 | * | | | - the rest (7-1) are reserved/unknown 1635 | * 1636 | * Other OEM struct number+rev combinations have been 1637 | * seen in the wild but we don't know how to decode 1638 | * them. 1639 | */ 1640 | 1641 | if (h->length < 0x0A || data[0x04] != 'T' || data[0x05] != 'P') 1642 | return 0; 1643 | 1644 | /* Bail out if not the expected format */ 1645 | if (data[0x06] != 0x07 || data[0x07] != 0x03 || data[0x08] != 0x01) 1646 | return 0; 1647 | 1648 | pr_handle_name("ThinkPad Device Presence Detection"); 1649 | pr_attr("Fingerprint Reader", "%s", 1650 | data[0x09] & 0x01 ? "Present" : "No"); 1651 | break; 1652 | 1653 | case 140: 1654 | /* 1655 | * Vendor Specific: ThinkPad Embedded Controller Program 1656 | * 1657 | * Source: some guesswork, and publicly available information; 1658 | * Lenovo's BIOS update READMEs often contain the ECP IDs 1659 | * which match the first string in this type. 1660 | * 1661 | * Offset | Name | Width | Description 1662 | * ---------------------------------------------------- 1663 | * 0x00 | Type | BYTE | 0x8C 1664 | * 0x01 | Length | BYTE | 1665 | * 0x02 | Handle | WORD | Varies 1666 | * 0x04 | Signature | BYTEx6 | ASCII for "LENOVO" 1667 | * 0x0A | OEM struct offset | BYTE | 0x0B 1668 | * 0x0B | OEM struct number | BYTE | 0x07, for this structure 1669 | * 0x0C | OEM struct revision | BYTE | 0x01, for this format 1670 | * 0x0D | ECP version ID | STRING | 1671 | * 0x0E | ECP release date | STRING | 1672 | */ 1673 | 1674 | if (h->length < 0x0F || memcmp(data + 4, "LENOVO", 6) != 0) 1675 | return 0; 1676 | 1677 | /* Bail out if not the expected format */ 1678 | if (data[0x0A] != 0x0B || data[0x0B] != 0x07 || data[0x0C] != 0x01) 1679 | return 0; 1680 | 1681 | pr_handle_name("ThinkPad Embedded Controller Program"); 1682 | pr_attr("Version ID", "%s", dmi_string(h, 1)); 1683 | pr_attr("Release Date", "%s", dmi_string(h, 2)); 1684 | break; 1685 | 1686 | default: 1687 | return 0; 1688 | } 1689 | return 1; 1690 | } 1691 | 1692 | /* 1693 | * Dispatch vendor-specific entries decoding 1694 | * Return 1 if decoding was successful, 0 otherwise 1695 | */ 1696 | int dmi_decode_oem(const struct dmi_header *h) 1697 | { 1698 | switch (dmi_vendor) 1699 | { 1700 | case VENDOR_HP: 1701 | case VENDOR_HPE: 1702 | return dmi_decode_hp(h); 1703 | case VENDOR_ACER: 1704 | return dmi_decode_acer(h); 1705 | case VENDOR_IBM: 1706 | case VENDOR_LENOVO: 1707 | return dmi_decode_ibm_lenovo(h); 1708 | default: 1709 | return 0; 1710 | } 1711 | } 1712 | -------------------------------------------------------------------------------- /dmioem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Decoding of OEM-specific entries 3 | * This file is part of the dmidecode project. 4 | * 5 | * Copyright (C) 2007-2008 Jean Delvare 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | struct dmi_header; 23 | 24 | void dmi_set_vendor(const char *s, const char *p); 25 | int dmi_decode_oem(const struct dmi_header *h); 26 | -------------------------------------------------------------------------------- /dmiopt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Command line handling of dmidecode 3 | * This file is part of the dmidecode project. 4 | * 5 | * Copyright (C) 2005-2023 Jean Delvare 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "config.h" 29 | #include "types.h" 30 | #include "util.h" 31 | #include "dmidecode.h" 32 | #include "dmiopt.h" 33 | 34 | 35 | /* Options are global */ 36 | struct opt opt; 37 | 38 | 39 | /* 40 | * Handling of option --type 41 | */ 42 | 43 | struct type_keyword 44 | { 45 | const char *keyword; 46 | const u8 *type; 47 | }; 48 | 49 | static const u8 opt_type_bios[] = { 0, 13, 255 }; 50 | static const u8 opt_type_system[] = { 1, 12, 15, 23, 32, 255 }; 51 | static const u8 opt_type_baseboard[] = { 2, 10, 41, 255 }; 52 | static const u8 opt_type_chassis[] = { 3, 255 }; 53 | static const u8 opt_type_processor[] = { 4, 255 }; 54 | static const u8 opt_type_memory[] = { 5, 6, 16, 17, 255 }; 55 | static const u8 opt_type_cache[] = { 7, 255 }; 56 | static const u8 opt_type_connector[] = { 8, 255 }; 57 | static const u8 opt_type_slot[] = { 9, 255 }; 58 | 59 | static const struct type_keyword opt_type_keyword[] = { 60 | { "bios", opt_type_bios }, 61 | { "system", opt_type_system }, 62 | { "baseboard", opt_type_baseboard }, 63 | { "chassis", opt_type_chassis }, 64 | { "processor", opt_type_processor }, 65 | { "memory", opt_type_memory }, 66 | { "cache", opt_type_cache }, 67 | { "connector", opt_type_connector }, 68 | { "slot", opt_type_slot }, 69 | }; 70 | 71 | static void print_opt_type_list(void) 72 | { 73 | unsigned int i; 74 | 75 | fprintf(stderr, "Valid type keywords are:\n"); 76 | for (i = 0; i < ARRAY_SIZE(opt_type_keyword); i++) 77 | { 78 | fprintf(stderr, " %s\n", opt_type_keyword[i].keyword); 79 | } 80 | } 81 | 82 | static u8 *parse_opt_type(u8 *p, const char *arg) 83 | { 84 | unsigned int i; 85 | 86 | /* Allocate memory on first call only */ 87 | if (p == NULL) 88 | { 89 | p = (u8 *)calloc(256, sizeof(u8)); 90 | if (p == NULL) 91 | { 92 | perror("calloc"); 93 | return NULL; 94 | } 95 | } 96 | 97 | /* First try as a keyword */ 98 | for (i = 0; i < ARRAY_SIZE(opt_type_keyword); i++) 99 | { 100 | if (!strcasecmp(arg, opt_type_keyword[i].keyword)) 101 | { 102 | int j = 0; 103 | while (opt_type_keyword[i].type[j] != 255) 104 | p[opt_type_keyword[i].type[j++]] = 1; 105 | goto found; 106 | } 107 | } 108 | 109 | /* Else try as a number */ 110 | while (*arg != '\0') 111 | { 112 | unsigned long val; 113 | char *next; 114 | 115 | val = strtoul(arg, &next, 0); 116 | if (next == arg || (*next != '\0' && *next != ',' && *next != ' ')) 117 | { 118 | fprintf(stderr, "Invalid type keyword: %s\n", arg); 119 | print_opt_type_list(); 120 | goto exit_free; 121 | } 122 | if (val > 0xff) 123 | { 124 | fprintf(stderr, "Invalid type number: %lu\n", val); 125 | goto exit_free; 126 | } 127 | 128 | p[val] = 1; 129 | arg = next; 130 | while (*arg == ',' || *arg == ' ') 131 | arg++; 132 | } 133 | 134 | found: 135 | return p; 136 | 137 | exit_free: 138 | free(p); 139 | return NULL; 140 | } 141 | 142 | 143 | /* 144 | * Handling of option --string 145 | */ 146 | 147 | /* This lookup table could admittedly be reworked for improved performance. 148 | Due to the low count of items in there at the moment, it did not seem 149 | worth the additional code complexity though. */ 150 | static const struct string_keyword opt_string_keyword[] = { 151 | { "bios-vendor", 0, 0x04 }, 152 | { "bios-version", 0, 0x05 }, 153 | { "bios-release-date", 0, 0x08 }, 154 | { "bios-revision", 0, 0x15 }, /* 0x14 and 0x15 */ 155 | { "firmware-revision", 0, 0x17 }, /* 0x16 and 0x17 */ 156 | { "system-manufacturer", 1, 0x04 }, 157 | { "system-product-name", 1, 0x05 }, 158 | { "system-version", 1, 0x06 }, 159 | { "system-serial-number", 1, 0x07 }, 160 | { "system-uuid", 1, 0x08 }, /* dmi_system_uuid() */ 161 | { "system-sku-number", 1, 0x19 }, 162 | { "system-family", 1, 0x1a }, 163 | { "baseboard-manufacturer", 2, 0x04 }, 164 | { "baseboard-product-name", 2, 0x05 }, 165 | { "baseboard-version", 2, 0x06 }, 166 | { "baseboard-serial-number", 2, 0x07 }, 167 | { "baseboard-asset-tag", 2, 0x08 }, 168 | { "chassis-manufacturer", 3, 0x04 }, 169 | { "chassis-type", 3, 0x05 }, /* dmi_chassis_type() */ 170 | { "chassis-version", 3, 0x06 }, 171 | { "chassis-serial-number", 3, 0x07 }, 172 | { "chassis-asset-tag", 3, 0x08 }, 173 | { "processor-family", 4, 0x06 }, /* dmi_processor_family() */ 174 | { "processor-manufacturer", 4, 0x07 }, 175 | { "processor-version", 4, 0x10 }, 176 | { "processor-frequency", 4, 0x16 }, /* dmi_processor_frequency() */ 177 | }; 178 | 179 | /* This is a template, 3rd field is set at runtime. */ 180 | static struct string_keyword opt_oem_string_keyword = 181 | { NULL, 11, 0x00 }; 182 | 183 | static void print_opt_string_list(void) 184 | { 185 | unsigned int i; 186 | 187 | fprintf(stderr, "Valid string keywords are:\n"); 188 | for (i = 0; i < ARRAY_SIZE(opt_string_keyword); i++) 189 | { 190 | fprintf(stderr, " %s\n", opt_string_keyword[i].keyword); 191 | } 192 | } 193 | 194 | static int parse_opt_string(const char *arg) 195 | { 196 | unsigned int i; 197 | 198 | if (opt.string) 199 | { 200 | fprintf(stderr, "Only one string can be specified\n"); 201 | return -1; 202 | } 203 | 204 | for (i = 0; i < ARRAY_SIZE(opt_string_keyword); i++) 205 | { 206 | if (!strcasecmp(arg, opt_string_keyword[i].keyword)) 207 | { 208 | opt.string = &opt_string_keyword[i]; 209 | return 0; 210 | } 211 | } 212 | 213 | fprintf(stderr, "Invalid string keyword: %s\n", arg); 214 | print_opt_string_list(); 215 | return -1; 216 | } 217 | 218 | static int parse_opt_oem_string(const char *arg) 219 | { 220 | unsigned long val; 221 | char *next; 222 | 223 | if (opt.string) 224 | { 225 | fprintf(stderr, "Only one string can be specified\n"); 226 | return -1; 227 | } 228 | 229 | /* Return the number of OEM strings */ 230 | if (strcmp(arg, "count") == 0) 231 | goto done; 232 | 233 | val = strtoul(arg, &next, 10); 234 | if (next == arg || *next != '\0' || val == 0x00 || val > 0xff) 235 | { 236 | fprintf(stderr, "Invalid OEM string number: %s\n", arg); 237 | return -1; 238 | } 239 | 240 | opt_oem_string_keyword.offset = val; 241 | done: 242 | opt.string = &opt_oem_string_keyword; 243 | return 0; 244 | } 245 | 246 | static u32 parse_opt_handle(const char *arg) 247 | { 248 | u32 val; 249 | char *next; 250 | 251 | val = strtoul(arg, &next, 0); 252 | if (next == arg || *next != '\0' || val > 0xffff) 253 | { 254 | fprintf(stderr, "Invalid handle number: %s\n", arg); 255 | return ~0; 256 | } 257 | return val; 258 | } 259 | 260 | /* 261 | * Command line options handling 262 | */ 263 | 264 | /* Return -1 on error, 0 on success */ 265 | int parse_command_line(int argc, char * const argv[]) 266 | { 267 | int option; 268 | unsigned int i; 269 | const char *optstring = "d:hqs:t:uH:Vi:"; 270 | struct option longopts[] = { 271 | { "dev-mem", required_argument, NULL, 'd' }, 272 | { "input-file", required_argument, NULL, 'i' }, 273 | { "help", no_argument, NULL, 'h' }, 274 | { "quiet", no_argument, NULL, 'q' }, 275 | { "no-quirks", no_argument, NULL, 'Q' }, 276 | { "string", required_argument, NULL, 's' }, 277 | { "type", required_argument, NULL, 't' }, 278 | { "dump", no_argument, NULL, 'u' }, 279 | { "dump-bin", required_argument, NULL, 'B' }, 280 | { "from-dump", required_argument, NULL, 'F' }, 281 | { "handle", required_argument, NULL, 'H' }, 282 | { "oem-string", required_argument, NULL, 'O' }, 283 | { "no-sysfs", no_argument, NULL, 'S' }, 284 | { "list-strings", no_argument, NULL, 'L' }, 285 | { "list-types", no_argument, NULL, 'T' }, 286 | { "version", no_argument, NULL, 'V' }, 287 | { NULL, 0, NULL, 0 } 288 | }; 289 | 290 | while ((option = getopt_long(argc, argv, optstring, longopts, NULL)) != -1) 291 | switch (option) 292 | { 293 | case 'i': 294 | opt.devmem = optarg; 295 | opt.flags |= FLAG_READFILE; 296 | break; 297 | case 'B': 298 | opt.flags |= FLAG_DUMP_BIN; 299 | opt.dumpfile = optarg; 300 | break; 301 | case 'F': 302 | opt.flags |= FLAG_FROM_DUMP; 303 | opt.dumpfile = optarg; 304 | break; 305 | case 'd': 306 | opt.devmem = optarg; 307 | break; 308 | case 'h': 309 | opt.flags |= FLAG_HELP; 310 | break; 311 | case 'q': 312 | opt.flags |= FLAG_QUIET; 313 | break; 314 | case 'Q': 315 | opt.flags |= FLAG_NO_QUIRKS; 316 | break; 317 | case 's': 318 | if (parse_opt_string(optarg) < 0) 319 | return -1; 320 | opt.flags |= FLAG_QUIET; 321 | break; 322 | case 'O': 323 | if (parse_opt_oem_string(optarg) < 0) 324 | return -1; 325 | opt.flags |= FLAG_QUIET; 326 | break; 327 | case 't': 328 | opt.type = parse_opt_type(opt.type, optarg); 329 | if (opt.type == NULL) 330 | return -1; 331 | break; 332 | case 'H': 333 | opt.handle = parse_opt_handle(optarg); 334 | if (opt.handle == ~0U) 335 | return -1; 336 | break; 337 | case 'u': 338 | opt.flags |= FLAG_DUMP; 339 | break; 340 | case 'S': 341 | opt.flags |= FLAG_NO_SYSFS; 342 | break; 343 | case 'L': 344 | for (i = 0; i < ARRAY_SIZE(opt_string_keyword); i++) 345 | fprintf(stdout, "%s\n", opt_string_keyword[i].keyword); 346 | opt.flags |= FLAG_LIST; 347 | return 0; 348 | case 'T': 349 | for (i = 0; i < ARRAY_SIZE(opt_type_keyword); i++) 350 | fprintf(stdout, "%s\n", opt_type_keyword[i].keyword); 351 | opt.flags |= FLAG_LIST; 352 | return 0; 353 | case 'V': 354 | opt.flags |= FLAG_VERSION; 355 | break; 356 | case '?': 357 | switch (optopt) 358 | { 359 | case 's': 360 | fprintf(stderr, "String keyword expected\n"); 361 | print_opt_string_list(); 362 | break; 363 | case 't': 364 | fprintf(stderr, "Type number or keyword expected\n"); 365 | print_opt_type_list(); 366 | break; 367 | } 368 | return -1; 369 | } 370 | 371 | /* Check for mutually exclusive output format options */ 372 | if ((opt.string != NULL) + (opt.type != NULL) 373 | + !!(opt.flags & FLAG_DUMP_BIN) + (opt.handle != ~0U) > 1) 374 | { 375 | fprintf(stderr, "Options --string, --type, --handle and --dump-bin are mutually exclusive\n"); 376 | return -1; 377 | } 378 | 379 | if ((opt.flags & FLAG_FROM_DUMP) && (opt.flags & FLAG_DUMP_BIN)) 380 | { 381 | fprintf(stderr, "Options --from-dump and --dump-bin are mutually exclusive\n"); 382 | return -1; 383 | } 384 | 385 | return 0; 386 | } 387 | 388 | void print_help(void) 389 | { 390 | static const char *help = 391 | "Usage: dmidecode [OPTIONS]\n" 392 | "Options are:\n" 393 | " -i, --input-file Decode DMI data from a binary file\n" 394 | " -d, --dev-mem FILE Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n" 395 | " -h, --help Display this help text and exit\n" 396 | " -q, --quiet Less verbose output\n" 397 | " --no-quirks Decode everything without quirks\n" 398 | " -s, --string KEYWORD Only display the value of the given DMI string\n" 399 | " --list-strings List available string keywords and exit\n" 400 | " -t, --type TYPE Only display the entries of given type\n" 401 | " --list-types List available type keywords and exit\n" 402 | " -H, --handle HANDLE Only display the entry of given handle\n" 403 | " -u, --dump Do not decode the entries\n" 404 | " --dump-bin FILE Dump the DMI data to a binary file\n" 405 | " --from-dump FILE Read the DMI data from a binary file\n" 406 | " --no-sysfs Do not attempt to read DMI data from sysfs files\n" 407 | " --oem-string N Only display the value of the given OEM string\n" 408 | " -V, --version Display the version and exit\n"; 409 | 410 | printf("%s", help); 411 | } 412 | -------------------------------------------------------------------------------- /dmiopt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Command line handling of dmidecode 3 | * This file is part of the dmidecode project. 4 | * 5 | * Copyright (C) 2005-2023 Jean Delvare 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #include "types.h" 23 | 24 | struct string_keyword 25 | { 26 | const char *keyword; 27 | u8 type; 28 | u8 offset; 29 | }; 30 | 31 | struct opt 32 | { 33 | const char *devmem; 34 | unsigned int flags; 35 | u8 *type; 36 | const struct string_keyword *string; 37 | char *dumpfile; 38 | u32 handle; 39 | }; 40 | extern struct opt opt; 41 | 42 | #define FLAG_VERSION (1 << 0) 43 | #define FLAG_HELP (1 << 1) 44 | #define FLAG_DUMP (1 << 2) 45 | #define FLAG_QUIET (1 << 3) 46 | #define FLAG_DUMP_BIN (1 << 4) 47 | #define FLAG_FROM_DUMP (1 << 5) 48 | #define FLAG_NO_SYSFS (1 << 6) 49 | #define FLAG_NO_QUIRKS (1 << 7) 50 | #define FLAG_LIST (1 << 8) 51 | #define FLAG_READFILE (1 << 9) 52 | 53 | int parse_command_line(int argc, char * const argv[]); 54 | void print_help(void); 55 | -------------------------------------------------------------------------------- /dmioutput.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic output functions 3 | * This file is part of the dmidecode project. 4 | * 5 | * Copyright (C) 2020 Jean Delvare 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #include 23 | #include 24 | #include "dmioutput.h" 25 | 26 | void pr_comment(const char *format, ...) 27 | { 28 | va_list args; 29 | 30 | printf("# "); 31 | va_start(args, format); 32 | vprintf(format, args); 33 | va_end(args); 34 | printf("\n"); 35 | } 36 | 37 | void pr_info(const char *format, ...) 38 | { 39 | va_list args; 40 | 41 | va_start(args, format); 42 | vprintf(format, args); 43 | va_end(args); 44 | printf("\n"); 45 | } 46 | 47 | void pr_handle(const struct dmi_header *h) 48 | { 49 | printf("Handle 0x%04X, DMI type %d, %d bytes\n", 50 | h->handle, h->type, h->length); 51 | } 52 | 53 | void pr_handle_name(const char *format, ...) 54 | { 55 | va_list args; 56 | 57 | va_start(args, format); 58 | vprintf(format, args); 59 | va_end(args); 60 | printf("\n"); 61 | } 62 | 63 | void pr_attr(const char *name, const char *format, ...) 64 | { 65 | va_list args; 66 | 67 | printf("\t%s: ", name); 68 | 69 | va_start(args, format); 70 | vprintf(format, args); 71 | va_end(args); 72 | printf("\n"); 73 | } 74 | 75 | void pr_subattr(const char *name, const char *format, ...) 76 | { 77 | va_list args; 78 | 79 | printf("\t\t%s: ", name); 80 | 81 | va_start(args, format); 82 | vprintf(format, args); 83 | va_end(args); 84 | printf("\n"); 85 | } 86 | 87 | void pr_list_start(const char *name, const char *format, ...) 88 | { 89 | va_list args; 90 | 91 | printf("\t%s:", name); 92 | 93 | /* format is optional, skip value if not provided */ 94 | if (format) 95 | { 96 | printf(" "); 97 | va_start(args, format); 98 | vprintf(format, args); 99 | va_end(args); 100 | } 101 | printf("\n"); 102 | 103 | } 104 | 105 | void pr_list_item(const char *format, ...) 106 | { 107 | va_list args; 108 | 109 | printf("\t\t"); 110 | 111 | va_start(args, format); 112 | vprintf(format, args); 113 | va_end(args); 114 | printf("\n"); 115 | } 116 | 117 | void pr_list_end(void) 118 | { 119 | /* a no-op for text output */ 120 | } 121 | 122 | void pr_sep(void) 123 | { 124 | printf("\n"); 125 | } 126 | 127 | void pr_struct_err(const char *format, ...) 128 | { 129 | va_list args; 130 | 131 | printf("\t"); 132 | 133 | va_start(args, format); 134 | vprintf(format, args); 135 | va_end(args); 136 | printf("\n"); 137 | } 138 | -------------------------------------------------------------------------------- /dmioutput.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic output functions 3 | * This file is part of the dmidecode project. 4 | * 5 | * Copyright (C) 2020 Jean Delvare 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #include "dmidecode.h" 23 | 24 | void pr_comment(const char *format, ...); 25 | void pr_info(const char *format, ...); 26 | void pr_handle(const struct dmi_header *h); 27 | void pr_handle_name(const char *format, ...); 28 | void pr_attr(const char *name, const char *format, ...); 29 | void pr_subattr(const char *name, const char *format, ...); 30 | void pr_list_start(const char *name, const char *format, ...); 31 | void pr_list_item(const char *format, ...); 32 | void pr_list_end(void); 33 | void pr_sep(void); 34 | void pr_struct_err(const char *format, ...); 35 | -------------------------------------------------------------------------------- /man/biosdecode.8: -------------------------------------------------------------------------------- 1 | .TH BIOSDECODE 8 "February 2007" "dmidecode" 2 | .\" 3 | .SH NAME 4 | biosdecode \- \s-1BIOS\s0 information decoder 5 | .\" 6 | .SH SYNOPSIS 7 | .B biosdecode 8 | .RI [ OPTIONS ] 9 | .\" 10 | .SH DESCRIPTION 11 | .B biosdecode 12 | parses the \s-1BIOS\s0 memory and prints information about all structures (or 13 | entry points) it knows of. Currently known entry point types are: 14 | .IP \(bu "\w'\(bu'u+1n" 15 | \s-1SMBIOS\s0 (System Management \s-1BIOS\s0) 16 | .br 17 | Use 18 | .B dmidecode 19 | for a more detailed output. 20 | .IP \(bu 21 | \s-1DMI\s0 (Desktop Management Interface, a legacy version of \s-1SMBIOS\s0) 22 | .br 23 | Use 24 | .B dmidecode 25 | for a more detailed output. 26 | .IP \(bu 27 | \s-1SYSID\s0 28 | .IP \(bu 29 | \s-1PNP\s0 (Plug and Play) 30 | .IP \(bu 31 | \s-1ACPI\s0 (Advanced Configuration and Power Interface) 32 | .IP \(bu 33 | \s-1BIOS32\s0 (\s-1BIOS32\s0 Service Directory) 34 | .IP \(bu 35 | \s-1PIR\s0 (\s-1PCI\s0 \s-1IRQ\s0 Routing) 36 | .IP \(bu 37 | \s-132OS\s0 (\s-1BIOS32\s0 Extension, Compaq-specific) 38 | .br 39 | See 40 | .B ownership 41 | for a Compaq ownership tag retrieval tool. 42 | .IP \(bu 43 | \s-1SNY\s0 (Sony-specific, not decoded) 44 | .IP \(bu 45 | \s-1VPD\s0 (Vital Product Data, IBM-specific) 46 | .br 47 | Use 48 | .B vpddecode 49 | for a more detailed output. 50 | .IP \(bu 51 | \s-1FJKEYINF\s0 (Application Panel, Fujitsu-specific) 52 | 53 | .PP 54 | .B biosdecode 55 | started its life as a part of 56 | .B dmidecode 57 | but as more entry point types were added, it was moved to a different 58 | program. 59 | .\" 60 | .SH OPTIONS 61 | .TP 62 | .BR "-d" ", " "--dev-mem \fIFILE\fP" 63 | Read memory from device \fIFILE\fP (default: \fI/dev/mem\fP) 64 | .TP 65 | .BR " " " " "--pir \fBfull\fP" 66 | Decode the details of the PCI IRQ routing table. 67 | Only \fBfull\fP mode is supported. 68 | .TP 69 | .BR "-h" ", " "--help" 70 | Display usage information and exit 71 | .TP 72 | .BR "-V" ", " "--version" 73 | Display the version and exit 74 | .\" 75 | .SH FILES 76 | .I /dev/mem 77 | .\" 78 | .SH BUGS 79 | Most of the time, 80 | .B biosdecode 81 | prints too much information (you don't really care about addresses) 82 | or not enough (because it doesn't follow pointers and has no lookup 83 | tables). 84 | .\" 85 | .SH AUTHORS 86 | Alan Cox, Jean Delvare 87 | .\" 88 | .SH "SEE ALSO" 89 | .BR dmidecode (8), 90 | .BR mem (4), 91 | .BR ownership (8), 92 | .BR vpddecode (8) 93 | -------------------------------------------------------------------------------- /man/dmidecode.8: -------------------------------------------------------------------------------- 1 | .TH DMIDECODE 8 "February 2023" "dmidecode" 2 | .\" 3 | .SH NAME 4 | dmidecode \- \s-1DMI\s0 table decoder 5 | .\" 6 | .SH SYNOPSIS 7 | .B dmidecode 8 | .RI [ OPTIONS ] 9 | .\" 10 | .SH DESCRIPTION 11 | .B dmidecode 12 | is a tool for dumping a computer's \s-1DMI\s0 (some say \s-1SMBIOS\s0) table 13 | contents in a human-readable format. This table contains a description of the 14 | system's hardware components, as well as other useful pieces of information 15 | such as serial numbers and \s-1BIOS\s0 revision. Thanks to this table, you can 16 | retrieve this information without having to probe for the actual hardware. 17 | While this is a good point in terms of report speed and safeness, this also 18 | makes the presented information possibly unreliable. 19 | 20 | The \s-1DMI\s0 table doesn't only describe what the system is currently made 21 | of, it also can report the possible evolutions (such as the fastest supported 22 | \s-1CPU\s0 or the maximal amount of memory supported). 23 | 24 | \s-1SMBIOS\s0 stands for System Management \s-1BIOS\s0, while \s-1DMI\s0 25 | stands for Desktop Management Interface. Both standards are tightly related 26 | and developed by the \s-1DMTF\s0 (Desktop Management Task Force). 27 | 28 | As you run it, 29 | .B dmidecode 30 | will try to locate the \s-1DMI\s0 table. It will first try to read the DMI table 31 | from sysfs, and next try reading directly from memory if sysfs access failed. 32 | If 33 | .B dmidecode 34 | succeeds in locating a valid DMI table, it will then parse this table 35 | and display a list of records like this one: 36 | 37 | Handle 0x0002, DMI type 2, 8 bytes. 38 | Base Board Information 39 | Manufacturer: Intel 40 | Product Name: C440GX+ 41 | Version: 727281-001 42 | Serial Number: INCY92700942 43 | 44 | Each record has: 45 | .IP \(bu "\w'\(bu'u+1n" 46 | A handle. This is a unique identifier, which allows records to 47 | reference each other. For example, processor records usually reference 48 | cache memory records using their handles. 49 | .IP \(bu 50 | A type. The \s-1SMBIOS\s0 specification defines different types of elements 51 | a computer can be made of. In this example, the type is 2, which 52 | means that the record contains "Base Board Information". 53 | .IP \(bu 54 | A size. Each record has a 4-byte header (2 for the handle, 1 for the type, 55 | 1 for the size), the rest is used by the record data. This value doesn't 56 | take text strings into account (these are placed at the end of the record), 57 | so the actual length of the record may be (and is often) greater than the 58 | displayed value. 59 | .IP \(bu 60 | Decoded values. The information presented of course depends on the type 61 | of record. Here, we learn about the board's manufacturer, model, version 62 | and serial number. 63 | .\" 64 | .SH OPTIONS 65 | .TP 66 | .BR "-d" ", " "--dev-mem \fIFILE\fP" 67 | Read memory from device \fIFILE\fP (default: \fI/dev/mem\fP) 68 | .TP 69 | .BR "-q" ", " "--quiet" 70 | Be less verbose. Unknown, inactive and \s-1OEM\s0-specific entries are not 71 | displayed. Meta-data and handle references are hidden. 72 | .TP 73 | .BR " " " " "--no-quirks" 74 | Decode everything exactly as it is in the table, without trying to fix up 75 | common mistakes or hide irrelevant fields. 76 | This mode is primarily aimed at firmware developers. 77 | .TP 78 | .BR "-s" ", " "--string \fIKEYWORD\fP" 79 | Only display the value of the \s-1DMI\s0 string identified by \fIKEYWORD\fP. 80 | It must be a keyword from the following list: 81 | .nh 82 | .BR bios\-vendor , 83 | .BR bios\-version , 84 | .BR bios\-release\-date , 85 | .BR bios\-revision , 86 | .BR firmware\-revision , 87 | .BR system\-manufacturer , 88 | .BR system\-product\-name , 89 | .BR system\-version , 90 | .BR system\-serial\-number , 91 | .BR system\-uuid , 92 | .BR system\-sku\-number , 93 | .BR system\-family , 94 | .BR baseboard\-manufacturer , 95 | .BR baseboard\-product\-name , 96 | .BR baseboard\-version , 97 | .BR baseboard\-serial\-number , 98 | .BR baseboard\-asset\-tag , 99 | .BR chassis\-manufacturer , 100 | .BR chassis\-type , 101 | .BR chassis\-version , 102 | .BR chassis\-serial\-number , 103 | .BR chassis\-asset\-tag , 104 | .BR processor\-family , 105 | .BR processor\-manufacturer , 106 | .BR processor\-version , 107 | .BR processor\-frequency . 108 | .hy 109 | Each keyword corresponds to a given \s-1DMI\s0 type and a given offset 110 | within this entry type. 111 | Not all strings may be meaningful or even defined on all systems. Some 112 | keywords may return more than one result on some systems (e.g. 113 | .nh 114 | .B processor\-version 115 | .hy 116 | on a multi-processor system). 117 | If \fIKEYWORD\fP is not provided or not valid, a list of all valid 118 | keywords is printed and 119 | .B dmidecode 120 | exits with an error. 121 | This option cannot be used more than once. 122 | 123 | Note: on Linux, most of these strings can alternatively be read directly 124 | from 125 | .BR sysfs , 126 | typically from files under 127 | .IR /sys/devices/virtual/dmi/id . 128 | Most of these files are even readable by regular users. 129 | .TP 130 | .BR " " " " "--list-strings" 131 | List available string keywords, which can then be passed to the \fB--string\fP 132 | option. 133 | .TP 134 | .BR "-t" ", " "--type \fITYPE\fP" 135 | Only display the entries of type \fITYPE\fP. It can be either a 136 | \s-1DMI\s0 type number, or a comma-separated list of type numbers, or a 137 | keyword from the following list: 138 | .nh 139 | .BR bios , 140 | .BR system , 141 | .BR baseboard , 142 | .BR chassis , 143 | .BR processor , 144 | .BR memory , 145 | .BR cache , 146 | .BR connector , 147 | .BR slot . 148 | .hy 149 | Refer to the DMI TYPES section below for details. 150 | If this option is used more than once, the set of displayed entries will be 151 | the union of all the given types. 152 | If \fITYPE\fP is not provided or not valid, a list of all valid keywords 153 | is printed and 154 | .B dmidecode 155 | exits with an error. 156 | .TP 157 | .BR " " " " "--list-types" 158 | List available type keywords, which can then be passed to the \fB--type\fP 159 | option. 160 | .TP 161 | .BR "-H" ", " "--handle \fIHANDLE\fP" 162 | Only display the entry whose handle matches \fIHANDLE\fP. 163 | \fIHANDLE\fP is a 16-bit integer. 164 | .TP 165 | .BR "-u" ", " "--dump" 166 | Do not decode the entries, dump their contents as hexadecimal instead. 167 | Note that this is still a text output, no binary data will be thrown upon 168 | you. The strings attached to each entry are displayed as both 169 | hexadecimal and \s-1ASCII\s0. This option is mainly useful for debugging. 170 | .TP 171 | .BR " " " " "--dump-bin \fIFILE\fP" 172 | Do not decode the entries, instead dump the DMI data to a file in binary 173 | form. The generated file is suitable to pass to \fB--from-dump\fP 174 | later. 175 | \fIFILE\fP must not exist. 176 | .TP 177 | .BR " " " " "--from-dump \fIFILE\fP" 178 | Read the DMI data from a binary file previously generated using 179 | \fB--dump-bin\fP. 180 | .TP 181 | .BR " " " " "--no-sysfs" 182 | Do not attempt to read DMI data from sysfs files. This is mainly useful for 183 | debugging. 184 | .TP 185 | .BR " " " " "--oem-string \fIN\fP" 186 | Only display the value of the \s-1OEM\s0 string number \fIN\fP. The first 187 | \s-1OEM\s0 string has number \fB1\fP. With special value \fBcount\fP, return the 188 | number of OEM strings instead. 189 | .TP 190 | .BR "-h" ", " "--help" 191 | Display usage information and exit 192 | .TP 193 | .BR "-V" ", " "--version" 194 | Display the version and exit 195 | .P 196 | Options 197 | .BR --string , 198 | .BR --type, 199 | .BR --dump-bin " and " --oem-string 200 | determine the output format and are mutually exclusive. 201 | .P 202 | Please note in case of 203 | .B dmidecode 204 | is run on a system with BIOS that boasts new SMBIOS specification, which 205 | is not supported by the tool yet, it will print out relevant message in 206 | addition to requested data on the very top of the output. Thus informs the 207 | output data is not reliable. 208 | .\" 209 | .SH "DMI TYPES" 210 | The \s-1SMBIOS\s0 specification defines the following \s-1DMI\s0 types: 211 | .TS 212 | r l 213 | __ 214 | r l. 215 | Type Information 216 | 0 BIOS 217 | 1 System 218 | 2 Baseboard 219 | 3 Chassis 220 | 4 Processor 221 | 5 Memory Controller 222 | 6 Memory Module 223 | 7 Cache 224 | 8 Port Connector 225 | 9 System Slots 226 | 10 On Board Devices 227 | 11 OEM Strings 228 | 12 System Configuration Options 229 | 13 BIOS Language 230 | 14 Group Associations 231 | 15 System Event Log 232 | 16 Physical Memory Array 233 | 17 Memory Device 234 | 18 32-bit Memory Error 235 | 19 Memory Array Mapped Address 236 | 20 Memory Device Mapped Address 237 | 21 Built-in Pointing Device 238 | 22 Portable Battery 239 | 23 System Reset 240 | 24 Hardware Security 241 | 25 System Power Controls 242 | 26 Voltage Probe 243 | 27 Cooling Device 244 | 28 Temperature Probe 245 | 29 Electrical Current Probe 246 | 30 Out-of-band Remote Access 247 | 31 Boot Integrity Services 248 | 32 System Boot 249 | 33 64-bit Memory Error 250 | 34 Management Device 251 | 35 Management Device Component 252 | 36 Management Device Threshold Data 253 | 37 Memory Channel 254 | 38 IPMI Device 255 | 39 Power Supply 256 | 40 Additional Information 257 | 41 Onboard Devices Extended Information 258 | 42 Management Controller Host Interface 259 | .TE 260 | 261 | Additionally, type 126 is used for disabled entries and type 127 is an 262 | end-of-table marker. Types 128 to 255 are for \s-1OEM\s0-specific data. 263 | .B dmidecode 264 | will display these entries by default, but it can only decode them 265 | when the vendors have contributed documentation or code for them. 266 | 267 | Keywords can be used instead of type numbers with \fB--type\fP. 268 | Each keyword is equivalent to a list of type numbers: 269 | 270 | .TS 271 | l l 272 | __ 273 | l l. 274 | Keyword Types 275 | bios 0, 13 276 | system 1, 12, 15, 23, 32 277 | baseboard 2, 10, 41 278 | chassis 3 279 | processor 4 280 | memory 5, 6, 16, 17 281 | cache 7 282 | connector 8 283 | slot 9 284 | .TE 285 | 286 | Keywords are matched case-insensitively. The following command lines are equivalent: 287 | .IP \(bu "\w'\(bu'u+1n" 288 | dmidecode --type 0 --type 13 289 | .IP \(bu 290 | dmidecode --type 0,13 291 | .IP \(bu 292 | dmidecode --type bios 293 | .IP \(bu 294 | dmidecode --type BIOS 295 | .\" 296 | .SH BINARY DUMP FILE FORMAT 297 | The binary dump files generated by \fB--dump-bin\fP and read using \fB--from-dump\fP 298 | are formatted as follows: 299 | .IP \(bu "\w'\(bu'u+1n" 300 | The SMBIOS or DMI entry point is located at offset 0x00. 301 | It is crafted to hard-code the table address at offset 0x20. 302 | .IP \(bu "\w'\(bu'u+1n" 303 | The DMI table is located at offset 0x20. 304 | .\" 305 | .SH UUID FORMAT 306 | There is some ambiguity about how to interpret the UUID fields prior to SMBIOS 307 | specification version 2.6. There was no mention of byte swapping, and RFC 4122 308 | says that no byte swapping should be applied by default. However, SMBIOS 309 | specification version 2.6 (and later) explicitly states that the first 3 fields 310 | of the UUID should be read as little-endian numbers (byte-swapped). 311 | Furthermore, it implies that the same was already true for older versions of 312 | the specification, even though it was not mentioned. In practice, many hardware 313 | vendors were not byte-swapping the UUID. So, in order to preserve 314 | compatibility, it was decided to interpret the UUID fields according to RFC 315 | 4122 (no byte swapping) when the SMBIOS version is older than 2.6, and to 316 | interpret the first 3 fields as little-endian (byte-swapped) when the SMBIOS 317 | version is 2.6 or later. The Linux kernel follows the same logic. 318 | .\" 319 | .SH FILES 320 | .I /dev/mem 321 | .br 322 | .I /sys/firmware/dmi/tables/smbios_entry_point 323 | (Linux only) 324 | .br 325 | .I /sys/firmware/dmi/tables/DMI 326 | (Linux only) 327 | .\" 328 | .SH BUGS 329 | More often than not, information contained in the \s-1DMI\s0 tables is inaccurate, 330 | incomplete or simply wrong. 331 | .\" 332 | .SH AUTHORS 333 | Alan Cox, Jean Delvare 334 | .\" 335 | .SH "SEE ALSO" 336 | .BR biosdecode (8), 337 | .BR mem (4), 338 | .BR ownership (8), 339 | .BR vpddecode (8) 340 | -------------------------------------------------------------------------------- /man/ownership.8: -------------------------------------------------------------------------------- 1 | .TH OWNERSHIP 8 "February 2005" "dmidecode" 2 | .\" 3 | .SH NAME 4 | ownership \- Compaq ownership tag retriever 5 | .\" 6 | .SH SYNOPSIS 7 | .B ownership 8 | .RI [ OPTIONS ] 9 | .\" 10 | .SH DESCRIPTION 11 | .B ownership 12 | retrieves and prints the "ownership tag" that can be set on Compaq 13 | computers. Contrary to all other programs of the 14 | .B dmidecode 15 | package, 16 | .B ownership 17 | doesn't print any version information, nor labels, but only the raw 18 | ownership tag. This should help its integration in scripts. 19 | .\" 20 | .SH OPTIONS 21 | .TP 22 | .BR "-d" ", " "--dev-mem \fIFILE\fP" 23 | Read memory from device \fIFILE\fP (default: \fI/dev/mem\fP) 24 | .TP 25 | .BR "-h" ", " "--help" 26 | Display usage information and exit 27 | .TP 28 | .BR "-V" ", " "--version" 29 | Display the version and exit 30 | .\" 31 | .SH FILES 32 | .I /dev/mem 33 | .\" 34 | .SH AUTHOR 35 | Jean Delvare 36 | .\" 37 | .SH "SEE ALSO" 38 | .BR biosdecode (8), 39 | .BR dmidecode (8), 40 | .BR mem (4), 41 | .BR vpddecode (8) 42 | -------------------------------------------------------------------------------- /man/vpddecode.8: -------------------------------------------------------------------------------- 1 | .TH VPDDECODE 8 "February 2007" "dmidecode" 2 | .\" 3 | .SH NAME 4 | vpddecode \- \s-1VPD\s0 structure decoder 5 | .\" 6 | .SH SYNOPSIS 7 | .B vpddecode 8 | .RI [ OPTIONS ] 9 | .\" 10 | .SH DESCRIPTION 11 | .B vpddecode 12 | prints the "vital product data" information that can be found in almost 13 | all IBM and Lenovo computers. Available items are: 14 | .IP \(bu "\w'\(bu'u+1n" 15 | \s-1BIOS\s0 Build \s-1ID\s0 16 | .IP \(bu 17 | Box Serial Number 18 | .IP \(bu 19 | Motherboard Serial Number 20 | .IP \(bu 21 | Machine Type/Model 22 | .PP 23 | Some systems have these additional items: 24 | .IP \(bu "\w'\(bu'u+1n" 25 | BIOS Release Date 26 | .IP \(bu 27 | Default Flash Image File Name 28 | .PP 29 | Note that these additional items are not documented by IBM, so this is 30 | guess work, and as such should not be blindly trusted. Feedback about 31 | the accuracy of these labels is welcome. 32 | .\" 33 | .SH OPTIONS 34 | .TP 35 | .BR "-d" ", " "--dev-mem \fIFILE\fP" 36 | Read memory from device \fIFILE\fP (default: \fI/dev/mem\fP) 37 | .TP 38 | .BR "-s" ", " "--string \fIKEYWORD\fP" 39 | Only display the value of the \s-1VPD\s0 string identified by \fIKEYWORD\fP. 40 | It must be a keyword from the following list: 41 | .nh 42 | .BR bios-build-id , 43 | .BR box-serial-number , 44 | .BR motherboard-serial-number , 45 | .BR machine-type-model , 46 | .BR bios-release-date . 47 | .hy 48 | Each keyword corresponds to an offset and a length within the \s-1VPD\s0 49 | record. 50 | Not all strings may be defined on all \s-1VPD\s0-enabled systems. 51 | If \fIKEYWORD\fP is not provided or not valid, a list of all valid 52 | keywords is printed and 53 | .B vpddecode 54 | exits with an error. 55 | This option cannot be used more than once. 56 | Mutually exclusive with \fB--dump\fP. 57 | .TP 58 | .BR "-u" ", " "--dump" 59 | Do not decode the VPD records, dump their contents as hexadecimal instead. 60 | Note that this is still a text output, no binary data will be thrown upon 61 | you. ASCII equivalent is displayed when possible. This option is mainly 62 | useful for debugging. 63 | Mutually exclusive with \fB--string\fP. 64 | .TP 65 | .BR "-h" ", " "--help" 66 | Display usage information and exit 67 | .TP 68 | .BR "-V" ", " "--version" 69 | Display the version and exit 70 | .\" 71 | .SH FILES 72 | .I /dev/mem 73 | .\" 74 | .SH AUTHOR 75 | Jean Delvare 76 | .\" 77 | .SH "SEE ALSO" 78 | .BR biosdecode (8), 79 | .BR dmidecode (8), 80 | .BR mem (4), 81 | .BR ownership (8) 82 | -------------------------------------------------------------------------------- /ownership.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Compaq Ownership Tag 3 | * 4 | * Copyright (C) 2003-2005 Jean Delvare 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | * 20 | * For the avoidance of doubt the "preferred form" of this code is one which 21 | * is in an open unpatent encumbered format. Where cryptographic key signing 22 | * forms part of the process of creating an executable the information 23 | * including keys needed to generate an equivalently functional executable 24 | * are deemed to be part of the source code. 25 | * 26 | * References: 27 | * - Compaq "Technical Reference Guide for Compaq Deskpro 4000 and 6000" 28 | * First Edition 29 | * http://h18000.www1.hp.com/support/techpubs/technical_reference_guides/113a1097.html 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "version.h" 39 | #include "config.h" 40 | #include "types.h" 41 | #include "util.h" 42 | 43 | /* Options are global */ 44 | struct opt 45 | { 46 | const char *devmem; 47 | unsigned int flags; 48 | }; 49 | static struct opt opt; 50 | 51 | #define FLAG_VERSION (1 << 0) 52 | #define FLAG_HELP (1 << 1) 53 | 54 | static void ownership(u32 base, const char *pname, const char *devmem) 55 | { 56 | u8 *buf; 57 | int i; 58 | 59 | /* read the ownership tag */ 60 | if ((buf = mem_chunk(base, 0x51, devmem)) == NULL) 61 | { 62 | perror(pname); 63 | return; 64 | } 65 | 66 | /* chop the trailing garbage */ 67 | i = 0x4f; 68 | while (i >= 0 && (buf[i] == 0x20 || buf[i] == 0x00)) 69 | i--; 70 | buf[i + 1] = '\0'; 71 | 72 | /* filter and print */ 73 | if (i >= 0) 74 | { 75 | for (; i >= 0; i--) 76 | { 77 | if (buf[i] < 32 || (buf[i] >= 127 && buf[i] < 160)) 78 | buf[i] = '?'; 79 | } 80 | printf("%s\n", (char *)buf); 81 | } 82 | 83 | free(buf); 84 | } 85 | 86 | static u32 decode(const u8 *p) 87 | { 88 | int i; 89 | 90 | /* integrity checking (lack of checksum) */ 91 | for (i = 0; i < p[4]; i++) 92 | { 93 | if (p[5 + i * 10] != '$' 94 | || !(p[6 + i * 10] >= 'A' && p[6 + i * 10] <= 'Z') 95 | || !(p[7 + i * 10] >= 'A' && p[7 + i * 10] <= 'Z') 96 | || !(p[8 + i * 10] >= 'A' && p[8 + i * 10] <= 'Z')) 97 | { 98 | printf("\t Abnormal Entry! Please report. [%02x %02x %02x %02x]\n", 99 | p[5 + i * 10], p[6 + i * 10], 100 | p[7 + i * 10], p[8 + i * 10]); 101 | return 0; 102 | } 103 | } 104 | 105 | /* search for the right entry */ 106 | for (i = 0; i < p[4]; i++) 107 | if (memcmp(p + 5 + i * 10, "$ERB", 4) == 0) 108 | return DWORD(p + 9 + i * 10); 109 | 110 | return 0; 111 | } 112 | 113 | /* Return -1 on error, 0 on success */ 114 | static int parse_command_line(int argc, char * const argv[]) 115 | { 116 | int option; 117 | const char *optstring = "d:hV"; 118 | struct option longopts[] = { 119 | { "dev-mem", required_argument, NULL, 'd' }, 120 | { "help", no_argument, NULL, 'h' }, 121 | { "version", no_argument, NULL, 'V' }, 122 | { NULL, 0, NULL, 0 } 123 | }; 124 | 125 | while ((option = getopt_long(argc, argv, optstring, longopts, NULL)) != -1) 126 | switch (option) 127 | { 128 | case 'd': 129 | opt.devmem = optarg; 130 | break; 131 | case 'h': 132 | opt.flags |= FLAG_HELP; 133 | break; 134 | case 'V': 135 | opt.flags |= FLAG_VERSION; 136 | break; 137 | case '?': 138 | return -1; 139 | } 140 | 141 | return 0; 142 | } 143 | 144 | static void print_help(void) 145 | { 146 | static const char *help = 147 | "Usage: ownership [OPTIONS]\n" 148 | "Options are:\n" 149 | " -d, --dev-mem FILE Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n" 150 | " -h, --help Display this help text and exit\n" 151 | " -V, --version Display the version and exit\n"; 152 | 153 | printf("%s", help); 154 | } 155 | 156 | int main(int argc, char * const argv[]) 157 | { 158 | u8 *buf; 159 | off_t fp; 160 | int ok = 0; 161 | 162 | if (sizeof(u8) != 1 || sizeof(u32) != 4) 163 | { 164 | fprintf(stderr, "%s: compiler incompatibility\n", argv[0]); 165 | exit(255); 166 | } 167 | 168 | /* Set default option values */ 169 | opt.devmem = DEFAULT_MEM_DEV; 170 | opt.flags = 0; 171 | 172 | if (parse_command_line(argc, argv)<0) 173 | exit(2); 174 | 175 | if (opt.flags & FLAG_HELP) 176 | { 177 | print_help(); 178 | return 0; 179 | } 180 | 181 | if (opt.flags & FLAG_VERSION) 182 | { 183 | printf("%s\n", VERSION); 184 | return 0; 185 | } 186 | 187 | if ((buf = mem_chunk(0xE0000, 0x20000, opt.devmem)) == NULL) 188 | exit(1); 189 | 190 | for (fp = 0; !ok && fp <= 0x1FFF0; fp += 16) 191 | { 192 | u8 *p = buf + fp; 193 | 194 | if (memcmp((char *)p, "32OS", 4) == 0) 195 | { 196 | off_t len = p[4] * 10 + 5; 197 | 198 | if (fp + len - 1 <= 0x1FFFF) 199 | { 200 | u32 base; 201 | 202 | if ((base = decode(p))) 203 | { 204 | ok = 1; 205 | ownership(base, argv[0], opt.devmem); 206 | } 207 | } 208 | } 209 | } 210 | 211 | free(buf); 212 | 213 | return 0; 214 | } 215 | -------------------------------------------------------------------------------- /types.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H 2 | #define TYPES_H 3 | 4 | #include "config.h" 5 | 6 | typedef unsigned char u8; 7 | typedef unsigned short u16; 8 | typedef signed short i16; 9 | typedef unsigned int u32; 10 | 11 | /* 12 | * You may use the following defines to adjust the type definitions 13 | * depending on the architecture: 14 | * - Define BIGENDIAN on big-endian systems. 15 | * - Define ALIGNMENT_WORKAROUND if your system doesn't support 16 | * non-aligned memory access. In this case, we use a slower, but safer, 17 | * memory access method. This should be done automatically in config.h 18 | * for architectures which need it. 19 | */ 20 | 21 | #ifdef BIGENDIAN 22 | typedef struct { 23 | u32 h; 24 | u32 l; 25 | } u64; 26 | #else 27 | typedef struct { 28 | u32 l; 29 | u32 h; 30 | } u64; 31 | #endif 32 | 33 | #if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN) 34 | static inline u64 U64(u32 low, u32 high) 35 | { 36 | u64 self; 37 | 38 | self.l = low; 39 | self.h = high; 40 | 41 | return self; 42 | } 43 | #endif 44 | 45 | /* 46 | * Per SMBIOS v2.8.0 and later, all structures assume a little-endian 47 | * ordering convention. 48 | */ 49 | #if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN) 50 | #define WORD(x) (u16)((x)[0] + ((x)[1] << 8)) 51 | #define DWORD(x) (u32)((x)[0] + ((x)[1] << 8) + ((x)[2] << 16) + ((x)[3] << 24)) 52 | #define QWORD(x) (U64(DWORD(x), DWORD(x + 4))) 53 | #else /* ALIGNMENT_WORKAROUND || BIGENDIAN */ 54 | #define WORD(x) (u16)(*(const u16 *)(x)) 55 | #define DWORD(x) (u32)(*(const u32 *)(x)) 56 | #define QWORD(x) (*(const u64 *)(x)) 57 | #endif /* ALIGNMENT_WORKAROUND || BIGENDIAN */ 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Common "util" functions 3 | * This file is part of the dmidecode project. 4 | * 5 | * Copyright (C) 2002-2023 Jean Delvare 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | * 21 | * For the avoidance of doubt the "preferred form" of this code is one which 22 | * is in an open unpatent encumbered format. Where cryptographic key signing 23 | * forms part of the process of creating an executable the information 24 | * including keys needed to generate an equivalently functional executable 25 | * are deemed to be part of the source code. 26 | */ 27 | 28 | #include 29 | #include 30 | 31 | #include "config.h" 32 | 33 | #ifdef USE_MMAP 34 | #include 35 | #ifndef MAP_FAILED 36 | #define MAP_FAILED ((void *) -1) 37 | #endif /* !MAP_FAILED */ 38 | #endif /* USE MMAP */ 39 | 40 | #ifdef __APPLE__ 41 | #include 42 | #include 43 | #endif 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #include "types.h" 53 | #include "util.h" 54 | 55 | static int myread(int fd, u8 *buf, size_t count, const char *prefix) 56 | { 57 | ssize_t r = 1; 58 | size_t r2 = 0; 59 | 60 | while (r2 != count && r != 0) 61 | { 62 | r = read(fd, buf + r2, count - r2); 63 | if (r == -1) 64 | { 65 | if (errno != EINTR) 66 | { 67 | perror(prefix); 68 | return -1; 69 | } 70 | } 71 | else 72 | r2 += r; 73 | } 74 | 75 | if (r2 != count) 76 | { 77 | fprintf(stderr, "%s: Unexpected end of file\n", prefix); 78 | return -1; 79 | } 80 | 81 | return 0; 82 | } 83 | 84 | int checksum(const u8 *buf, size_t len) 85 | { 86 | u8 sum = 0; 87 | size_t a; 88 | 89 | for (a = 0; a < len; a++) 90 | sum += buf[a]; 91 | return (sum == 0); 92 | } 93 | 94 | /* 95 | * Reads all of file from given offset, up to max_len bytes. 96 | * A buffer of at most max_len bytes is allocated by this function, and 97 | * needs to be freed by the caller. 98 | * This provides a similar usage model to mem_chunk() 99 | * 100 | * Returns a pointer to the allocated buffer, or NULL on error, and 101 | * sets max_len to the length actually read. 102 | */ 103 | void *read_file(off_t base, size_t *max_len, const char *filename) 104 | { 105 | struct stat statbuf; 106 | int fd; 107 | u8 *p; 108 | 109 | /* 110 | * Don't print error message on missing file, as we will try to read 111 | * files that may or may not be present. 112 | */ 113 | if ((fd = open(filename, O_RDONLY)) == -1) 114 | { 115 | if (errno != ENOENT) 116 | perror(filename); 117 | return NULL; 118 | } 119 | 120 | /* 121 | * Check file size, don't allocate more than can be read. 122 | */ 123 | if (fstat(fd, &statbuf) == 0) 124 | { 125 | if (base >= statbuf.st_size) 126 | { 127 | fprintf(stderr, "%s: Can't read data beyond EOF\n", 128 | filename); 129 | p = NULL; 130 | goto out; 131 | } 132 | if (*max_len > (size_t)statbuf.st_size - base) 133 | *max_len = statbuf.st_size - base; 134 | } 135 | 136 | if ((p = malloc(*max_len)) == NULL) 137 | { 138 | perror("malloc"); 139 | goto out; 140 | } 141 | 142 | if (lseek(fd, base, SEEK_SET) == -1) 143 | { 144 | fprintf(stderr, "%s: ", filename); 145 | perror("lseek"); 146 | goto err_free; 147 | } 148 | 149 | if (myread(fd, p, *max_len, filename) == 0) 150 | goto out; 151 | 152 | err_free: 153 | free(p); 154 | p = NULL; 155 | 156 | out: 157 | if (close(fd) == -1) 158 | perror(filename); 159 | 160 | return p; 161 | } 162 | 163 | static void *mem_chunk_ioreg(off_t base, size_t len) 164 | { 165 | #ifdef __APPLE__ 166 | CFDataRef data; 167 | CFStringRef field; 168 | io_registry_entry_t entry; 169 | void *blob; 170 | size_t org_len; 171 | 172 | if (base == 0xF0000) 173 | { 174 | field = CFSTR("SMBIOS-EPS"); 175 | } 176 | else 177 | { 178 | field = CFSTR("SMBIOS"); 179 | } 180 | 181 | data = NULL; 182 | entry = IORegistryEntryFromPath(kIOMasterPortDefault, 183 | "IOService:/AppleACPIPlatformExpert/bios/AppleSMBIOS"); 184 | if (entry != MACH_PORT_NULL) 185 | { 186 | data = IORegistryEntryCreateCFProperty(entry, field, kCFAllocatorDefault, 0); 187 | if (data != NULL) 188 | { 189 | if (CFGetTypeID(data) != CFDataGetTypeID()) 190 | { 191 | CFRelease(data); 192 | data = NULL; 193 | } 194 | } 195 | IOObjectRelease(entry); 196 | } 197 | 198 | if (data != NULL) 199 | { 200 | if ((blob = calloc(1, len)) != NULL) 201 | { 202 | org_len = (size_t)CFDataGetLength(data); 203 | if (org_len < len) 204 | len = org_len; 205 | memcpy(blob, CFDataGetBytePtr(data), len); 206 | CFRelease(data); 207 | return blob; 208 | } else { 209 | CFRelease(data); 210 | perror("malloc"); 211 | return NULL; 212 | } 213 | } 214 | 215 | #endif 216 | 217 | fprintf(stderr, "Unable to access I/O Registry at %lx for %lu bytes\n", 218 | (unsigned long)base, (unsigned long)len); 219 | return NULL; 220 | } 221 | 222 | #ifdef USE_MMAP 223 | static void safe_memcpy(void *dest, const void *src, size_t n) 224 | { 225 | #ifdef USE_SLOW_MEMCPY 226 | size_t i; 227 | 228 | for (i = 0; i < n; i++) 229 | *((u8 *)dest + i) = *((const u8 *)src + i); 230 | #else 231 | memcpy(dest, src, n); 232 | #endif /* USE_SLOW_MEMCPY */ 233 | } 234 | #endif /* USE_MMAP */ 235 | 236 | /* 237 | * Copy a physical memory chunk into a memory buffer. 238 | * This function allocates memory. 239 | */ 240 | void *mem_chunk(off_t base, size_t len, const char *devmem) 241 | { 242 | struct stat statbuf; 243 | void *p = NULL; 244 | int fd; 245 | #ifdef USE_MMAP 246 | off_t mmoffset; 247 | void *mmp; 248 | #endif 249 | 250 | if (strcmp(devmem, "I/O Registry") == 0) { 251 | return mem_chunk_ioreg(base, len); 252 | } 253 | 254 | /* 255 | * Safety check: if running as root, devmem is expected to be a 256 | * character device file. 257 | */ 258 | if ((fd = open(devmem, O_RDONLY)) == -1 259 | || fstat(fd, &statbuf) == -1 260 | || (geteuid() == 0 && !S_ISCHR(statbuf.st_mode))) 261 | { 262 | fprintf(stderr, "Can't read memory from %s\n", devmem); 263 | if (fd == -1) 264 | return NULL; 265 | goto out; 266 | } 267 | 268 | if ((p = malloc(len)) == NULL) 269 | { 270 | perror("malloc"); 271 | goto out; 272 | } 273 | 274 | #ifdef USE_MMAP 275 | /* 276 | * mmap() will fail with SIGBUS if trying to map beyond the end of 277 | * the file. 278 | */ 279 | if (S_ISREG(statbuf.st_mode) && base + (off_t)len > statbuf.st_size) 280 | { 281 | fprintf(stderr, "mmap: Can't map beyond end of file %s\n", 282 | devmem); 283 | goto err_free; 284 | } 285 | 286 | #ifdef _SC_PAGESIZE 287 | mmoffset = base % sysconf(_SC_PAGESIZE); 288 | #else 289 | mmoffset = base % getpagesize(); 290 | #endif /* _SC_PAGESIZE */ 291 | /* 292 | * Please note that we don't use mmap() for performance reasons here, 293 | * but to workaround problems many people encountered when trying 294 | * to read from /dev/mem using regular read() calls. 295 | */ 296 | mmp = mmap(NULL, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset); 297 | if (mmp == MAP_FAILED) 298 | goto try_read; 299 | 300 | safe_memcpy(p, (u8 *)mmp + mmoffset, len); 301 | 302 | if (munmap(mmp, mmoffset + len) == -1) 303 | { 304 | fprintf(stderr, "%s: ", devmem); 305 | perror("munmap"); 306 | } 307 | 308 | goto out; 309 | 310 | try_read: 311 | #endif /* USE_MMAP */ 312 | if (lseek(fd, base, SEEK_SET) == -1) 313 | { 314 | fprintf(stderr, "%s: ", devmem); 315 | perror("lseek"); 316 | goto err_free; 317 | } 318 | 319 | if (myread(fd, p, len, devmem) == 0) 320 | goto out; 321 | 322 | err_free: 323 | free(p); 324 | p = NULL; 325 | 326 | out: 327 | if (close(fd) == -1) 328 | perror(devmem); 329 | 330 | return p; 331 | } 332 | 333 | /* Returns end - start + 1, assuming start < end */ 334 | u64 u64_range(u64 start, u64 end) 335 | { 336 | u64 res; 337 | 338 | res.h = end.h - start.h; 339 | res.l = end.l - start.l; 340 | 341 | if (end.l < start.l) 342 | res.h--; 343 | if (++res.l == 0) 344 | res.h++; 345 | 346 | return res; 347 | } 348 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the dmidecode project. 3 | * 4 | * Copyright (C) 2003-2023 Jean Delvare 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #include 22 | 23 | #include "types.h" 24 | 25 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) 26 | 27 | int checksum(const u8 *buf, size_t len); 28 | void *read_file(off_t base, size_t *len, const char *filename); 29 | void *mem_chunk(off_t base, size_t len, const char *devmem); 30 | u64 u64_range(u64 start, u64 end); 31 | -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | #define VERSION "3.6a" 2 | -------------------------------------------------------------------------------- /vpddecode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * IBM Vital Product Data decoder 3 | * 4 | * Copyright (C) 2003-2007 Jean Delvare 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | * 20 | * For the avoidance of doubt the "preferred form" of this code is one which 21 | * is in an open unpatent encumbered format. Where cryptographic key signing 22 | * forms part of the process of creating an executable the information 23 | * including keys needed to generate an equivalently functional executable 24 | * are deemed to be part of the source code. 25 | * 26 | * References: 27 | * - IBM "Using the BIOS Build ID to identify Thinkpad systems" 28 | * Revision 2006-01-31 29 | * http://www-307.ibm.com/pc/support/site.wss/MIGR-45120.html 30 | * 31 | * Notes: 32 | * - Main part of the code is taken directly from biosdecode, with an 33 | * additional command line interface and a few experimental features. 34 | */ 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include "version.h" 42 | #include "config.h" 43 | #include "types.h" 44 | #include "util.h" 45 | #include "vpdopt.h" 46 | 47 | static void print_entry(const char *name, const u8 *p, size_t len) 48 | { 49 | size_t i; 50 | 51 | if (name != NULL) 52 | printf("%s: ", name); 53 | for (i = 0; i < len; i++) 54 | { 55 | /* ASCII filtering */ 56 | if (p[i] >= 32 && p[i] < 127) 57 | printf("%c", p[i]); 58 | else if (p[i] != 0) 59 | printf("."); 60 | } 61 | printf("\n"); 62 | } 63 | 64 | static void dump(const u8 *p, u8 len) 65 | { 66 | int done, i, min; 67 | 68 | for (done = 0; done < len; done += 16) 69 | { 70 | printf("%02X:", done); 71 | min = (len - done < 16) ? len - done : 16; 72 | 73 | /* As hexadecimal first */ 74 | for (i = 0; i < min; i++) 75 | printf(" %02X", p[done + i]); 76 | for (; i < 16; i++) /* Complete line if needed */ 77 | printf(" "); 78 | printf(" "); 79 | 80 | /* And now as text, with ASCII filtering */ 81 | for (i = 0; i < min; i++) 82 | printf("%c", (p[done + i] >= 32 && p[done + i] < 127) ? 83 | p[done + i] : '.'); 84 | printf("\n"); 85 | } 86 | } 87 | 88 | static int decode(const u8 *p) 89 | { 90 | if (p[5] < 0x30) 91 | return 0; 92 | 93 | /* XSeries have longer records, exact length seems to vary. */ 94 | if (!(p[5] >= 0x45 && checksum(p, p[5])) 95 | /* Some Netvista seem to work with this. */ 96 | && !(checksum(p, 0x30)) 97 | /* The Thinkpad/Thinkcentre checksum does *not* include the first 98 | 13 bytes. */ 99 | && !(checksum(p + 0x0D, 0x30 - 0x0D))) 100 | { 101 | /* A few systems have a bad checksum (xSeries 325, 330, 335 102 | and 345 with early BIOS) but the record is otherwise 103 | valid. */ 104 | if (!(opt.flags & FLAG_QUIET)) 105 | printf("# Bad checksum!\n"); 106 | } 107 | 108 | if (opt.string != NULL) 109 | { 110 | if (opt.string->offset + opt.string->len < p[5]) 111 | print_entry(NULL, p + opt.string->offset, 112 | opt.string->len); 113 | return 1; 114 | } 115 | 116 | print_entry("BIOS Build ID", p + 0x0D, 9); 117 | print_entry("Box Serial Number", p + 0x16, 7); 118 | print_entry("Motherboard Serial Number", p + 0x1D, 11); 119 | print_entry("Machine Type/Model", p + 0x28, 7); 120 | 121 | if (p[5] < 0x44) 122 | return 1; 123 | 124 | print_entry("BIOS Release Date", p + 0x30, 8); 125 | print_entry("Default Flash Image File Name", p + 0x38, 12); 126 | 127 | if (p[5] >= 0x46 && p[0x44] != 0x00) 128 | { 129 | printf("%s: %u\n", "BIOS Revision", p[0x44]); 130 | } 131 | 132 | return 1; 133 | } 134 | 135 | int main(int argc, char * const argv[]) 136 | { 137 | u8 *buf; 138 | int found = 0; 139 | unsigned int fp; 140 | 141 | if (sizeof(u8) != 1) 142 | { 143 | fprintf(stderr, "%s: compiler incompatibility\n", argv[0]); 144 | exit(255); 145 | } 146 | 147 | /* Set default option values */ 148 | opt.devmem = DEFAULT_MEM_DEV; 149 | opt.flags = 0; 150 | 151 | if (parse_command_line(argc, argv)<0) 152 | exit(2); 153 | 154 | if (opt.flags & FLAG_HELP) 155 | { 156 | print_help(); 157 | return 0; 158 | } 159 | 160 | if (opt.flags & FLAG_VERSION) 161 | { 162 | printf("%s\n", VERSION); 163 | return 0; 164 | } 165 | 166 | if (!(opt.flags & FLAG_QUIET)) 167 | printf("# vpddecode %s\n", VERSION); 168 | 169 | if ((buf = mem_chunk(0xF0000, 0x10000, opt.devmem)) == NULL) 170 | exit(1); 171 | 172 | for (fp = 0; fp <= 0xFFF0; fp += 4) 173 | { 174 | u8 *p = buf + fp; 175 | 176 | if (memcmp((char *)p, "\252\125VPD", 5) == 0 177 | && fp + p[5] - 1 <= 0xFFFF) 178 | { 179 | if (fp % 16 && !(opt.flags & FLAG_QUIET)) 180 | printf("# Unaligned address (%#x)\n", 181 | 0xf0000 + fp); 182 | if (opt.flags & FLAG_DUMP) 183 | { 184 | dump(p, p[5]); 185 | found++; 186 | } 187 | else 188 | { 189 | if (decode(p)) 190 | found++; 191 | } 192 | } 193 | } 194 | 195 | free(buf); 196 | 197 | if (!found && !(opt.flags & FLAG_QUIET)) 198 | printf("# No VPD structure found, sorry.\n"); 199 | 200 | return 0; 201 | } 202 | -------------------------------------------------------------------------------- /vpdopt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Command line handling of vpddecode 3 | * This file is part of the dmidecode project. 4 | * 5 | * Copyright (C) 2005-2007 Jean Delvare 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "config.h" 28 | #include "util.h" 29 | #include "vpdopt.h" 30 | 31 | 32 | /* Options are global */ 33 | struct opt opt; 34 | 35 | 36 | /* 37 | * Handling of option --string 38 | */ 39 | 40 | /* This lookup table could admittedly be reworked for improved performance. 41 | Due to the low count of items in there at the moment, it did not seem 42 | worth the additional code complexity though. */ 43 | static const struct string_keyword opt_string_keyword[] = { 44 | { "bios-build-id", 0x0D, 9 }, 45 | { "box-serial-number", 0x16, 7 }, 46 | { "motherboard-serial-number", 0x1D, 11 }, 47 | { "machine-type-model", 0x28, 7 }, 48 | { "bios-release-date", 0x30, 8 }, 49 | }; 50 | 51 | static void print_opt_string_list(void) 52 | { 53 | unsigned int i; 54 | 55 | fprintf(stderr, "Valid string keywords are:\n"); 56 | for (i = 0; i < ARRAY_SIZE(opt_string_keyword); i++) 57 | { 58 | fprintf(stderr, " %s\n", opt_string_keyword[i].keyword); 59 | } 60 | } 61 | 62 | static int parse_opt_string(const char *arg) 63 | { 64 | unsigned int i; 65 | 66 | if (opt.string) 67 | { 68 | fprintf(stderr, "Only one string can be specified\n"); 69 | return -1; 70 | } 71 | 72 | for (i = 0; i 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #include 23 | 24 | struct string_keyword 25 | { 26 | const char *keyword; 27 | off_t offset; 28 | size_t len; 29 | }; 30 | 31 | struct opt 32 | { 33 | const char *devmem; 34 | unsigned int flags; 35 | const struct string_keyword *string; 36 | }; 37 | extern struct opt opt; 38 | 39 | #define FLAG_VERSION (1 << 0) 40 | #define FLAG_HELP (1 << 1) 41 | #define FLAG_DUMP (1 << 2) 42 | #define FLAG_QUIET (1 << 3) 43 | 44 | int parse_command_line(int argc, char * const argv[]); 45 | void print_help(void); 46 | --------------------------------------------------------------------------------