diff --git a/.autoheader b/.autoheader index bc6e134..fb8f9cc 100644 --- a/.autoheader +++ b/.autoheader @@ -1,6 +1,6 @@ -© 2007-2009 Nima Talebi -© 2009 David Sommerseth +© 2007-2010 Nima Talebi +© 2009-2010 David Sommerseth © 2002-2008 Jean Delvare © 2000-2002 Alan Cox diff --git a/.github/.codecov.yml b/.github/.codecov.yml new file mode 100644 index 0000000..b89aac2 --- /dev/null +++ b/.github/.codecov.yml @@ -0,0 +1,29 @@ +codecov: + notify: + require_ci_to_pass: yes + +coverage: + precision: 2 + round: down + range: "70...100" + + status: + project: yes + patch: + default: + target: auto + threshold: 100% + changes: no + +parsers: + gcov: + branch_detection: + conditional: yes + loop: yes + method: no + macro: no + +comment: + layout: "header, diff" + behavior: default + require_changes: no diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..cb46c7e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,25 @@ +language: c +sudo: true + +env: + global: + - CODECOV_TOKEN=4792f32d-1685-4e2d-8cc4-b82e9578a605 + +before_install: + - sudo apt-get update -qq + - sudo apt-get install python-libxml2 libxml2-dev python-dev + +script: + - sed 's/$(CC)/$(CC) -coverage/g' Makefile > t_makefile + - cp t_makefile Makefile + - rm -f t_makefile + - make GCOV=1 build + - make GCOV=1 unit + - find build/ -name '*.gcno' -exec mv {} ./ \; + - find build/ -name '*.gcda' -exec mv {} ./ \; + - make GCOV=1 dmidump + - sudo ./dmidump /dev/mem /dev/null + - make GCOV=1 version + +after_success: + - bash <(curl -s https://codecov.io/bash) -F unittest diff --git a/Makefile b/Makefile index 107dbdb..2f47a75 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,57 @@ +#. ******* coding:utf-8 AUTOHEADER START v1.2 ******* +#. vim: fileencoding=utf-8 syntax=Makefile sw=4 ts=4 et #. -#. DMI Decode Python Extension Module +#. © 2007-2010 Nima Talebi +#. © 2009-2010 David Sommerseth +#. © 2002-2008 Jean Delvare +#. © 2000-2002 Alan Cox #. -#. (C) 2008 Nima Talebi +#. This file is part of python-dmidecode. #. -#. Licensed under the GNU Public License v2 +#. python-dmidecode is free software: you can redistribute it and/or modify +#. it under the terms of the GNU General Public License as published by +#. the Free Software Foundation, either version 2 of the License, or +#. (at your option) any later version. #. +#. python-dmidecode is distributed in the hope that it will be useful, +#. but WITHOUT ANY WARRANTY; without even the implied warranty of +#. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#. GNU General Public License for more details. +#. +#. You should have received a copy of the GNU General Public License +#. along with python-dmidecode. If not, see . +#. +#. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +#. WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +#. MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +#. EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +#. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +#. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +#. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +#. LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +#. OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +#. ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#. +#. ADAPTED M. STONE & T. PARKER DISCLAIMER: THIS SOFTWARE COULD RESULT IN INJURY +#. AND/OR DEATH, AND AS SUCH, IT SHOULD NOT BE BUILT, INSTALLED OR USED BY ANYONE. +#. +#. $AutoHeaderSerial::20100225 $ +#. ******* AUTOHEADER END v1.2 ******* -VERSION := $(shell cd src;python -c "from setup_common import *; print get_version();") +PY_BIN := python3 +VERSION := $(shell cd src;$(PY_BIN) -c "from setup_common import *; print(get_version());") PACKAGE := python-dmidecode -PY_VER := $(shell python -c 'import sys; print "%d.%d"%sys.version_info[0:2]') +PY_VER := $(shell $(PY_BIN) -c 'import sys; print("%d.%d"%sys.version_info[0:2])') +PY_MV := $(shell echo $(PY_VER) | cut -b 1) PY := python$(PY_VER) -SO = build/lib.linux-$(shell uname -m)-$(PY_VER)/dmidecodemod.so +SO_PATH := build/lib.linux-$(shell uname -m)-$(PY_VER) +ifeq ($(PY_MV),2) + SO := $(SO_PATH)/dmidecodemod.so +else + SOABI := $(shell $(PY_BIN) -c 'import sysconfig; print(sysconfig.get_config_var("SOABI"))') + SO := $(SO_PATH)/dmidecodemod.$(SOABI).so +endif +SHELL := /bin/bash ############################################################################### .PHONY: build dmidump install uninstall clean tarball rpm unit version @@ -23,7 +64,7 @@ $(PY)-dmidecodemod.so: $(SO) $(SO): $(PY) src/setup.py build -dmidump : src/util.o src/efi.o +dmidump : src/util.o src/efi.o src/dmilog.o $(CC) -o $@ src/dmidump.c $^ -g -Wall -D_DMIDUMP_MAIN_ install: @@ -34,25 +75,31 @@ uninstall: clean: -$(PY) src/setup.py clean --all - -rm -f *.so lib/*.o core dmidump + -rm -f *.so lib/*.o core dmidump src/*.o -rm -rf build -rm -rf rpm -rm -rf src/setup_common.py[oc] + -rm -rf __pycache__ src/__pycache__ -rm -rf $(PACKAGE)-$(VERSION) $(PACKAGE)-$(VERSION).tar.gz $(MAKE) -C unit-tests clean tarball: rm -rf $(PACKAGE)-$(VERSION) mkdir $(PACKAGE)-$(VERSION) - cp -r contrib doc examples Makefile man README src dmidecode.py $(PACKAGE)-$(VERSION) + cp -r contrib doc examples Makefile man README src dmidecode.py unit-tests/ $(PACKAGE)-$(VERSION) tar -czvf $(PACKAGE)-$(VERSION).tar.gz $(PACKAGE)-$(VERSION) -rpm: tarball +rpm-prep: mkdir -p rpm/{BUILD,RPMS,SRPMS,SPECS,SOURCES} cp contrib/$(PACKAGE).spec rpm/SPECS cp $(PACKAGE)-$(VERSION).tar.gz rpm/SOURCES + +rpm: tarball rpm-prep rpmbuild -ba --define "_topdir $(shell pwd)/rpm" rpm/SPECS/$(PACKAGE).spec +rpm-md5: tarball rpm-prep + rpmbuild-md5 -ba --define "_topdir $(shell pwd)/rpm" rpm/SPECS/$(PACKAGE).spec + unit: $(MAKE) -C unit-tests @@ -60,3 +107,8 @@ version: @echo "python-dmidecode: $(VERSION)" @echo "python version: $(PY_VER) ($(PY))" +conflicts: + @comm -12 \ + <(dpkg-deb -c ../../DPKGS/python-dmidecode_$(VERSION)-1_amd64.deb | awk '$$NF!~/\/$$/{print$$NF}'|sort) \ + <(dpkg-deb -c ../../DPKGS/python-dmidecode-dbg_$(VERSION)-1_amd64.deb | awk '$$NF!~/\/$$/{print$$NF}'|sort) + diff --git a/README b/README index 4892ef5..8b13789 100644 --- a/README +++ b/README @@ -1 +1 @@ -Please visit http://projects.autonomy.net.au/python-dmidecode/ + diff --git a/contrib/python-dmidecode.spec b/contrib/python-dmidecode.spec index 0d48fc3..2c7f942 100644 --- a/contrib/python-dmidecode.spec +++ b/contrib/python-dmidecode.spec @@ -1,16 +1,15 @@ -%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} -%{!?python_ver: %define python_ver %(%{__python} -c "import sys ; print sys.version[:3]")} +%{!?python_sitearch: %global python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} +%{!?python_ver: %global python_ver %(%{__python} -c "import sys ; print sys.version[:3]")} -Summary: python extension module to access DMI data +Summary: Python module to access DMI data Name: python-dmidecode -Version: 3.10.6 -Release: 6%{?dist} +Version: 3.12.3 +Release: 1%{?dist} License: GPLv2 Group: System Environment/Libraries -URL: http://projects.autonomy.net.au/dmidecode/ -Source0: %{name}-%{version}.tar.gz +URL: http://projects.autonomy.net.au/python-dmidecode/ +Source0: http://src.autonomy.net.au/python-dmidecode/%{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root -Requires: libxml2 Requires: libxml2-python BuildRequires: libxml2-python BuildRequires: libxml2-devel @@ -26,10 +25,13 @@ as python data structures or as XML data using libxml2. %build make build +cd unit-tests +make +cd .. %install rm -rf $RPM_BUILD_ROOT -python src/setup.py install --root $RPM_BUILD_ROOT +python src/setup.py install --root $RPM_BUILD_ROOT --prefix=%{_prefix} %clean rm -rf $RPM_BUILD_ROOT @@ -37,16 +39,68 @@ rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,-) -%doc +%doc README doc/README.upstream doc/LICENSE doc/AUTHORS doc/AUTHORS.upstream %{python_sitearch}/dmidecodemod.so %{python_sitearch}/dmidecode.py %{python_sitearch}/dmidecode.py[co] %if "%{python_ver}" >= "2.5" %{python_sitearch}/*.egg-info %endif -/usr/share/python-dmidecode/pymap.xml +%{_datadir}/python-dmidecode/ %changelog +* Thu Nov 17 2022 Lianbo Jiang - 3.12.3-1 +- Update to new release + +* Mon Jun 08 2015 Nima Talebi - 3.12.2-1 +- Update to new release + +* Mon Jul 8 2013 David Sommerseth - 3.12.1-1 +- Updated against upstream v3.12.1, which realigns against dmidecode 2.12 + +* Thu Jul 4 2013 David Sommerseth - 3.11.1-1 +- Updated against upstream v3.11.1, which realigns against dmidecode 2.11 + +* Wed Jul 3 2013 David Sommerseth - 3.10.15-1 +- Update to new release + +* Fri Apr 05 2013 David Sommerseth - 3.10.14-1 +- Update to new release + +* Thu Jun 03 2010 Nima Talebi - 3.10.13-1 +- Update to new release + +* Fri Mar 12 2010 Nima Talebi - 3.10.12-1 +- Update to new release + +* Tue Feb 16 2010 Nima Talebi - 3.10.11-1 +- Update to new release + +* Tue Jan 12 2010 Nima Talebi - 3.10.10-1 +- Update to new release + +* Thu Jan 07 2010 Nima Talebi - 3.10.9-1 +- Update to new release + + +* Thu Dec 15 2009 Nima Talebi - 3.10.8-1 +- New Upstream release. +- Big-endian and little-endian approved. +- Packaged unit-test to tarball. +- Rewritten unit-test to be able to run as non-root user, where it will not + try to read /dev/mem. +- Added two dmidump data files to the unit-test. + +* Thu Nov 26 2009 David Sommerseth - 3.10.7-3 +- Fixed even more .spec file issues and removed explicit mentioning + of /usr/share/python-dmidecode/pymap.xml + +* Wed Nov 25 2009 David Sommerseth - 3.10.7-2 +- Fixed some .spec file issues (proper Requires, use _datadir macro) + +* Wed Sep 23 2009 Nima Talebi - 3.10.7-1 +- Updated source0 to new 3.10.7 tar ball + * Wed Jul 13 2009 David Sommerseth - 3.10.6-6 - Only build the python-dmidecode module, not everything diff --git a/debian/changelog b/debian/changelog index 01b37e7..4bd61c9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,94 @@ +python-dmidecode (3.10.13-1) unstable; urgency=low + + * New upstream release. + + -- Nima Talebi Thu, 03 Jun 2010 19:56:38 +1000 + +python-dmidecode (3.10.12-2) unstable; urgency=low + + * Added a missing dependency (Closes: Bug#578891) - thanks to Sven Wick for + the bug report. + + -- Nima Talebi Fri, 23 Apr 2010 22:25:55 +1000 + +python-dmidecode (3.10.12-1) unstable; urgency=low + + * Switch to dpkg-source 3.0 (quilt) format + * Upstream bugfix release. See the following URI for details: + https://bugzilla.redhat.com/show_bug.cgi?id=583867 + + -- Nima Talebi Fri, 23 Apr 2010 22:24:50 +1000 + +python-dmidecode (3.10.11-2) unstable; urgency=low + + * Small fix to example file. + + -- Nima Talebi Thu, 04 Mar 2010 10:55:55 +1100 + +python-dmidecode (3.10.11-1) unstable; urgency=low + + * New upstream release. + * Log messages no longer handled via `fprintf' statements, but handled + inside a data structure and dealt with accordingly. + + -- Nima Talebi Tue, 16 Feb 2010 08:30:44 +1100 + +python-dmidecode (3.10.10-1) unstable; urgency=low + + * New upstream cleanup release. + * This release has addressed the previously messy error/warning handling. + + -- Nima Talebi Tue, 12 Jan 2010 11:59:27 +1100 + +python-dmidecode (3.10.9-1) unstable; urgency=low + + * New upstream bug-fix release. + * Add --install-layout=deb to debian/rules setup.py install to prevent files + from landing in /usr/local (Closes: Bug#563883) - thanks to Scott + Kitterman. + -- Nima Talebi Tue, 05 Jan 2010 22:02:29 -0500 + +python-dmidecode (3.10.8-2) unstable; urgency=low + + * Resolved conflict between standard and debug package (Closes: #561904). + + -- Nima Talebi Sun, 20 Dec 2009 11:17:37 +1100 + +python-dmidecode (3.10.8-1) unstable; urgency=low + + * New Upstream release. + * Big-endian and little-endian approved. + * Packaged unit-test to tarball. + * Rewritten unit-test to be able to run as non-root user, where it will not + try to read /dev/mem. + * Added two dmidump data files to the unit-test. + + -- Nima Talebi Tue, 15 Dec 2009 10:33:31 +1100 + +python-dmidecode (3.10.7-3) unstable; urgency=low + + * Last of URI fixes (#540389). + + -- Nima Talebi Sun, 13 Dec 2009 04:20:55 +1100 + +python-dmidecode (3.10.7-2) unstable; urgency=low + + * Added libxml2 dependencies (Closes: #548669). + + -- Nima Talebi Mon, 28 Sep 2009 18:59:05 +1000 + +python-dmidecode (3.10.7-1) unstable; urgency=low + + * New Upstream release. + + -- Nima Talebi Wed, 23 Sep 2009 18:43:29 +1000 + +python-dmidecode (3.10.6-3) unstable; urgency=low + + * Updating debian/* to generate package. + + -- Nima Talebi Wed, 09 Sep 2009 23:01:48 +1000 + python-dmidecode (3.10.6-2) unstable; urgency=low * Fixed homepage (Closes: #540389). diff --git a/debian/control b/debian/control index f0f88e9..9a0297b 100644 --- a/debian/control +++ b/debian/control @@ -4,15 +4,15 @@ Section: python Priority: optional Homepage: http://projects.autonomy.net.au/python-dmidecode Maintainer: Nima Talebi -Build-Depends: debhelper (> 7), python-support (>= 0.5.3), python, - python-all-dev (>= 2.3.5-11), python-all-dbg, electric-fence (> 2) -Standards-Version: 3.8.1 +Build-Depends: debhelper (>> 7), python-support (>= 0.5.3), python, + python-all-dev (>= 2.5.4-2), python-all-dbg, libxml2-dev, python-libxml2 +Standards-Version: 3.8.4 Package: python-dmidecode XB-Python-Version: ${python:Versions} Architecture: any Provides: ${python:Provides} -Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends} +Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}, python-libxml2 Description: Python extension module for dmidecode DMI (the desktop management interface) provides a standardized description of a computer's hardware, including characteristics such as BIOS serial number diff --git a/debian/rules b/debian/rules index 906da77..c33d38d 100755 --- a/debian/rules +++ b/debian/rules @@ -13,6 +13,7 @@ build-ext-%: python$* src/setup.py build touch $@ build-dbg-ext-%: + cp dmidecode.py dmidecode-dbg.py python$*-dbg src/setup-dbg.py build touch $@ @@ -30,10 +31,14 @@ install: install-stamp dh_installman install-stamp: build-stamp $(PYVERS:%=install-ext-%) $(PYVERS:%=install-dbg-ext-%) install-ext-%: - python$* src/setup.py install --root $(CURDIR)/debian/$(PACKAGE) + python$* src/setup.py install \ + --root $(CURDIR)/debian/$(PACKAGE) \ + --install-layout=deb touch $@ install-dbg-ext-%: - python$*-dbg src/setup-dbg.py install --root $(CURDIR)/debian/$(PACKAGE)-dbg + python$*-dbg src/setup-dbg.py install \ + --root $(CURDIR)/debian/$(PACKAGE)-dbg \ + --install-layout=deb #find $(CURDIR)/debian/$(PACKAGE)-dbg/usr/lib/python$*/ ! -type d ! -name '*_d\.so' -delete #find $(CURDIR)/debian/$(PACKAGE)-dbg/usr/lib/python$*/ -depth -empty -delete touch $@ @@ -60,7 +65,7 @@ clean: dh_testdir dh_testroot $(MAKE) -f Makefile clean - dh_clean build-stamp install-stamp \ + dh_clean build-stamp install-stamp dmidecode-dbg.py \ $(PYVERS:%=install-ext-%) $(PYVERS:%=build-ext-%) \ $(PYVERS:%=install-dbg-ext-%) $(PYVERS:%=build-dbg-ext-%) diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/dmidecode.py b/dmidecode.py index cd37b40..ac81365 100644 --- a/dmidecode.py +++ b/dmidecode.py @@ -48,7 +48,7 @@ def SetResultType(self, type): elif type == DMIXML_DOC: self.restype = DMIXML_DOC else: - raise TypeError, "Invalid result type value" + raise TypeError("Invalid result type value") return True def QuerySection(self, sectname): @@ -65,7 +65,7 @@ def QuerySection(self, sectname): result_type=self.restype, section=sectname) ) else: - raise TypeError, "Invalid result type value" + raise TypeError("Invalid result type value") return ret @@ -83,7 +83,7 @@ def QueryTypeId(self, tpid): result_type=self.restype, typeid=tpid)) else: - raise TypeError, "Invalid result type value" + raise TypeError("Invalid result type value") return ret diff --git a/doc/AUTHORS b/doc/AUTHORS index b061b5d..6c1d024 100644 --- a/doc/AUTHORS +++ b/doc/AUTHORS @@ -1,4 +1,4 @@ -DEVELOPER AND MAINTAINER OF PYTHON MODULE (http://projects.autonomy.net.au/dmidecode) +DEVELOPER AND MAINTAINER OF PYTHON MODULE (http://projects.autonomy.net.au/python-dmidecode) Nima Talebi David Sommerseth diff --git a/examples/dmidump.py b/examples/dmidump.py index a6c7bf7..769750d 100755 --- a/examples/dmidump.py +++ b/examples/dmidump.py @@ -1,54 +1,179 @@ -#!/usr/bin/env python2.4 +#!/usr/bin/env python +# +# Examples which makes use of the different python-dmidecode features +# This script should be run as root, or else expect permission warnings +# +# Copyright 2008-2009 Nima Talebi +# Copyright 2010 David Sommerseth +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# For the avoidance of doubt the "preferred form" of this code is one which +# is in an open unpatent encumbered format. Where cryptographic key signing +# forms part of the process of creating an executable the information +# including keys needed to generate an equivalently functional executable +# are deemed to be part of the source code. +# + import dmidecode -import sys +import sys, os from pprint import pprint -#. Test all functions using /dev/mem... -print "*** bios ***\n"; dmidecode.bios() -print "*** system ***\n"; dmidecode.system() -print "*** system ***\n"; dmidecode.system() -print "*** baseboard ***\n"; dmidecode.baseboard() -print "*** chassis ***\n"; dmidecode.chassis() -print "*** processor ***\n"; dmidecode.processor() -print "*** memory ***\n"; dmidecode.memory() -print "*** cache ***\n"; dmidecode.cache() -print "*** connector ***\n"; dmidecode.connector() -print "*** slot ***\n"; dmidecode.slot() +def print_warnings(): + "Simple function, dumping out warnings with a prefix if warnings are found and clearing warning buffer" + warn = dmidecode.get_warnings() + if warn: + print("### WARNING: %s" % warn) + dmidecode.clear_warnings() + + +# Check if running as root .... provide a warning if not +root_user = (os.getuid() == 0 and True or False) +if not root_user: + print("####") + print("#### NOT RUNNING AS ROOT") + print("####") + print("#### The first run must always be done as root for this example to work.") + print("#### When not run as root, quite some permission errors might appear") + print("####") + print("#### If this script is first run as root, it should be possible to run this script") + print("#### as an unprivileged user afterwards, with less warnings.") + print("####") + print() + print() + + +#. Test for presence of important functions using /dev/mem... Using the legacy API +#. This does not print any decoded info. If the call fails, either a warning will +#. be issued or an exception will be raised. This test is now only used to check +#. for presence of the legacy API, which "under the hood" uses +#. dmidecode.QuerySection(name), where name can be 'bios', 'system', etc. +if root_user: + print("*** bios ***\n"); dmidecode.bios() + print_warnings() + print("*** system ***\n"); dmidecode.system() + print_warnings() + print("*** baseboard ***\n"); dmidecode.baseboard() + print_warnings() + print("*** chassis ***\n"); dmidecode.chassis() + print_warnings() + print("*** processor ***\n"); dmidecode.processor() + print_warnings() + print("*** memory ***\n"); dmidecode.memory() + print_warnings() + print("*** cache ***\n"); dmidecode.cache() + print_warnings() + print("*** connector ***\n"); dmidecode.connector() + print_warnings() + print("*** slot ***\n"); dmidecode.slot() + print_warnings() + #. Now test get/set of memory device file... -print dmidecode.get_dev() -print dmidecode.set_dev("private/mem-XXX"); -print dmidecode.get_dev() +print("*** get_dev()") +print(dmidecode.get_dev()) +print_warnings() +print("*** set_dev('dmidata.dump')") +print(dmidecode.set_dev("dmidata.dump")); +print_warnings() +print("*** get_dev()") +print(dmidecode.get_dev()) +print_warnings() #. Test taking a dump... -print dmidecode.dump() - -#. Test reading the dump... -print "*** bios ***\n"; pprint(dmidecode.bios()) -print "*** system ***\n"; pprint(dmidecode.system()) -print "*** system ***\n"; pprint(dmidecode.system()) -print "*** baseboard ***\n"; pprint(dmidecode.baseboard()) -print "*** chassis ***\n"; pprint(dmidecode.chassis()) -print "*** processor ***\n"; pprint(dmidecode.processor()) -print "*** memory ***\n"; pprint(dmidecode.memory()) -print "*** cache ***\n"; pprint(dmidecode.cache()) -print "*** connector ***\n"; pprint(dmidecode.connector()) -print "*** slot ***\n"; pprint(dmidecode.slot()) - -sys.exit(0) -print "*** bios ***\n"; pprint(dmidecode.bios()) -print "*** system ***\n"; pprint(dmidecode.system()) -print "*** baseboard ***\n"; pprint(dmidecode.baseboard()) -print "*** chassis ***\n"; pprint(dmidecode.chassis()) -print "*** processor ***\n"; pprint(dmidecode.processor()) -print "*** memory ***\n"; pprint(dmidecode.memory()) -print "*** cache ***\n"; pprint(dmidecode.cache()) -print "*** connector ***\n"; pprint(dmidecode.connector()) -print "*** slot ***\n"; pprint(dmidecode.slot()) +if root_user: + print("*** Dumping DMI data to dump file") + print(dmidecode.dump()) + print_warnings() +#. Test reading the dump... Using the preferred API +print("*** bios ***\n"); pprint(dmidecode.QuerySection('bios')) +print_warnings() +print("*** system ***\n"); pprint(dmidecode.QuerySection('system')) +print_warnings() +print("*** baseboard ***\n"); pprint(dmidecode.QuerySection('baseboard')) +print_warnings() +print("*** chassis ***\n"); pprint(dmidecode.QuerySection('chassis')) +print_warnings() +print("*** processor ***\n"); pprint(dmidecode.QuerySection('processor')) +print_warnings() +print("*** memory ***\n"); pprint(dmidecode.QuerySection('memory')) +print_warnings() +print("*** cache ***\n"); pprint(dmidecode.QuerySection('cache')) +print_warnings() +print("*** connector ***\n"); pprint(dmidecode.QuerySection('connector')) +print_warnings() +print("*** slot ***\n"); pprint(dmidecode.QuerySection('slot')) +print_warnings() + +print("*** Extracting memory information") for v in dmidecode.memory().values(): if type(v) == dict and v['dmi_type'] == 17: pprint(v['data']['Size']), -pprint(dmidecode.type('3')) -pprint(dmidecode.type('bios')) +print("*** Querying for DMI type 3 and 7") +pprint(dmidecode.type(3)) # <-- Legacy API +pprint(dmidecode.QueryTypeId(7)) # <-- preferred API +print_warnings() + +print("*** Querying for the BIOS section") +pprint(dmidecode.QuerySection('bios')) +print_warnings() + +# +# Test XML stuff +# +print() +print() +print() +print("---------------------------------------") +print("*** *** *** Testing XML API *** *** ***") +print("---------------------------------------") +print() +print() +dmixml = dmidecode.dmidecodeXML() + +# Fetch all DMI data into a libxml2.xmlDoc object +print("*** Getting all DMI data into a XML document variable") +dmixml.SetResultType(dmidecode.DMIXML_DOC) # Valid values: dmidecode.DMIXML_DOC, dmidecode.DMIXML_NODE +xmldoc = dmixml.QuerySection('all') + +# Dump the XML to dmidump.xml - formated in UTF-8 decoding +print("*** Dumping XML document to dmidump.xml") +xmldoc.saveFormatFileEnc('dmidump.xml','UTF-8',1) + +# Do some XPath queries on the XML document +print("*** Doing some XPath queries against the XML document") +dmixp = xmldoc.xpathNewContext() + +# What to look for - XPath expressions +keys = ['/dmidecode/SystemInfo/Manufacturer', + '/dmidecode/SystemInfo/ProductName', + '/dmidecode/SystemInfo/SerialNumber', + '/dmidecode/SystemInfo/SystemUUID'] + +# Extract data and print it +for k in keys: + data = dmixp.xpathEval(k) + for d in data: + print("%s: %s" % (k, d.get_content())) + +del dmixp +del xmldoc + +# Query for only a particular DMI TypeID - 0x04 - Processor +print("*** Quering for Type ID 0x04 - Processor - dumping XML document to stdout") +dmixml.QueryTypeId(0x04).saveFormatFileEnc('-','UTF-8',1) +print_warnings() diff --git a/man/dmidecode.8 b/man/dmidecode.8 index 1e8fed8..f5fef0d 100644 --- a/man/dmidecode.8 +++ b/man/dmidecode.8 @@ -1,4 +1,4 @@ -.TH DMIDECODE 8 "October 2008" "dmidecode" +.TH DMIDECODE 8 "March 2012" "dmidecode" .SH NAME dmidecode \- \s-1DMI\s0 table decoder .SH SYNOPSIS @@ -127,6 +127,13 @@ Display the version and exit .P Options --string, --type, --dump and --dump-bin determine the output format and are mutually exclusive. +.P +Please note in case of +.B dmidecode +is run on a system with BIOS that boasts new SMBIOS specification, which +is not supported by the tool yet, it will print out relevant message in +addition to requested data on the very top of the output. Thus informs the +output data is not reliable. .SH "DMI TYPES" The \s-1SMBIOS\s0 specification defines the following \s-1DMI\s0 types: @@ -138,7 +145,7 @@ r l. Type Information 0 BIOS 1 System -2 Base Board +2 Baseboard 3 Chassis 4 Processor 5 Memory Controller @@ -176,6 +183,9 @@ Type Information 37 Memory Channel 38 IPMI Device 39 Power Supply +40 Additional Information +41 Onboard Devices Extended Information +42 Management Controller Host Interface .TE Additionally, type 126 is used for disabled entries and type 127 is an diff --git a/src/compat.h b/src/compat.h index 80a08c6..170f596 100644 --- a/src/compat.h +++ b/src/compat.h @@ -40,4 +40,19 @@ #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None #endif +// Python 2 vs Python 3 compat +#if PY_MAJOR_VERSION >= 3 +#define IS_PY3K +#define MODINITERROR return NULL +#define PYNUMBER_FROMLONG PyLong_FromLong +#define PYTEXT_FROMSTRING PyUnicode_FromString +#else +#include +#define MODINITERROR return +#define PYNUMBER_FROMLONG PyInt_FromLong +#define PYTEXT_FROMSTRING PyString_FromString +#define PyCapsule_New(pointer, name, destructor) \ + (PyCObject_FromVoidPtr(pointer, destructor)) +#endif + #endif diff --git a/src/config.h b/src/config.h index 2876788..ac3c942 100644 --- a/src/config.h +++ b/src/config.h @@ -41,7 +41,7 @@ #define CONFIG_H /* Default memory device file */ -#ifdef __BEOS__ +#if defined(__BEOS__) || defined(__HAIKU__) #define DEFAULT_MEM_DEV "/dev/misc/mem" #else #define DEFAULT_MEM_DEV "/dev/mem" @@ -53,7 +53,7 @@ #endif /* Use memory alignment workaround or not */ -#ifdef __ia64__ +#if defined(__ia64__) || defined(__arm__) #define ALIGNMENT_WORKAROUND #endif diff --git a/src/dmidecode.c b/src/dmidecode.c index aa2332d..d40f0ee 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -2,9 +2,9 @@ /*. ******* coding:utf-8 AUTOHEADER START v1.1 ******* *. vim: fileencoding=utf-8 syntax=c sw=2 ts=2 et *. - *. © 2007-2009 Nima Talebi - *. © 2009 David Sommerseth - *. © 2002-2008 Jean Delvare + *. © 2007-2013 Nima Talebi + *. © 2009-2013 David Sommerseth + *. © 2002-2010 Jean Delvare *. © 2000-2002 Alan Cox *. *. This file is part of Python DMI-Decode. @@ -44,17 +44,17 @@ * DMI Decode * * Unless specified otherwise, all references are aimed at the "System - * Management BIOS Reference Specification, Version 2.6" document, - * available from http://www.dmtf.org/standards/smbios/. + * Management BIOS Reference Specification, Version 2.8.0" document, + * available from http://www.dmtf.org/standards/smbios. * * Note to contributors: * Please reference every value you add or modify, especially if the * information does not come from the above mentioned specification. * * Additional references: - * - Intel AP-485 revision 32 + * - Intel AP-485 revision 36 * "Intel Processor Identification and the CPUID Instruction" - * http://developer.intel.com/design/xeon/applnots/241618.htm + * http://www.intel.com/support/processors/sb/cs-009861.htm * - DMTF Common Information Model * CIM Schema version 2.19.1 * http://www.dmtf.org/standards/cim/ @@ -65,6 +65,9 @@ * "CPUID Specification" * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf * - BIOS Integrity Services Application Programming Interface version 1.0 + * - DMTF DSP0239 version 1.1.0 + * "Management Component Transport Protocol (MCTP) IDs and Codes" + * http://www.dmtf.org/standards/pmci * http://www.intel.com/design/archives/wfm/downloads/bisspec.htm * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * @@ -76,23 +79,38 @@ #include #include #include +#include #include "version.h" #include "config.h" #include "types.h" #include "util.h" -#include "dmixml.h" #include "dmidecode.h" +#include "dmixml.h" #include "dmioem.h" #include "efi.h" #include "dmidump.h" - #include "dmihelper.h" +#define SUPPORTED_SMBIOS_VER 0x030300 +#define OUT_OF_SPEC "outofspec" + /******************************************************************************* ** Type-independant Stuff */ +/* Returns 1 if the buffer contains only printable ASCII characters */ +int is_printable(const u8 *data, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (data[i] < 32 || data[i] >= 127) + return 0; + + return 1; +} + const char *dmi_string(const struct dmi_header *dm, u8 s) { char *bp = (char *)dm->data; @@ -168,12 +186,16 @@ xmlNode *dmi_smbios_structure_type(xmlNode *node, u8 code) {"Management Device Threshold Data","ManagementDevice", "type", "Threshold Data"}, {"Memory Channel", "MemoryChannel", NULL, NULL}, {"IPMI Device", "IPMIdevice", NULL, NULL}, - {"Power Supply", "PowerSupply", NULL, NULL} /* 39 */ + {"Power Supply", "PowerSupply", NULL, NULL}, /* 39 */ + {"Additional Information", "AdditionalInfo", NULL, NULL}, + {"Onboard Device", "OnboardDevice", NULL, NULL}, /* 41 */ + {"Management Controller Host Interface", "MgmntCtrltHostIntf", NULL, NULL}, /* 42 */ + {"TPM Device", "TPMDevice", NULL, NULL}, /* 43 */ /* *INDENT-ON* */ }; xmlNode *type_n = NULL; - if(code <= 39) { + if(code <= 43) { type_n = xmlNewChild(node, NULL, (xmlChar *)types[code].tagname, NULL); assert( type_n != NULL ); @@ -183,6 +205,10 @@ xmlNode *dmi_smbios_structure_type(xmlNode *node, u8 code) if( (types[code].attrname != NULL) && (types[code].attrvalue != NULL) ) { dmixml_AddAttribute(type_n, types[code].attrname, "%s", types[code].attrvalue); } + } else if (code >= 128) { + type_n = xmlNewChild(node, NULL, (xmlChar *)"OEMspecific", NULL); + assert( type_n != NULL ); + dmixml_AddAttribute(type_n, "flags", "0x%04x", code); } else { type_n = xmlNewChild(node, NULL, (xmlChar *) "UnknownSMBiosType", NULL); dmixml_AddAttribute(type_n, "flags", "0x%04x", code); @@ -214,7 +240,7 @@ void dmi_dump(xmlNode *node, struct dmi_header * h) for(row = 0; row < ((h->length - 1) >> 4) + 1; row++) { memset(tmp_s, 0, (h->length * 2) + 2); - for(i = 0; i < (16 && i < h->length - (row << 4)); i++) { + for(i = 0; i < 16 && (i < h->length - (row << 4)); i++) { snprintf(tmp_s + strlen(tmp_s), (h->length * 2)-strlen(tmp_s), "0x%02x", (h->data)[(row << 4) + i]); } @@ -254,8 +280,53 @@ void dmi_dump(xmlNode *node, struct dmi_header * h) dump_n = NULL; } + +/* shift is 0 if the value is in bytes, 1 if it is in kilobytes */ +static void dmi_add_memory_size(xmlNode *node, u64 code, int shift) +{ + unsigned long capacity; + u16 split[7]; + static const char *unit[8] = { + "bytes", "kB", "MB", "GB", "TB", "PB", "EB", "ZB" + }; + int i; + + /* + * We split the overall size in powers of thousand: EB, PB, TB, GB, + * MB, kB and B. In practice, it is expected that only one or two + * (consecutive) of these will be non-zero. + */ + split[0] = code.l & 0x3FFUL; + split[1] = (code.l >> 10) & 0x3FFUL; + split[2] = (code.l >> 20) & 0x3FFUL; + split[3] = ((code.h << 2) & 0x3FCUL) | (code.l >> 30); + split[4] = (code.h >> 8) & 0x3FFUL; + split[5] = (code.h >> 18) & 0x3FFUL; + split[6] = code.h >> 28; + + /* + * Now we find the highest unit with a non-zero value. If the following + * is also non-zero, we use that as our base. If the following is zero, + * we simply display the highest unit. + */ + for (i = 6; i > 0; i--) { + if (split[i]) + break; + } + if (i > 0 && split[i - 1]) { + i--; + capacity = split[i] + (split[i + 1] << 10); + } else { + capacity = split[i]; + } + + dmixml_AddAttribute(node, "unit", unit[i + shift]); + dmixml_AddTextContent(node, "%lu", capacity); +} + + /******************************************************************************* -** 3.3.1 BIOS Information (Type 0) +** 7.1 BIOS Information (Type 0) */ void dmi_bios_runtime_size(xmlNode *node, u32 code) @@ -273,7 +344,31 @@ void dmi_bios_runtime_size(xmlNode *node, u32 code) } } -/* 3.3.1.1 */ +void dmi_bios_rom_size(xmlNode *node, u8 code1, u16 code2) +{ + static const char *unit[4] = { + "MB", "GB" + }; + + xmlNode *brz_n = xmlNewChild(node, NULL, (xmlChar *)"ROMSize", NULL); + dmixml_AddAttribute(brz_n, "flags", "0x%04x", code1); + + if (code1 != 0xFF) + { + u64 s = { .l = (code1 + 1) << 6}; + dmi_add_memory_size(brz_n, s, 1); + }else{ + if ( (code2 >> 14) <= 0x02 ){ + dmixml_AddAttribute(brz_n, "unit", unit[code2 >> 14]); + dmixml_AddTextContent(brz_n, "%i", code2 & 0x3FFF); + }else{ + dmixml_AddAttribute(brz_n, OUT_OF_SPEC, "1"); + } + + } +} + +/* 7.1.1 */ void dmi_bios_characteristics(xmlNode *node, u64 code) { static const char *characteristics[] = { @@ -296,9 +391,9 @@ void dmi_bios_characteristics(xmlNode *node, u64 code) "EDD is supported", "Japanese floppy for NEC 9800 1.2 MB is supported (int 13h)", "Japanese floppy for Toshiba 1.2 MB is supported (int 13h)", - "5.25\"/360 KB floppy services are supported (int 13h)", + "5.25\"/360 kB floppy services are supported (int 13h)", "5.25\"/1.2 MB floppy services are supported (int 13h)", - "3.5\"/720 KB floppy services are supported (int 13h)", + "3.5\"/720 kB floppy services are supported (int 13h)", "3.5\"/2.88 MB floppy services are supported (int 13h)", "Print screen service is supported (int 5h)", "8042 keyboard services are supported (int 9h)", @@ -307,7 +402,7 @@ void dmi_bios_characteristics(xmlNode *node, u64 code) "CGA/mono video services are supported (int 10h)", "NEC PC-98" /* 31 */ }; - dmixml_AddAttribute(node, "dmispec", "3.3.1.1"); + dmixml_AddAttribute(node, "dmispec", "7.1.1"); dmixml_AddAttribute(node, "flags", "0x%04x", code); if(code.l&(1<<3)) { @@ -325,7 +420,7 @@ void dmi_bios_characteristics(xmlNode *node, u64 code) } } -/* 3.3.1.2.1 */ +/* 7.1.2.1 */ void dmi_bios_characteristics_x1(xmlNode *node, u8 code) { int i = 0; @@ -340,7 +435,7 @@ void dmi_bios_characteristics_x1(xmlNode *node, u8 code) "Smart battery" /* 7 */ }; - dmixml_AddAttribute(node, "dmispec", "3.3.1.2.1"); + dmixml_AddAttribute(node, "dmispec", "7.1.2.1"); dmixml_AddAttribute(node, "flags", "0x%04x", code); for(i = 0; i <= 7; i++) { @@ -349,27 +444,29 @@ void dmi_bios_characteristics_x1(xmlNode *node, u8 code) } } -/* 3.3.1.2.2 */ +/* 7.1.2.2 */ void dmi_bios_characteristics_x2(xmlNode *node, u8 code) { int i = 0; static const char *characteristics[] = { "BIOS boot specification", /* 0 */ "Function key-initiated network boot", - "Targeted content distribution" /* 2 */ + "Targeted content distribution", /* 2 */ + "UEFI is supported", + "System is a virtual machine" /* 4 */ }; - dmixml_AddAttribute(node, "dmispec", "3.3.1.2.2"); + dmixml_AddAttribute(node, "dmispec", "7.1.2.2"); dmixml_AddAttribute(node, "flags", "0x%04x", code); - for(i = 0; i <= 2; i++) { + for(i = 0; i <= 4; i++) { xmlNode *chr_n = dmixml_AddTextChild(node, "characteristic", characteristics[i]); dmixml_AddAttribute(chr_n, "enabled", "%i", (code & (1 << i) ? 1: 0)); } } /******************************************************************************* -** 3.3.2 System Information (Type 1) +** 7.2 System Information (Type 1) */ void dmi_system_uuid(xmlNode *node, const u8 * p, u16 ver) @@ -386,9 +483,9 @@ void dmi_system_uuid(xmlNode *node, const u8 * p, u16 ver) } uuid_n = xmlNewChild(node, NULL, (xmlChar *) "SystemUUID", NULL); - dmixml_AddAttribute(uuid_n, "dmispec", "3.3.2"); + dmixml_AddAttribute(uuid_n, "dmispec", "7.2"); - if(only0xFF ) { + if(only0xFF) { dmixml_AddAttribute(uuid_n, "unavailable", "1"); dmixml_AddTextContent(uuid_n, "Not Present"); return; @@ -401,7 +498,7 @@ void dmi_system_uuid(xmlNode *node, const u8 * p, u16 ver) } /* - * As off version 2.6 of the SMBIOS specification, the first 3 + * As of version 2.6 of the SMBIOS specification, the first 3 * fields of the UUID are supposed to be encoded on little-endian. * The specification says that this is the defacto standard, * however I've seen systems following RFC 4122 instead and use @@ -421,7 +518,7 @@ void dmi_system_uuid(xmlNode *node, const u8 * p, u16 ver) } } -/* 3.3.2.1 */ +/* 7.2.2 */ void dmi_system_wake_up_type(xmlNode *node, u8 code) { static const char *type[] = { @@ -437,21 +534,21 @@ void dmi_system_wake_up_type(xmlNode *node, u8 code) }; xmlNode *swut_n = xmlNewChild(node, NULL, (xmlChar *) "SystemWakeUpType", NULL); assert( swut_n != NULL ); - dmixml_AddAttribute(swut_n, "dmispec", "3.3.2.1"); + dmixml_AddAttribute(swut_n, "dmispec", "7.2.2"); dmixml_AddAttribute(swut_n, "flags", "0x%04x", code); if(code <= 0x08) { dmixml_AddTextContent(swut_n, type[code]); } else { - dmixml_AddAttribute(swut_n, "outofspec", "1"); + dmixml_AddAttribute(swut_n, OUT_OF_SPEC, "1"); } } /******************************************************************************* -** 3.3.3 Base Board Information (Type 2) +** 7.3 Base Board Information (Type 2) */ -/* 3.3.3.1 */ +/* 7.3.1 */ void dmi_base_board_features(xmlNode *node, u8 code) { static const char *features[] = { @@ -464,7 +561,7 @@ void dmi_base_board_features(xmlNode *node, u8 code) xmlNode *feat_n = xmlNewChild(node, NULL, (xmlChar *) "Features", NULL); assert( feat_n != NULL ); - dmixml_AddAttribute(feat_n, "dmispec", "3.3.3.1"); + dmixml_AddAttribute(feat_n, "dmispec", "7.3.1"); dmixml_AddAttribute(feat_n, "flags", "0x%04x", code); if((code & 0x1F) != 0) { @@ -482,7 +579,7 @@ void dmi_base_board_features(xmlNode *node, u8 code) void dmi_base_board_type(xmlNode *node, const char *tagname, u8 code) { - /* 3.3.3.2 */ + /* 7.3.2 */ static const char *type[] = { "Unknown", /* 0x01 */ "Other", @@ -500,7 +597,7 @@ void dmi_base_board_type(xmlNode *node, const char *tagname, u8 code) }; xmlNode *type_n = xmlNewChild(node, NULL, (xmlChar *) tagname, NULL); assert( type_n != NULL ); - dmixml_AddAttribute(type_n, "dmispec", "3.3.3.2"); + dmixml_AddAttribute(type_n, "dmispec", "7.3.2"); dmixml_AddAttribute(type_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x0D) { @@ -528,10 +625,10 @@ void dmi_base_board_handles(xmlNode *node, u8 count, const u8 * p) } /******************************************************************************* -** 3.3.4 Chassis Information (Type 3) +** 7.4 Chassis Information (Type 3) */ -/* 3.3.4.1 */ +/* 7.4.1 */ void dmi_chassis_type(xmlNode *node, u8 code) { static const char *type[] = { @@ -563,14 +660,23 @@ void dmi_chassis_type(xmlNode *node, u8 code) "CompactPCI", "AdvancedTCA", /* 0x1B */ "Blade", - "Blade Enclosing" /* 0x1D */ + "Blade Enclosing", /* 0x1D */ + "Tablet", + "Convertible", + "Detachable", + "IoT Gateway", + "Embedded PC", + "Mini PC", + "Stick PC" /* 0x24 */ }; xmlNode *type_n = xmlNewChild(node, NULL, (xmlChar *)"ChassisType", NULL); assert( type_n != NULL ); - dmixml_AddAttribute(type_n, "dmispec", "3.3.4.1"); + dmixml_AddAttribute(type_n, "dmispec", "7.4.1"); dmixml_AddAttribute(type_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x1B) { + code &= 0x7F; /* bits 6:0 are chassis type, 7th bit is the lock bit */ + + if(code >= 0x01 && code <= 0x24) { dmixml_AddAttribute(type_n, "available", "1"); dmixml_AddTextContent(type_n, "%s", type[code - 0x01]); } else { @@ -586,25 +692,25 @@ void dmi_chassis_lock(xmlNode *node, u8 code) }; xmlNode *lock_n = xmlNewChild(node, NULL, (xmlChar *) "ChassisLock", NULL); assert( lock_n != NULL ); - dmixml_AddAttribute(lock_n, "dmispec", "3.3.4"); + dmixml_AddAttribute(lock_n, "dmispec", "7.4.1"); dmixml_AddAttribute(lock_n, "flags", "0x%04x", code); dmixml_AddTextContent(lock_n, "%s", lock[code]); } -/* 3.3.4.2 */ +/* 7.4.2 */ void dmi_chassis_state(xmlNode *node, const char *tagname, u8 code) { static const char *state[] = { "Other", /* 0x01 */ "Unknown", - "Safe", /* master.mif says OK */ + "Safe", "Warning", "Critical", "Non-recoverable" /* 0x06 */ }; xmlNode *state_n = xmlNewChild(node, NULL, (xmlChar *) tagname, NULL); assert( state_n != NULL ); - dmixml_AddAttribute(state_n, "dmispec", "3.3.4.2"); + dmixml_AddAttribute(state_n, "dmispec", "7.4.2"); dmixml_AddAttribute(state_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x06) { @@ -614,7 +720,7 @@ void dmi_chassis_state(xmlNode *node, const char *tagname, u8 code) } } -/* 3.3.4.3 */ +/* 7.4.3 */ void dmi_chassis_security_status(xmlNode *node, u8 code) { static const char *status[] = { @@ -626,13 +732,13 @@ void dmi_chassis_security_status(xmlNode *node, u8 code) }; xmlNode *secstat_n = xmlNewChild(node, NULL, (xmlChar *) "SecurityStatus", NULL); assert( secstat_n != NULL ); - dmixml_AddAttribute(secstat_n, "dmispec", "3.3.4.3"); + dmixml_AddAttribute(secstat_n, "dmispec", "7.4.3"); dmixml_AddAttribute(secstat_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x05) { dmixml_AddTextContent(secstat_n, "%s", status[code - 0x01]); } else { - dmixml_AddAttribute(secstat_n, "unavailable", "1"); + dmixml_AddAttribute(secstat_n, OUT_OF_SPEC, "1"); } } @@ -642,7 +748,7 @@ void dmi_chassis_height(xmlNode *node, u8 code) assert( hght_n != NULL ); if(code == 0x00) { - dmixml_AddAttribute(hght_n, "unspecified", "1"); + dmixml_AddAttribute(hght_n, OUT_OF_SPEC, "1"); } else { dmixml_AddAttribute(hght_n, "unit", "U"); dmixml_AddTextContent(hght_n, "%i", code); @@ -655,7 +761,7 @@ void dmi_chassis_power_cords(xmlNode *node, u8 code) assert( pwrc_n != NULL ); if(code == 0x00) { - dmixml_AddAttribute(pwrc_n, "unspecified", "1"); + dmixml_AddAttribute(pwrc_n, OUT_OF_SPEC, "1"); } else { dmixml_AddTextContent(pwrc_n, "%i", code); } @@ -691,12 +797,12 @@ void dmi_chassis_elements(xmlNode *node, u8 count, u8 len, const u8 * p) } /******************************************************************************* -** 3.3.5 Processor Information (Type 4) +** 7.5 Processor Information (Type 4) */ void dmi_processor_type(xmlNode *node, u8 code) { - /* 3.3.5.1 */ + /* 7.5.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -712,17 +818,17 @@ void dmi_processor_type(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x06) { dmixml_AddTextContent(proct_n, type[code - 0x01]); } else { - dmixml_AddAttribute(proct_n, "outofspec", "1"); + dmixml_AddAttribute(proct_n, OUT_OF_SPEC, "1"); } } -void dmi_processor_family(xmlNode *node, const struct dmi_header *h) +void dmi_processor_family(xmlNode *node, const struct dmi_header *h, u16 ver) { const u8 *data = h->data; unsigned int i, low, high; u16 code; - /* 3.3.5.2 */ + /* 7.5.2 */ static struct { int value; const char *name; @@ -747,8 +853,8 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) { 0x11, "Pentium III" }, { 0x12, "M1" }, { 0x13, "M2" }, - { 0x14, "Celeron M" }, /* From CIM_Processor.Family */ - { 0x15, "Pentium 4 HT" }, /* From CIM_Processor.Family */ + { 0x14, "Celeron M" }, + { 0x15, "Pentium 4 HT" }, { 0x18, "Duron" }, { 0x19, "K5" }, @@ -766,10 +872,14 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) { 0x25, "Power PC 620" }, { 0x26, "Power PC x704" }, { 0x27, "Power PC 750" }, - { 0x28, "Core Duo" }, /* From CIM_Processor.Family */ - { 0x29, "Core Duo Mobile" }, /* From CIM_Processor.Family */ - { 0x2A, "Core Solo Mobile" }, /* From CIM_Processor.Family */ - { 0x2B, "Atom" }, /* From CIM_Processor.Family */ + { 0x28, "Core Duo" }, + { 0x29, "Core Duo Mobile" }, + { 0x2A, "Core Solo Mobile" }, + { 0x2B, "Atom" }, + { 0x2C, "Core M" }, + { 0x2D, "Core m3" }, + { 0x2E, "Core m5" }, + { 0x2F, "Core m7" }, { 0x30, "Alpha" }, { 0x31, "Alpha 21064" }, @@ -779,6 +889,14 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) { 0x35, "Alpha 21164a" }, { 0x36, "Alpha 21264" }, { 0x37, "Alpha 21364" }, + { 0x38, "Turion II Ultra Dual-Core Mobile M" }, + { 0x39, "Turion II Dual-Core Mobile M" }, + { 0x3A, "Athlon II Dual-Core M" }, + { 0x3B, "Opteron 6100" }, + { 0x3C, "Opteron 4100" }, + { 0x3D, "Opteron 6200" }, + { 0x3E, "Opteron 4200" }, + { 0x3F, "FX" }, { 0x40, "MIPS" }, { 0x41, "MIPS R4000" }, @@ -786,6 +904,16 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) { 0x43, "MIPS R4400" }, { 0x44, "MIPS R4600" }, { 0x45, "MIPS R10000" }, + { 0x46, "C-Series" }, + { 0x47, "E-Series" }, + { 0x48, "A-Series" }, + { 0x49, "G-Series" }, + { 0x4A, "Z-Series" }, + { 0x4B, "R-Series" }, + { 0x4C, "Opteron 4300" }, + { 0x4D, "Opteron 6300" }, + { 0x4E, "Opteron 3300" }, + { 0x4F, "FirePro" }, { 0x50, "SPARC" }, { 0x51, "SuperSPARC" }, @@ -803,6 +931,12 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) { 0x63, "68010" }, { 0x64, "68020" }, { 0x65, "68030" }, + { 0x66, "Athlon X4" }, + { 0x67, "Opteron X1000" }, + { 0x68, "Opteron X2000" }, + { 0x69, "Opteron A-Series" }, + { 0x6A, "Opteron X3000" }, + { 0x6B, "Zen" }, { 0x70, "Hobbit" }, @@ -820,12 +954,12 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) { 0x87, "Dual-Core Opteron" }, { 0x88, "Athlon 64 X2" }, { 0x89, "Turion 64 X2" }, - { 0x8A, "Quad-Core Opteron" }, /* From CIM_Processor.Family */ - { 0x8B, "Third-Generation Opteron" }, /* From CIM_Processor.Family */ - { 0x8C, "Phenom FX" }, /* From CIM_Processor.Family */ - { 0x8D, "Phenom X4" }, /* From CIM_Processor.Family */ - { 0x8E, "Phenom X2" }, /* From CIM_Processor.Family */ - { 0x8F, "Athlon X2" }, /* From CIM_Processor.Family */ + { 0x8A, "Quad-Core Opteron" }, + { 0x8B, "Third-Generation Opteron" }, + { 0x8C, "Phenom FX" }, + { 0x8D, "Phenom X4" }, + { 0x8E, "Phenom X2" }, + { 0x8F, "Athlon X2" }, { 0x90, "PA-RISC" }, { 0x91, "PA-RISC 8500" }, { 0x92, "PA-RISC 8000" }, @@ -835,17 +969,21 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) { 0x96, "PA-RISC 7100" }, { 0xA0, "V30" }, - { 0xA1, "Quad-Core Xeon 3200" }, /* From CIM_Processor.Family */ - { 0xA2, "Dual-Core Xeon 3000" }, /* From CIM_Processor.Family */ - { 0xA3, "Quad-Core Xeon 5300" }, /* From CIM_Processor.Family */ - { 0xA4, "Dual-Core Xeon 5100" }, /* From CIM_Processor.Family */ - { 0xA5, "Dual-Core Xeon 5000" }, /* From CIM_Processor.Family */ - { 0xA6, "Dual-Core Xeon LV" }, /* From CIM_Processor.Family */ - { 0xA7, "Dual-Core Xeon ULV" }, /* From CIM_Processor.Family */ - { 0xA8, "Dual-Core Xeon 7100" }, /* From CIM_Processor.Family */ - { 0xA9, "Quad-Core Xeon 5400" }, /* From CIM_Processor.Family */ - { 0xAA, "Quad-Core Xeon" }, /* From CIM_Processor.Family */ - + { 0xA1, "Quad-Core Xeon 3200" }, + { 0xA2, "Dual-Core Xeon 3000" }, + { 0xA3, "Quad-Core Xeon 5300" }, + { 0xA4, "Dual-Core Xeon 5100" }, + { 0xA5, "Dual-Core Xeon 5000" }, + { 0xA6, "Dual-Core Xeon LV" }, + { 0xA7, "Dual-Core Xeon ULV" }, + { 0xA8, "Dual-Core Xeon 7100" }, + { 0xA9, "Quad-Core Xeon 5400" }, + { 0xAA, "Quad-Core Xeon" }, + { 0xAB, "Dual-Core Xeon 5200" }, + { 0xAC, "Dual-Core Xeon 7200" }, + { 0xAD, "Quad-Core Xeon 7300" }, + { 0xAE, "Quad-Core Xeon 7400" }, + { 0xAF, "Multi-Core Xeon 7400" }, { 0xB0, "Pentium III Xeon" }, { 0xB1, "Pentium III Speedstep" }, { 0xB2, "Pentium 4" }, @@ -862,27 +1000,57 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) { 0xBD, "Core Solo" }, /* 0xBE handled as a special case */ { 0xBF, "Core 2 Duo" }, - { 0xC0, "Core 2 Solo" }, /* From CIM_Processor.Family */ - { 0xC1, "Core 2 Extreme" }, /* From CIM_Processor.Family */ - { 0xC2, "Core 2 Quad" }, /* From CIM_Processor.Family */ - { 0xC3, "Core 2 Extreme Mobile" }, /* From CIM_Processor.Family */ - { 0xC4, "Core 2 Duo Mobile" }, /* From CIM_Processor.Family */ - { 0xC5, "Core 2 Solo Mobile" }, /* From CIM_Processor.Family */ - + { 0xC0, "Core 2 Solo" }, + { 0xC1, "Core 2 Extreme" }, + { 0xC2, "Core 2 Quad" }, + { 0xC3, "Core 2 Extreme Mobile" }, + { 0xC4, "Core 2 Duo Mobile" }, + { 0xC5, "Core 2 Solo Mobile" }, + { 0xC6, "Core i7" }, + { 0xC7, "Dual-Core Celeron" }, { 0xC8, "IBM390" }, { 0xC9, "G4" }, { 0xCA, "G5" }, { 0xCB, "ESA/390 G6" }, { 0xCC, "z/Architectur" }, + { 0xCD, "Core i5" }, + { 0xCE, "Core i3" }, { 0xD2, "C7-M" }, { 0xD3, "C7-D" }, { 0xD4, "C7" }, { 0xD5, "Eden" }, + { 0xD6, "Multi-Core Xeon" }, + { 0xD7, "Dual-Core Xeon 3xxx" }, + { 0xD8, "Quad-Core Xeon 3xxx" }, + { 0xD9, "Nano" }, + { 0xDA, "Dual-Core Xeon 5xxx" }, + { 0xDB, "Quad-Core Xeon 5xxx" }, + + { 0xDD, "Dual-Core Xeon 7xxx" }, + { 0xDE, "Quad-Core Xeon 7xxx" }, + { 0xDF, "Multi-Core Xeon 7xxx" }, + { 0xE0, "Multi-Core Xeon 3400" }, + + { 0xE4, "Opteron 3000" }, + { 0xE5, "Sempron II" }, + { 0xE6, "Embedded Opteron Quad-Core" }, + { 0xE7, "Phenom Triple-Core" }, + { 0xE8, "Turion Ultra Dual-Core Mobile" }, + { 0xE9, "Turion Dual-Core Mobile" }, + { 0xEA, "Athlon Dual-Core" }, + { 0xEB, "Sempron SI" }, + { 0xEC, "Phenom II" }, + { 0xED, "Athlon II" }, + { 0xEE, "Six-Core Opteron" }, + { 0xEF, "Sempron M" }, + { 0xFA, "i860" }, { 0xFB, "i960" }, + { 0x100, "ARMv7" }, + { 0x101, "ARMv8" }, { 0x104, "SH-3" }, { 0x105, "SH-4" }, @@ -898,6 +1066,9 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) { 0x15E, "DSP" }, { 0x1F4, "Video Processor" }, + { 0x200, "RV32" }, + { 0x201, "RV64" }, + { 0x202, "RV128" } /* *INDENT-ON* */ }; @@ -909,7 +1080,18 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) xmlNode *family_n = xmlNewChild(node, NULL, (xmlChar *) "Family", NULL); assert( family_n != NULL ); - dmixml_AddAttribute(family_n, "dmispec", "3.3.3.5"); + dmixml_AddAttribute(family_n, "dmispec", "7.5.2"); + + /* Special case for ambiguous value 0x30 (SMBIOS 2.0 only) */ + if (ver == 0x0200 && data[0x06] == 0x30 && h->length >= 0x08) { + const char *manufacturer = dmi_string(h, data[0x07]); + + if (strstr(manufacturer, "Intel") != NULL + || strncasecmp(manufacturer, "Intel", 5) == 0) { + dmixml_AddTextContent(family_n, "Pentium Pro"); + return; + } + } code = (data[0x06] == 0xFE && h->length >= 0x2A) ? WORD(data + 0x28) : data[0x06]; @@ -919,6 +1101,11 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) if(code == 0xBE) { const char *manufacturer = dmi_string(h, data[0x07]); + if( manufacturer == NULL ) { + dmixml_AddTextContent(family_n, "Core 2 or K7 (Unknown manufacturer)"); + return; + } + /* Best bet based on manufacturer string */ if(strstr(manufacturer, "Intel") != NULL || strncasecmp(manufacturer, "Intel", 5) == 0) { @@ -931,7 +1118,7 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) dmixml_AddTextContent(family_n, "K7"); return; } - dmixml_AddTextContent(family_n, "Core 2 or K7"); + dmixml_AddTextContent(family_n, "Core 2 or K7 (Unknown manufacturer)"); return; } @@ -946,7 +1133,7 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) } if(low == high) { /* Not found */ - dmixml_AddAttribute(family_n, "outofspec", "1"); + dmixml_AddAttribute(family_n, OUT_OF_SPEC, "1"); return; } @@ -956,12 +1143,12 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h) low = i + 1; } - dmixml_AddAttribute(family_n, "outofspec", "1"); + dmixml_AddAttribute(family_n, OUT_OF_SPEC, "1"); } -xmlNode *dmi_processor_id(xmlNode *node, u8 type, const u8 * p, const char *version) +xmlNode *dmi_processor_id(xmlNode *node, const struct dmi_header *h) { - /* Intel AP-485 revision 31, table 3-4 */ + /* Intel AP-485 revision 36, table 2-4 */ static struct _cpuflags { const char *flag; const char *descr; @@ -991,21 +1178,28 @@ xmlNode *dmi_processor_id(xmlNode *node, u8 type, const u8 * p, const char *vers {"DS", "DS (Debug store)"}, {"ACPI", "ACPI (ACPI supported)"}, {"MMX", "MMX (MMX technology supported)"}, - {"FXSR", "FXSR (Fast floating-point save and restore)"}, + {"FXSR", "FXSR (FXSAVE and FXSTOR instructions supported)"}, {"SSE", "SSE (Streaming SIMD extensions)"}, {"SSE2", "SSE2 (Streaming SIMD extensions 2)"}, {"SS", "SS (Self-snoop)"}, - {"HTT", "HTT (Hyper-threading technology)"}, + {"HTT", "HTT (Multi-threading)"}, {"TM", "TM (Thermal monitor supported)"}, - {"IA64", "IA64 (IA64 capabilities)"}, + {NULL, NULL}, {"PBE", "PBE (Pending break enabled)"} /* 31 */ /* *INDENT-ON* */ }; + u8 type, *p = NULL; + char *version = NULL; xmlNode *flags_n = NULL; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "CPUCore", NULL); assert( data_n != NULL ); + assert( h && h->data ); + type = (h->data[0x06] == 0xFE && h->length >=0x2A) ? WORD(h->data+0x28) : h->data[0x06]; + p = h->data + 8; + version = (char *) dmi_string(h, h->data[0x10]); + /* ** Extra flags are now returned in the ECX register when one calls ** the CPUID instruction. Their meaning is explained in table 3-5, but @@ -1019,7 +1213,6 @@ xmlNode *dmi_processor_id(xmlNode *node, u8 type, const u8 * p, const char *vers ** CPUID instruction or another form of identification. */ - //. TODO: PyString_FromFormat does not support %x (yet?)... dmixml_AddTextChild(data_n, "ID", "%02x %02x %02x %02x %02x %02x %02x %02x", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); @@ -1055,27 +1248,45 @@ xmlNode *dmi_processor_id(xmlNode *node, u8 type, const u8 * p, const char *vers dx & 0xF); return data_n; } - } else if((type >= 0x0B && type <= 0x15) /* Intel, Cyrix */ + } else if ( (type >= 0x100 && type <= 0x101) /* ARM */ + || (type >= 0x118 && type <= 0x119)) /* ARM */ + { + u32 midr = DWORD(p); + /* + * The format of this field was not defined for ARM processors + * before version 3.1.0 of the SMBIOS specification, so we + * silently skip it if it reads all zeroes. + */ + if (midr == 0) + return data_n; + dmixml_AddTextChild(data_n, "Signature", + "Implementor 0x%02x, Variant 0x%x, Architecture %i, Part 0x%03x, Revision %i", + midr >> 24, (midr >> 20) & 0xF, (midr >> 16) & 0xF, (midr >> 4) & 0xFFF, midr & 0xF); + return data_n; + } else if( (type >= 0x0B && type <= 0x15) /* Intel, Cyrix */ ||(type >= 0x28 && type <= 0x2B) /* Intel */ - ||(type >= 0xA1 && type <= 0xAA) /* Intel */ - ||(type >= 0xB0 && type <= 0xB3) /* Intel */ - ||type == 0xB5 /* Intel */ - || (type >= 0xB9 && type <= 0xC5) /* Intel */ - ||(type >= 0xD2 && type <= 0xD5) /* VIA */ + ||(type >= 0xA1 && type <= 0xB3) /* Intel */ + ||type == 0xB5 /* Intel */ + ||(type >= 0xB9 && type <= 0xC7) /* Intel */ + ||(type >= 0xCD && type <= 0xCE) /* Intel */ + ||(type >= 0xD2 && type <= 0xDB) /* VIA, Intel */ + ||(type >= 0xDD && type <= 0xE0) /* Intel */ ) { sig = 1; - - } else if((type >= 0x18 && type <= 0x1D) /* AMD */ - ||type == 0x1F /* AMD */ - || (type >= 0x83 && type <= 0x8F) /* AMD */ + } else if((type >= 0x18 && type <= 0x1D) /* AMD */ + ||type == 0x1F /* AMD */ + ||(type >= 0x38 && type <= 0x3F) /* AMD */ + ||(type >= 0x46 && type <= 0x4F) /* AMD */ + ||(type >= 0x66 && type <= 0x6B) /* AMD */ + ||(type >= 0x83 && type <= 0x8F) /* AMD */ ||(type >= 0xB6 && type <= 0xB7) /* AMD */ - ||(type >= 0xE6 && type <= 0xEB) /* AMD */ + ||(type >= 0xE6 && type <= 0xEF) /* AMD */ ) { sig = 2; - } else if(type == 0x01 || type == 0x02) { + } else if(version && (type == 0x01 || type == 0x02)) { /* ** Some X86-class CPU have family "Other" or "Unknown". In this case, ** we use the version string to determine if they are known to @@ -1102,14 +1313,21 @@ xmlNode *dmi_processor_id(xmlNode *node, u8 type, const u8 * p, const char *vers return data_n; } + /* + * Extra flags are now returned in the ECX register when one calls + * the CPUID instruction. Their meaning is explained in table 3-5, but + * DMI doesn't support this yet. + */ eax = DWORD(p); edx = DWORD(p + 4); switch (sig) { case 1: /* Intel */ dmixml_AddTextChild(data_n, "Signature", "Type %i, Family %i, Model %i, Stepping %i", - (eax >> 12) & 0x3, ((eax >> 20) & 0xFF) + ((eax >> 8) & 0x0F), - ((eax >> 12) & 0xF0) + ((eax >> 4) & 0x0F), eax & 0xF); + (eax >> 12) & 0x3, + ((eax >> 20) & 0xFF) + ((eax >> 8) & 0x0F), + ((eax >> 12) & 0xF0) + ((eax >> 4) & 0x0F), + eax & 0xF); break; case 2: /* AMD, publication #25481 revision 2.28 */ dmixml_AddTextChild(data_n, "Signature", @@ -1124,7 +1342,7 @@ xmlNode *dmi_processor_id(xmlNode *node, u8 type, const u8 * p, const char *vers edx = DWORD(p + 4); flags_n = xmlNewChild(data_n, NULL, (xmlChar *) "cpu_flags", NULL); - if((edx & 0xFFEFFBFF) != 0) { + if((edx & 0xBFEFFBFF) != 0) { int i; for(i = 0; i <= 31; i++) { @@ -1139,7 +1357,7 @@ xmlNode *dmi_processor_id(xmlNode *node, u8 type, const u8 * p, const char *vers return data_n; } -/* 3.3.5.4 */ +/* 7.5.4 */ void dmi_processor_voltage(xmlNode *node, u8 code) { static const char *voltage[] = { @@ -1150,13 +1368,13 @@ void dmi_processor_voltage(xmlNode *node, u8 code) int i; xmlNode *vltg_n = xmlNewChild(node, NULL, (xmlChar *) "Voltages", NULL); assert( vltg_n != NULL ); - dmixml_AddAttribute(vltg_n, "dmispec", "3.3.5.4"); + dmixml_AddAttribute(vltg_n, "dmispec", "7.5.4"); dmixml_AddAttribute(vltg_n, "flags", "0x%04x", code); if(code & 0x80) { xmlNode *v_n = dmixml_AddTextChild(vltg_n, "Voltage", "%.1f", (float)(code & 0x7f) / 10); dmixml_AddAttribute(v_n, "unit", "V"); - } else if( code == 0x00 ) { + } else if( (code & 0x07 ) == 0x00 ) { dmixml_AddAttribute(vltg_n, "unknown_value", "1"); } else { for(i = 0; i <= 2; i++) { @@ -1199,13 +1417,13 @@ void dmi_processor_status(xmlNode *node, u8 code) } else if( code == 0x07 ) { dmixml_AddTextContent(prst_n, "%s", status[5]); } else { - dmixml_AddAttribute(prst_n, "outofspec", "1"); + dmixml_AddAttribute(prst_n, OUT_OF_SPEC, "1"); } } void dmi_processor_upgrade(xmlNode *node, u8 code) { - /* 3.3.5.5 */ + /* 7.5.5 */ static const char *upgrade[] = { "Other", /* 0x01 */ "Unknown", @@ -1230,17 +1448,53 @@ void dmi_processor_upgrade(xmlNode *node, u8 code) "Socket LGA775", /* 0x15 */ "Socket S1", "Socket AM2", - "Socket F (1207)" /* 0x18 */ + "Socket F (1207)", /* 0x18 */ + "Socket LGA1366", + "Socket G34", + "Socket AM3", + "Socket C32", + "Socket LGA1156", + "Socket LGA1567", + "Socket PGA988A", + "Socket BGA1288", /* 0x20 */ + "Socket rPGA988B", + "Socket BGA1023", + "Socket BGA1224", + "Socket BGA1155", + "Socket LGA1356", + "Socket LGA2011", + "Socket FS1", + "Socket FS2", + "Socket FM1", + "Socket FM2", + "Socket LGA2011-3", + "Socket LGA1356-3", /* 0x2C */ + "Socket LGA1150", + "Socket BGA1168", + "Socket BGA1234", + "Socket BGA1364", + "Socket AM4", + "Socket LGA1151", + "Socket BGA1356", + "Socket BGA1440", + "Socket BGA1515", + "Socket LGA3647-1", + "Socket SP3", + "Socket SP3r2", + "Socket LGA2066", + "Socket BGA1392", + "Socket BGA1510", + "Socket BGA1528" /* 0x3C */ }; xmlNode *upgr_n = xmlNewChild(node, NULL, (xmlChar *) "Upgrade", NULL); assert( upgr_n != NULL ); - dmixml_AddAttribute(upgr_n, "dmispec", "3.3.5.5"); + dmixml_AddAttribute(upgr_n, "dmispec", "7.5.5"); dmixml_AddAttribute(upgr_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x15) { + if(code >= 0x01 && code <= 0x3C) { dmixml_AddTextContent(upgr_n, "%s", upgrade[code - 0x01]); } else { - dmixml_AddAttribute(upgr_n, "outofspec", "1"); + dmixml_AddAttribute(upgr_n, OUT_OF_SPEC, "1"); } } @@ -1265,23 +1519,28 @@ void dmi_processor_cache(xmlNode *cache_n, u16 code, u16 ver) } } -/* 3.3.5.9 */ +/* 7.5.9 */ void dmi_processor_characteristics(xmlNode *node, u16 code) { static const char *characteristics[] = { "Unknown", /* 1 */ - "64-bit capable" /* 2 */ + "64-bit capable", /* 2 */ + "Multi-Core", + "Hardware Thread", + "Execute Protection", + "Enhanced Virtualization", + "Power/Performance Control" /* 7 */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Characteristics", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.5.9"); + dmixml_AddAttribute(data_n, "dmispec", "7.5.9"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if((code & 0x0004) != 0) { + if((code & 0x00FC) != 0) { int i; - for(i = 1; i <= 2; i++) { + for(i = 1; i <= 7; i++) { if(code & (1 << i)) { dmixml_AddTextChild(data_n, "Flag", "%s", characteristics[i - 1]); } @@ -1290,12 +1549,12 @@ void dmi_processor_characteristics(xmlNode *node, u16 code) } /******************************************************************************* -** 3.3.6 Memory Controller Information (Type 5) +** 7.6 Memory Controller Information (Type 5) */ void dmi_memory_controller_ed_method(xmlNode *node, u8 code) { - /* 3.3.6.1 */ + /* 7.6.1 */ static const char *method[] = { "Other", /* 0x01 */ "Unknown", @@ -1308,17 +1567,17 @@ void dmi_memory_controller_ed_method(xmlNode *node, u8 code) }; xmlNode *ercm_n = xmlNewChild(node, NULL, (xmlChar *) "CorrectionMethod", NULL); assert( ercm_n != NULL ); - dmixml_AddAttribute(ercm_n, "dmispec", "3.3.6.1"); + dmixml_AddAttribute(ercm_n, "dmispec", "7.6.1"); dmixml_AddAttribute(ercm_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x08) { dmixml_AddTextContent(ercm_n, method[code - 0x01]); } else { - dmixml_AddAttribute(ercm_n, "outofspec", "1"); + dmixml_AddAttribute(ercm_n, OUT_OF_SPEC, "1"); } } -/* 3.3.6.2 */ +/* 7.6.2 */ void dmi_memory_controller_ec_capabilities(xmlNode *node, const char *tagname, u8 code) { static const char *capabilities[] = { @@ -1332,7 +1591,7 @@ void dmi_memory_controller_ec_capabilities(xmlNode *node, const char *tagname, u xmlNode *cap_n = xmlNewChild(node, NULL, (xmlChar *) tagname, NULL); assert( cap_n != NULL ); - dmixml_AddAttribute(cap_n, "dmispec", "3.3.6.2"); + dmixml_AddAttribute(cap_n, "dmispec", "7.6.2"); dmixml_AddAttribute(cap_n, "flags", "0x%04x", code); if((code & 0x3F) != 0) { @@ -1349,7 +1608,7 @@ void dmi_memory_controller_ec_capabilities(xmlNode *node, const char *tagname, u void dmi_memory_controller_interleave(xmlNode *node, const char *tagname, u8 code) { - /* 3.3.6.3 */ + /* 7.6.3 */ static const char *interleave[] = { "Other", /* 0x01 */ "Unknown", @@ -1361,17 +1620,17 @@ void dmi_memory_controller_interleave(xmlNode *node, const char *tagname, u8 cod }; xmlNode *mci_n = xmlNewChild(node, NULL, (xmlChar *) tagname, NULL); assert( mci_n != NULL ); - dmixml_AddAttribute(mci_n, "dmispec", "3.3.6.3"); + dmixml_AddAttribute(mci_n, "dmispec", "7.6.3"); dmixml_AddAttribute(mci_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x07) { dmixml_AddTextContent(mci_n, interleave[code - 0x01]); } else { - dmixml_AddAttribute(mci_n, "outofspec", "1"); + dmixml_AddAttribute(mci_n, OUT_OF_SPEC, "1"); } } -/* 3.3.6.4 */ +/* 7.6.4 */ void dmi_memory_controller_speeds(xmlNode *node, u16 code) { static struct { @@ -1386,7 +1645,7 @@ void dmi_memory_controller_speeds(xmlNode *node, u16 code) }; xmlNode *mcs_n = xmlNewChild(node, NULL, (xmlChar *) "SupportedSpeeds", NULL); assert( mcs_n != NULL ); - dmixml_AddAttribute(mcs_n, "dmispec", "3.3.6.4"); + dmixml_AddAttribute(mcs_n, "dmispec", "7.6.4"); dmixml_AddAttribute(mcs_n, "flags", "0x%04x", code); if((code & 0x001F) == 0) { @@ -1418,10 +1677,10 @@ void dmi_memory_controller_slots(xmlNode *node, u8 count, const u8 * p) } /******************************************************************************* -** 3.3.7 Memory Module Information (Type 6) +** 7.7 Memory Module Information (Type 6) */ -/* 3.3.7.1 */ +/* 7.7.1 */ void dmi_memory_module_types(xmlNode *node, const char *tagname, u16 code) { static const char *types[] = { @@ -1439,7 +1698,7 @@ void dmi_memory_module_types(xmlNode *node, const char *tagname, u16 code) }; xmlNode *mmt_n = xmlNewChild(node, NULL, (xmlChar *) tagname, NULL); assert( mmt_n != NULL ); - dmixml_AddAttribute(mmt_n, "dmispec", "3.3.7.1"); + dmixml_AddAttribute(mmt_n, "dmispec", "7.7.1"); dmixml_AddAttribute(mmt_n, "flags", "0x%04x", code); if((code & 0x07FF) != 0) { @@ -1485,14 +1744,14 @@ void dmi_memory_module_speed(xmlNode *node, const char *tagname, u8 code) } } -/* 3.3.7.2 */ +/* 7.7.2 */ void dmi_memory_module_size(xmlNode *node, const char *tagname, u8 code) { int check_conn = 1; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) tagname, NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.7.2"); + dmixml_AddAttribute(data_n, "dmispec", "7.7.2"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); switch (code & 0x7F) { @@ -1505,6 +1764,7 @@ void dmi_memory_module_size(xmlNode *node, const char *tagname, u8 code) case 0x7F: dmixml_AddAttribute(data_n, "installed", "0"); check_conn = 0; + break; default: dmixml_AddAttribute(data_n, "installed", "1"); dmixml_AddAttribute(data_n, "unit", "MB"); @@ -1520,24 +1780,22 @@ void dmi_memory_module_error(xmlNode *node, u8 code) { xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "ModuleErrorStatus", NULL); assert( data_n != NULL ); + static const char *status[] = { + "OK", /* 0x00 */ + "Uncorrectable Errors", + "Correctable Errors", + "Correctable and Uncorrectable Errors" /* 0x03 */ + }; dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if( !(code & (1 << 2)) ) { - if((code & 0x03) == 0) { - dmixml_AddAttribute(data_n, "Error", "1"); - } - if(code & (1 << 0)) { - dmixml_AddTextContent(data_n, "Uncorrectable Errors"); - } - if(code & (1 << 1)) { - dmixml_AddTextContent(data_n, "Correctable Errors"); - } + dmixml_AddAttribute(data_n, "Error Status", "%s", status[code & 0x03]); } } /******************************************************************************* -** 3.3.8 Cache Information (Type 7) +** 7.8 Cache Information (Type 7) */ static const char *dmi_cache_mode(u8 code) { @@ -1562,33 +1820,43 @@ void dmi_cache_location(xmlNode *node, u8 code) xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "CacheLocation", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.8"); + dmixml_AddAttribute(data_n, "dmispec", "7.8"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(location[code] != NULL) { dmixml_AddTextContent(data_n, location[code]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } -void dmi_cache_size(xmlNode *node, const char *tagname, u16 code) +void dmi_cache_size_2(xmlNode *node, const char *tagname, u32 code) { - xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) tagname, NULL); - assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.8"); - dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + xmlNode *caches_n = xmlNewChild(node, NULL, (xmlChar *)tagname, NULL); + assert(caches_n != NULL); + dmixml_AddAttribute(caches_n, "dmispec", "7.8"); + dmixml_AddAttribute(caches_n, "flags", "0x%04x", code); - if(code & 0x8000) { - dmixml_AddAttribute(data_n, "unit", "KB"); - dmixml_AddTextContent(data_n, "%i", (code & 0x7FFF) << 6); + u64 size; + if (code & 0x80000000){ + code &= 0x7FFFFFFFLU; + size.l = code << 6; + size.h = code >> 26; } else { - dmixml_AddAttribute(data_n, "unit", "KB"); - dmixml_AddTextContent(data_n, "%i", code); + size.l = code; + size.h = 0; } + + /* Use a more convenient unit for large cache size */ + dmi_add_memory_size(caches_n, size, 1); +} + +void dmi_cache_size(xmlNode *node, const char *tagname, u16 code) +{ + dmi_cache_size_2(node, tagname, (((u32)code & 0x8000LU) << 16) | (code & 0x7FFFLU)); } -/* 3.3.8.2 */ +/* 7.8.2 */ void dmi_cache_types(xmlNode *node, const char *tagname, u16 code) { static const char *types[] = { @@ -1603,7 +1871,7 @@ void dmi_cache_types(xmlNode *node, const char *tagname, u16 code) xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) tagname, NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.8.2"); + dmixml_AddAttribute(data_n, "dmispec", "7.8.2"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); @@ -1620,7 +1888,7 @@ void dmi_cache_types(xmlNode *node, const char *tagname, u16 code) void dmi_cache_ec_type(xmlNode *node, u8 code) { - /* 3.3.8.3 */ + /* 7.8.3 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -1631,19 +1899,19 @@ void dmi_cache_ec_type(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "ErrorCorrectionType", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.8.3"); + dmixml_AddAttribute(data_n, "dmispec", "7.8.3"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x06) { dmixml_AddTextContent(data_n, type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_cache_type(xmlNode *node, u8 code) { - /* 3.3.8.4 */ + /* 7.8.4 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -1653,19 +1921,19 @@ void dmi_cache_type(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "SystemType", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.8.4"); + dmixml_AddAttribute(data_n, "dmispec", "7.8.4"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x05) { dmixml_AddTextContent(data_n, type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_cache_associativity(xmlNode *node, u8 code) { - /* 3.3.8.5 */ + /* 7.8.5 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -1674,27 +1942,33 @@ void dmi_cache_associativity(xmlNode *node, u8 code) "4-way Set-associative", "Fully Associative", "8-way Set-associative", - "16-way Set-associative" /* 0x08 */ + "16-way Set-associative", /* 0x08 */ + "12-way Set-associative", + "24-way Set-associative", + "32-way Set-associative", + "48-way Set-associative", + "64-way Set-associative", /* 0x0D */ + "20-way Set-associative" /* 0x0E */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Associativity", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.8.5"); + dmixml_AddAttribute(data_n, "dmispec", "7.8.5"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x08) { + if(code >= 0x01 && code <= 0x0E) { dmixml_AddTextContent(data_n, type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } /******************************************************************************* -** 3.3.9 Port Connector Information (Type 8) +** 7.9 Port Connector Information (Type 8) */ void dmi_port_connector_type(xmlNode *node, const char *tpref, u8 code) { - /* 3.3.9.2 */ + /* 7.9.2 */ static const char *type[] = { "None", /* 0x00 */ "Centronics", @@ -1730,7 +2004,8 @@ void dmi_port_connector_type(xmlNode *node, const char *tpref, u8 code) "Mini Jack (headphones)", "BNC", "IEEE 1394", - "SAS/SATA Plug Receptacle" /* 0x22 */ + "SAS/SATA Plug Receptacle", /* 0x22 */ + "USB Type-C Receptacle" /* 0x23 */ }; static const char *type_0xA0[] = { "PC-98", /* 0xA0 */ @@ -1742,24 +2017,24 @@ void dmi_port_connector_type(xmlNode *node, const char *tpref, u8 code) xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Connector", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.9.2"); + dmixml_AddAttribute(data_n, "dmispec", "7.9.2"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); dmixml_AddAttribute(data_n, "type", "%s", tpref); - if(code <= 0x22) { + if(code <= 0x23) { dmixml_AddTextContent(data_n, type[code]); } else if(code >= 0xA0 && code <= 0xA4) { dmixml_AddTextContent(data_n, type_0xA0[code - 0xA0]); } else if(code == 0xFF) { dmixml_AddTextContent(data_n, "Other"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_port_type(xmlNode *node, u8 code) { - /* 3.3.9.3 */ + /* 7.9.3 */ static const char *type[] = { "None", /* 0x00 */ "Parallel Port XT/AT Compatible", @@ -1803,7 +2078,7 @@ void dmi_port_type(xmlNode *node, u8 code) xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "PortType", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.9.3"); + dmixml_AddAttribute(data_n, "dmispec", "7.9.3"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code <= 0x21) { @@ -1813,17 +2088,17 @@ void dmi_port_type(xmlNode *node, u8 code) } else if(code == 0xFF) { dmixml_AddTextContent(data_n, "Other"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } /******************************************************************************* -** 3.3.10 System Slots (Type 9) +** 7.10 System Slots (Type 9) */ void dmi_slot_type(xmlNode *node, u8 code) { - /* 3.3.10.1 */ + /* 7.10.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -1843,8 +2118,29 @@ void dmi_slot_type(xmlNode *node, u8 code) "AGP 2x", "AGP 4x", "PCI-X", - "AGP 8x" /* 0x13 */ + "AGP 8x", /* 0x13 */ + "M.2 Socket 1-DP", + "M.2 Socket 1-SD", + "M.2 Socket 2", + "M.2 Socket 3", + "MXM Type I", + "MXM Type II", + "MXM Type III", + "MXM Type III-HE", + "MXM Type IV", + "MXM 3.0 Type A", + "MXM 3.0 Type B", + "PCI Express 2 SFF-8639", + "PCI Express 3 SFF-8639", + "PCI Express Mini 52-pin with bottom-side keep-outs", + "PCI Express Mini 52-pin without bottom-side keep-outs", + "PCI Express Mini 76-pin" /* 0x23 */ + }; + + static const char *type_0x30[] = { + "CXL FLexbus 1.0" /* 0x30 */ }; + static const char *type_0xA0[] = { "PC-98/C20", /* 0xA0 */ "PC-98/C24", @@ -1856,25 +2152,48 @@ void dmi_slot_type(xmlNode *node, u8 code) "PCI Express x2", "PCI Express x4", "PCI Express x8", - "PCI Express x16" /* 0xAA */ + "PCI Express x16", /* 0xAA */ + "PCI Express 2", + "PCI Express 2 x1", + "PCI Express 2 x2", + "PCI Express 2 x4", + "PCI Express 2 x8", + "PCI Express 2 x16", /* 0xB0 */ + "PCI Express 3", + "PCI Express 3 x1", + "PCI Express 3 x2", + "PCI Express 3 x4", + "PCI Express 3 x8", + "PCI Express 3 x16", /* 0xB6 */ + NULL, /* 0xB7 */ + "PCI Express 4", + "PCI Express 4 x1", + "PCI Express 4 x2", + "PCI Express 4 x4", + "PCI Express 4 x8", + "PCI Express 4 x16" /* 0xBD */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "SlotType", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.10.1"); + dmixml_AddAttribute(data_n, "dmispec", "7.10.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x13) { + if(code >= 0x01 && code <= 0x23) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); - } else if(code >= 0xA0 && code <= 0xAA) { + } else if (code == 0x30){ + dmixml_AddTextContent(data_n, "%s", type_0x30[code - 0x30]); + } else if (code >= 0xA0 && code <= 0xB6) { dmixml_AddTextContent(data_n, "%s", type_0xA0[code - 0xA0]); + } else if (code >= 0xB8 && code <= 0xBD) { + dmixml_AddTextContent(data_n, "%s", type_0xA0[code - 0xB8]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_slot_bus_width(xmlNode *node, u8 code) { - /* 3.3.10.2 */ + /* 7.10.2 */ static const char *width[] = { "", /* 0x01, "Other" */ "", /* "Unknown" */ @@ -1893,63 +2212,66 @@ void dmi_slot_bus_width(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "SlotWidth", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.10.2"); + dmixml_AddAttribute(data_n, "dmispec", "7.10.2"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if( (code >= 0x01) && (code <= 0x0E) ) { dmixml_AddTextContent(data_n, "%s", width[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_slot_current_usage(xmlNode *node, u8 code) { - /* 3.3.10.3 */ + /* 7.10.3 */ static const char *usage[] = { "Other", /* 0x01 */ "Unknown", "Available", - "In Use" /* 0x04 */ + "In Use", /* 0x04 */ + "Unavailable" /* 0x05 */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "CurrentUsage", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.10.3"); + dmixml_AddAttribute(data_n, "dmispec", "7.10.3"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x04) { + if(code >= 0x01 && code <= 0x05) { dmixml_AddTextContent(data_n, usage[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } -/* 3.3.1O.4 */ +/* 7.1O.4 */ void dmi_slot_length(xmlNode *node, u8 code) { static const char *length[] = { "Other", /* 0x01 */ "Unknown", "Short", - "Long" /* 0x04 */ + "Long", /* 0x04 */ + "2.5\" drive form factor", + "3.5\" drive form factor" /* 0x06 */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "SlotLength", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.10.4"); + dmixml_AddAttribute(data_n, "dmispec", "7.10.4"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x04) { + if(code >= 0x01 && code <= 0x06) { dmixml_AddTextContent(data_n, length[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } -/* 3.3.10.5 */ -void inline set_slottype(xmlNode *node, u8 type) { +/* 7.10.5 */ +void set_slottype(xmlNode *node, u8 type) { switch (type) { case 0x04: /* MCA */ dmixml_AddAttribute(node, "slottype", "MCA"); @@ -1970,9 +2292,45 @@ void inline set_slottype(xmlNode *node, u8 type) { case 0x12: /* PCI-X */ dmixml_AddAttribute(node, "slottype", "PCI-X"); break; + case 0x21: /* PCI Express Mini */ + case 0x22: /* PCI Express Mini */ + case 0x23: /* PCI Express Mini */ + dmixml_AddAttribute(node, "slottype", "PCI Express Mini"); + break; case 0xA5: /* PCI Express */ + case 0xA6: /* PCI Express */ + case 0xA7: /* PCI Express */ + case 0xA8: /* PCI Express */ + case 0xA9: /* PCI Express */ + case 0xAA: /* PCI Express */ dmixml_AddAttribute(node, "slottype", "PCI Express"); break; + case 0x1F: /* PCI Express 2*/ + case 0xAB: /* PCI Express 2*/ + case 0xAC: /* PCI Express 2*/ + case 0xAD: /* PCI Express 2*/ + case 0xAE: /* PCI Express 2*/ + case 0xAF: /* PCI Express 2*/ + case 0xB0: /* PCI Express 2*/ + dmixml_AddAttribute(node, "slottype", "PCI Express 2"); + break; + case 0x20: /* PCI Express 3 */ + case 0xB1: /* PCI Express 3 */ + case 0xB2: /* PCI Express 3 */ + case 0xB3: /* PCI Express 3 */ + case 0xB4: /* PCI Express 3 */ + case 0xB5: /* PCI Express 3 */ + case 0xB6: /* PCI Express 3 */ + dmixml_AddAttribute(node, "slottype", "PCI Express 3"); + break; + case 0xB8: /* PCI Express 4 */ + case 0xB9: /* PCI Express 4 */ + case 0xBA: /* PCI Express 4 */ + case 0xBB: /* PCI Express 4 */ + case 0xBC: /* PCI Express 4 */ + case 0xBD: /* PCI Express 4 */ + dmixml_AddAttribute(node, "slottype", "PCI Express 4"); + break; case 0x07: /* PCMCIA */ dmixml_AddAttribute(node, "slottype", "PCMCIA"); break; @@ -1984,7 +2342,7 @@ void inline set_slottype(xmlNode *node, u8 type) { void dmi_slot_id(xmlNode *node, u8 code1, u8 code2, u8 type) { xmlNode *slotid_n = xmlNewChild(node, NULL, (xmlChar *) "SlotID", NULL); - dmixml_AddAttribute(slotid_n, "dmispec", "3.3.10.5"); + dmixml_AddAttribute(slotid_n, "dmispec", "7.10.5"); dmixml_AddAttribute(slotid_n, "flags1", "0x%04x", code1); dmixml_AddAttribute(slotid_n, "flags2", "0x%04x", code2); dmixml_AddAttribute(slotid_n, "type", "0x%04x", type); @@ -1995,19 +2353,47 @@ void dmi_slot_id(xmlNode *node, u8 code1, u8 code2, u8 type) case 0x05: /* EISA */ dmixml_AddAttribute(slotid_n, "id", "%i", code1); break; - case 0x06: /* PCI */ - case 0x0E: /* PCI */ - case 0x0F: /* AGP */ - case 0x10: /* AGP */ - case 0x11: /* AGP */ - case 0x12: /* PCI-X */ - case 0x13: /* AGP */ - case 0xA5: /* PCI Express */ + case 0x06: /* PCI */ + case 0x0E: /* PCI */ + case 0x0F: /* AGP */ + case 0x10: /* AGP */ + case 0x11: /* AGP */ + case 0x12: /* PCI-X */ + case 0x13: /* AGP */ + case 0x1F: /* PCI Express 2 */ + case 0x20: /* PCI Express 3 */ + case 0x21: /* PCI Express Mini */ + case 0x22: /* PCI Express Mini */ + case 0x23: /* PCI Express Mini */ + case 0xA5: /* PCI Express */ + case 0xA6: /* PCI Express */ + case 0xA7: /* PCI Express */ + case 0xA8: /* PCI Express */ + case 0xA9: /* PCI Express */ + case 0xAA: /* PCI Express */ + case 0xAB: /* PCI Express 2 */ + case 0xAC: /* PCI Express 2 */ + case 0xAD: /* PCI Express 2 */ + case 0xAE: /* PCI Express 2 */ + case 0xAF: /* PCI Express 2 */ + case 0xB0: /* PCI Express 2 */ + case 0xB1: /* PCI Express 3 */ + case 0xB2: /* PCI Express 3 */ + case 0xB3: /* PCI Express 3 */ + case 0xB4: /* PCI Express 3 */ + case 0xB5: /* PCI Express 3 */ + case 0xB6: /* PCI Express 3 */ + case 0xB8: /* PCI Express 4 */ + case 0xB9: /* PCI Express 4 */ + case 0xBA: /* PCI Express 4 */ + case 0xBB: /* PCI Express 4 */ + case 0xBC: /* PCI Express 4 */ + case 0xBD: /* PCI Express 4 */ dmixml_AddAttribute(slotid_n, "id", "%i", code1); break; case 0x07: /* PCMCIA */ dmixml_AddAttribute(slotid_n, "adapter", "%i", code1); - dmixml_AddAttribute(slotid_n, "id", "%i", code2); + dmixml_AddAttribute(slotid_n, "socket", "%i", code2); break; default: break; @@ -2017,7 +2403,7 @@ void dmi_slot_id(xmlNode *node, u8 code1, u8 code2, u8 type) void dmi_slot_characteristics(xmlNode *node, u8 code1, u8 code2) { - /* 3.3.10.6 */ + /* 7.10.6 */ static const char *characteristics1[] = { "5.0 V is provided", /* 1 */ "3.3 V is provided", @@ -2028,15 +2414,17 @@ void dmi_slot_characteristics(xmlNode *node, u8 code1, u8 code2) "Modem ring resume is supported" /* 7 */ }; - /* 3.3.10.7 */ + /* 7.10.7 */ static const char *characteristics2[] = { "PME signal is supported", /* 0 */ "Hot-plug devices are supported", - "SMBus signal is supported" /* 2 */ + "SMBus signal is supported", /* 2 */ + "PCIe slot bifurcation is supported" /* 3 */ }; + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "SlotCharacteristics", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.10.6"); + dmixml_AddAttribute(data_n, "dmispec", "7.10.6, 7.10.7"); dmixml_AddAttribute(data_n, "flags1", "0x%04x", code1); dmixml_AddAttribute(data_n, "flags2", "0x%04x", code2); @@ -2055,7 +2443,7 @@ void dmi_slot_characteristics(xmlNode *node, u8 code1, u8 code2) c_n = NULL; } } - for(i = 0; i <= 2; i++) { + for(i = 0; i <= 3; i++) { if(code2 & (1 << i)) { xmlNode *c_n = dmixml_AddTextChild(data_n, "Characteristic", "%s", characteristics2[i]); @@ -2068,23 +2456,40 @@ void dmi_slot_characteristics(xmlNode *node, u8 code1, u8 code2) void dmi_slot_segment_bus_func(xmlNode *node, u16 code1, u8 code2, u8 code3) { - /* 3.3.10.8 */ + /* 7.10.8 */ xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "BusAddress", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.10.8"); + dmixml_AddAttribute(data_n, "dmispec", "7.10.8"); if(!(code1 == 0xFFFF && code2 == 0xFF && code3 == 0xFF)) { dmixml_AddTextContent(data_n, "%04x:%02x:%02x.%x", code1, code2, code3 >> 3, code3 & 0x7); } } +void dmi_slot_peers(xmlNode *node, u8 n, const u8 *data, struct dmi_header *h) +{ + xmlNode *sp_n = xmlNewChild(node, NULL, (xmlChar *)"Peerdevices", NULL); + assert(sp_n != NULL); + + int i; + for (i = 1; i <= n; i++, data += 5){ + xmlNode *dev_n = dmixml_AddDMIstring(sp_n, "device", h, i); + + dmixml_AddAttribute(dev_n, "index", "%i", i); + dmixml_AddTextContent(dev_n, "%04x:%02x:%02x.%x (Width %u)", + WORD(data), data[2], data[3] >> 3, data[3] & 0x07, data[4]); + dev_n = NULL; + } +} + + /******************************************************************************* -** 3.3.11 On Board Devices Information (Type 10) +** 7.11 On Board Devices Information (Type 10) */ void dmi_on_board_devices_type(xmlNode *node, u8 code) { - /* 3.3.11.1 */ + /* 7.11.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -2098,17 +2503,17 @@ void dmi_on_board_devices_type(xmlNode *node, u8 code) "SAS Controller" /* 0x0A */ }; - dmixml_AddAttribute(node, "dmispec", "3.3.11.1"); + dmixml_AddAttribute(node, "dmispec", "7.11.1, 7.42.2"); dmixml_AddAttribute(node, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x0A) { dmixml_AddTextChild(node, "Type", "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(node, "outofspec", "1"); + dmixml_AddAttribute(node, OUT_OF_SPEC, "1"); } } -void dmi_on_board_devices(xmlNode *node, const char *tagname, struct dmi_header *h) +void dmi_on_board_devices(xmlNode *node, const char *tagname, const struct dmi_header *h) { u8 *p = h->data + 4; u8 count = (h->length - 0x04) / 2; @@ -2116,7 +2521,7 @@ void dmi_on_board_devices(xmlNode *node, const char *tagname, struct dmi_header xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) tagname, NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.11"); + dmixml_AddAttribute(data_n, "dmispec", "7.11"); for(i = 0; i < count; i++) { xmlNode *dev_n = xmlNewChild(data_n, NULL, (xmlChar *) "Device", NULL); @@ -2124,13 +2529,13 @@ void dmi_on_board_devices(xmlNode *node, const char *tagname, struct dmi_header dmi_on_board_devices_type(dev_n, p[2 * i] & 0x7F); dmixml_AddAttribute(dev_n, "Enabled", "%i", ((p[2 * i] & 0x80) ? 1 : 0)); - dmixml_AddTextChild(dev_n, "Description", "%s", dmi_string(h, p[2 * i + 1])); + dmixml_AddDMIstring(dev_n, "Description", h, p[2 * i + 1]); dev_n = NULL; } } /******************************************************************************* - * 3.3.12 OEM Strings (Type 11) + * 7.12 OEM Strings (Type 11) */ void dmi_oem_strings(xmlNode *node, struct dmi_header *h) @@ -2142,14 +2547,14 @@ void dmi_oem_strings(xmlNode *node, struct dmi_header *h) dmixml_AddAttribute(node, "count", "%i", count); for(i = 1; i <= count; i++) { - xmlNode *str_n = dmixml_AddTextChild(node, "Record", "%s", dmi_string(h, i)); + xmlNode *str_n = dmixml_AddDMIstring(node, "Record", h, i); assert( str_n != NULL ); dmixml_AddAttribute(str_n, "index", "%i", i); } } /******************************************************************************* -** 3.3.13 System Configuration Options (Type 12) +** 7.13 System Configuration Options (Type 12) */ void dmi_system_configuration_options(xmlNode *node, struct dmi_header *h) @@ -2160,11 +2565,11 @@ void dmi_system_configuration_options(xmlNode *node, struct dmi_header *h) xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Options", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.13"); + dmixml_AddAttribute(data_n, "dmispec", "7.13"); dmixml_AddAttribute(data_n, "count", "%i", count); for(i = 1; i <= count; i++) { - xmlNode *o_n = dmixml_AddTextChild(data_n, "Option", "%s", dmi_string(h, i)); + xmlNode *o_n = dmixml_AddDMIstring(data_n, "Option", h, i); assert( o_n != NULL ); dmixml_AddAttribute(o_n, "index", "%ld", i); @@ -2172,10 +2577,10 @@ void dmi_system_configuration_options(xmlNode *node, struct dmi_header *h) } /******************************************************************************* -** 3.3.14 BIOS Language Information (Type 13) +** 7.14 BIOS Language Information (Type 13) */ -void dmi_bios_languages(xmlNode *node, struct dmi_header *h) +void dmi_bios_languages(xmlNode *node, struct dmi_header *h, u8 brevity_code) { u8 *p = h->data + 4; u8 count = p[0x00]; @@ -2183,23 +2588,37 @@ void dmi_bios_languages(xmlNode *node, struct dmi_header *h) xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Installed", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.14"); + dmixml_AddAttribute(data_n, "dmispec", "7.14"); dmixml_AddAttribute(data_n, "count", "%i", count); + if (brevity_code & 0x01) { + dmixml_AddAttribute(data_n, "format", "Abbreviated"); + } else { + dmixml_AddAttribute(data_n, "format", "Long"); + } + for(i = 1; i <= count; i++) { - xmlNode *l_n = dmixml_AddTextChild(data_n, "Language", "%s", dmi_string(h, i)); + xmlNode *l_n = dmixml_AddDMIstring(data_n, "Language", h, i); assert( l_n != NULL ); dmixml_AddAttribute(l_n, "index", "%i", i); } } +static const char *dmi_bios_language_format(u8 code) +{ + if (code & 0x01) + return "Abbreviated"; + else + return "Long"; +} + /******************************************************************************* -** 3.3.15 Group Associations (Type 14) +** 7.15 Group Associations (Type 14) */ void dmi_group_associations_items(xmlNode *node, u8 count, const u8 * p) { - dmixml_AddAttribute(node, "dmispec", "3.3.15"); + dmixml_AddAttribute(node, "dmispec", "7.15"); dmixml_AddAttribute(node, "items", "%i", count); int i; @@ -2213,7 +2632,7 @@ void dmi_group_associations_items(xmlNode *node, u8 count, const u8 * p) } /******************************************************************************* -** 3.3.16 System Event Log (Type 15) +** 7.16 System Event Log (Type 15) */ void dmi_event_log_method(xmlNode *node, u8 code) @@ -2228,7 +2647,7 @@ void dmi_event_log_method(xmlNode *node, u8 code) xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "AccessMethod", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.16"); + dmixml_AddAttribute(data_n, "dmispec", "7.16"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code <= 0x04) { @@ -2237,7 +2656,7 @@ void dmi_event_log_method(xmlNode *node, u8 code) dmixml_AddTextContent(data_n, "OEM-specific"); dmixml_AddAttribute(data_n, "unknown", "1"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2254,10 +2673,9 @@ void dmi_event_log_status(xmlNode *node, u8 code) xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Status", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.16"); + dmixml_AddAttribute(data_n, "dmispec", "7.16"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - // FIXME: Should we use 0/1 instead of strings? dmixml_AddAttribute(data_n, "Full", "%s", full[(code >> 1) & 1]); dmixml_AddAttribute(data_n, "Valid", "%s", valid[(code >> 0) & 1]); } @@ -2266,10 +2684,10 @@ void dmi_event_log_address(xmlNode *node, u8 method, const u8 * p) { xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Address", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.16.3"); + dmixml_AddAttribute(data_n, "dmispec", "7.16.3"); dmixml_AddAttribute(data_n, "method", "0x%04x", method); - /* 3.3.16.3 */ + /* 7.16.3 */ switch (method) { case 0x00: case 0x01: @@ -2297,7 +2715,7 @@ void dmi_event_log_header_type(xmlNode *node, u8 code) xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Format", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.16"); + dmixml_AddAttribute(data_n, "dmispec", "7.16"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code <= 0x01) { @@ -2305,13 +2723,13 @@ void dmi_event_log_header_type(xmlNode *node, u8 code) } else if(code >= 0x80) { dmixml_AddTextContent(data_n, "OEM-specific"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_event_log_descriptor_type(xmlNode *node, u8 code) { - /* 3.3.16.6.1 */ + /* 7.16.6.1 */ static const char *type[] = { NULL, /* 0x00 */ "Single-bit ECC memory error", @@ -2341,7 +2759,7 @@ void dmi_event_log_descriptor_type(xmlNode *node, u8 code) xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Descriptor", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.16.6.1"); + dmixml_AddAttribute(data_n, "dmispec", "7.16.6.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code <= 0x17 && type[code] != NULL) { @@ -2351,13 +2769,13 @@ void dmi_event_log_descriptor_type(xmlNode *node, u8 code) } else if(code == 0xFF) { dmixml_AddTextContent(data_n, "End of log"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_event_log_descriptor_format(xmlNode *node, u8 code) { - /* 3.3.16.6.2 */ + /* 7.16.6.2 */ static const char *format[] = { "None", /* 0x00 */ "Handle", @@ -2370,7 +2788,7 @@ void dmi_event_log_descriptor_format(xmlNode *node, u8 code) xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Format", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.16.6.2"); + dmixml_AddAttribute(data_n, "dmispec", "7.16.6.2"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code <= 0x06) { @@ -2378,16 +2796,16 @@ void dmi_event_log_descriptor_format(xmlNode *node, u8 code) } else if(code >= 0x80) { dmixml_AddTextContent(data_n, "OEM-specific"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_event_log_descriptors(xmlNode *node, u8 count, const u8 len, const u8 * p) { - /* 3.3.16.1 */ + /* 7.16.1 */ int i; - dmixml_AddAttribute(node, "dmispec", "3.3.16.1"); + dmixml_AddAttribute(node, "dmispec", "7.16.1"); for(i = 0; i < count; i++) { if(len >= 0x02) { @@ -2401,12 +2819,12 @@ void dmi_event_log_descriptors(xmlNode *node, u8 count, const u8 len, const u8 * } /******************************************************************************* -** 3.3.17 Physical Memory Array (Type 16) +** 7.17 Physical Memory Array (Type 16) */ void dmi_memory_array_location(xmlNode *node, u8 code) { - /* 3.3.17.1 */ + /* 7.17.1 */ static const char *location[] = { "Other", /* 0x01 */ "Unknown", @@ -2420,16 +2838,17 @@ void dmi_memory_array_location(xmlNode *node, u8 code) "NuBus" /* 0x0A, master.mif says 16 */ }; static const char *location_0xA0[] = { - "PC-98/C20 Add-on Card", /* 0xA0 */ - "PC-98/C24 Add-on Card", - "PC-98/E Add-on Card", - "PC-98/Local Bus Add-on Card", - "PC-98/Card Slot Add-on Card" /* 0xA4, from master.mif */ + "PC-98/C20 Add-on Card", /* 0xA0 */ + "PC-98/C24 Add-on Card", + "PC-98/E Add-on Card", + "PC-98/Local Bus Add-on Card", + "PC-98/Card Slot Add-on Card", + "CXL Flexbus 1.0" /* 0xA4, from master.mif */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Location", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.17.1"); + dmixml_AddAttribute(data_n, "dmispec", "7.17.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x0A) { @@ -2437,13 +2856,13 @@ void dmi_memory_array_location(xmlNode *node, u8 code) } else if(code >= 0xA0 && code <= 0xA4) { dmixml_AddTextContent(data_n, location_0xA0[code - 0xA0]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_memory_array_use(xmlNode *node, u8 code) { - /* 3.3.17.2 */ + /* 7.17.2 */ static const char *use[] = { "Other", /* 0x01 */ "Unknown", @@ -2455,19 +2874,19 @@ void dmi_memory_array_use(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Use", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.17.2"); + dmixml_AddAttribute(data_n, "dmispec", "7.17.2"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x07) { dmixml_AddTextContent(data_n, use[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_memory_array_ec_type(xmlNode *node, u8 code) { - /* 3.3.17.3 */ + /* 7.17.3 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -2480,35 +2899,33 @@ void dmi_memory_array_ec_type(xmlNode *node, u8 code) xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "ErrorCorrectionType", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.17.3"); + dmixml_AddAttribute(data_n, "dmispec", "7.17.3"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x07) { dmixml_AddTextContent(data_n, type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } -void dmi_memory_array_capacity(xmlNode *node, u32 code) +void dmi_memory_array_capacity(xmlNode *node, struct dmi_header *h, const u8 *data) { xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "MaxCapacity", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code == 0x8000000) { - dmixml_AddAttribute(data_n, "unknown", "1"); - } else { - if((code & 0x000FFFFF) == 0) { - dmixml_AddAttribute(data_n, "unit", "GB"); - dmixml_AddTextContent(data_n, "%i", code >> 20); - } else if((code & 0x000003FF) == 0) { - dmixml_AddAttribute(data_n, "unit", "MB"); - dmixml_AddTextContent(data_n, "%i", code >> 10); + if(DWORD(data + 0x07) == 0x8000000) { + if( h->length < 0x17 ) { + dmixml_AddAttribute(data_n, "unknown", "1"); } else { - dmixml_AddAttribute(data_n, "unit", "KB"); - dmixml_AddTextContent(data_n, "%i", code); + dmi_add_memory_size(data_n, QWORD(data + 0x0F), 0); } + } else { + u64 capacity; + + capacity.h = 0; + capacity.l = DWORD(data + 0x07); + dmi_add_memory_size(data_n, capacity, 1); } } @@ -2527,7 +2944,7 @@ void dmi_memory_array_error_handle(xmlNode *node, u16 code) } /******************************************************************************* -** 3.3.18 Memory Device (Type 17) +** 7.18 Memory Device (Type 17) */ void dmi_memory_device_width(xmlNode *node, const char *tagname, u16 code) @@ -2560,38 +2977,79 @@ void dmi_memory_device_size(xmlNode *node, u16 code) //. Keeping this as String rather than Int as it has KB and MB representations... dmixml_AddAttribute(data_n, "unit", "%s", (code & 0x8000 ? "KB" : "MB")); dmixml_AddTextContent(data_n, "%d", (code & 0x8000 ? code & 0x7FFF : code)); + //dmi_add_memory_size(data_n, code, 1); } } + +static void dmi_memory_device_extended_size(xmlNode *node, u32 code) +{ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Size", NULL); + assert( data_n != NULL ); + + code &= 0x7FFFFFFFUL; + dmixml_AddAttribute(data_n, "flags", "0x%08x", code); + dmixml_AddAttribute(data_n, "mode", "extended"); + + /* Use the most suitable unit depending on size */ + if (code & 0x3FFUL) { + dmixml_AddAttribute(data_n, "unit", "MB"); + dmixml_AddTextContent(data_n, "%lu", (unsigned long) code); + } else if (code & 0xFFFFFUL) { + dmixml_AddAttribute(data_n, "unit", "GB"); + dmixml_AddTextContent(data_n, "%lu", (unsigned long) code >> 10); + } else { + dmixml_AddAttribute(data_n, "unit", "TB"); + dmixml_AddTextContent(data_n, "%lu", (unsigned long) code >> 20); + } +} + + +void dmi_memory_voltage_value(xmlNode *node, const char *tag, u16 code) +{ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)tag, NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + if (code == 0) { + dmixml_AddAttribute(data_n, "unknown", "1"); + } else { + dmixml_AddAttribute(data_n, "unit", "V"); + dmixml_AddTextContent(data_n, "%.3f", (float)(i16)code / 1000); + } +} + + void dmi_memory_device_form_factor(xmlNode *node, u8 code) { - /* 3.3.18.1 */ + /* 7.18.1 */ static const char *form_factor[] = { - "Other", /* 0x01 */ - "Unknown", - "SIMM", - "SIP", - "Chip", - "DIP", - "ZIP", - "Proprietary Card", - "DIMM", - "TSOP", - "Row Of Chips", - "RIMM", - "SODIMM", - "SRIMM", - "FB-DIMM" /* 0x0F */ + "Other", /* 0x01 */ + "Unknown", + "SIMM", + "SIP", + "Chip", + "DIP", + "ZIP", + "Proprietary Card", + "DIMM", + "TSOP", + "Row Of Chips", + "RIMM", + "SODIMM", + "SRIMM", + "FB-DIMM", /* 0x0F */ + "Die" /* 0x10 */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "FormFactor", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.18.1"); + dmixml_AddAttribute(data_n, "dmispec", "7.18.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x0F) { + if(code >= 0x01 && code <= 0x10) { dmixml_AddTextContent(data_n, "%s", form_factor[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2601,53 +3059,70 @@ void dmi_memory_device_set(xmlNode *node, u8 code) assert( data_n != NULL ); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code == 0xFF) { - dmixml_AddAttribute(data_n, "outofspec", "1"); - } else if( code > 0 ) { + if (code == 0) { + // empty tag + } else if (code == 0xFF) { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } else { dmixml_AddTextContent(data_n, "%ld", code); } } void dmi_memory_device_type(xmlNode *node, u8 code) { - /* 3.3.18.2 */ + /* 7.18.2 */ static const char *type[] = { - "Other", /* 0x01 */ - "Unknown", - "DRAM", - "EDRAM", - "VRAM", - "SRAM", - "RAM", - "ROM", - "Flash", - "EEPROM", - "FEPROM", - "EPROM", - "CDRAM", - "3DRAM", - "SDRAM", - "SGRAM", - "RDRAM", - "DDR", - "DDR2", - "DDR2 FB-DIMM" /* 0x14 */ + "Other", /* 0x01 */ + "Unknown", + "DRAM", + "EDRAM", + "VRAM", + "SRAM", + "RAM", + "ROM", + "Flash", + "EEPROM", + "FEPROM", + "EPROM", + "CDRAM", + "3DRAM", + "SDRAM", + "SGRAM", + "RDRAM", + "DDR", + "DDR2", + "DDR2 FB-DIMM", /* 0x14 */ + "Reserved", + "Reserved", + "Reserved", + "DDR3", + "FBD2", /* 0x19 */ + "DDR4", + "LPDDR", + "LPDDR2", + "LPDDR3", + "LPDDR4", + "Logical non-volatile device", + "HBM", + "HBM2", /* 0x21 */ + "DDR5", + "LPDDR5" /* 0x23 */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Type", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.18.2"); + dmixml_AddAttribute(data_n, "dmispec", "7.18.2"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x14) { + if(code >= 0x01 && code <= 0x23) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_memory_device_type_detail(xmlNode *node, u16 code) { - /* 3.3.18.3 */ + /* 7.18.3 */ static const char *detail[] = { "Other", /* 1 */ "Unknown", @@ -2660,16 +3135,19 @@ void dmi_memory_device_type_detail(xmlNode *node, u16 code) "EDO", "Window DRAM", "Cache DRAM", - "Non-Volatile" /* 12 */ + "Non-Volatile", /* 12 */ + "Registered (Buffered)", + "Unbuffered (Unregistered)", /* 14 */ + "LRDIMM" /* 15 */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "TypeDetails", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.18.3"); + dmixml_AddAttribute(data_n, "dmispec", "7.18.3"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if((code & 0x1FFE) != 0) { + if((code & 0xFFFE) != 0) { int i; - for(i = 1; i <= 12; i++) { + for(i = 1; i <= 15; i++) { if(code & (1 << i)) { xmlNode *td_n = dmixml_AddTextChild(data_n, "flag", "%s", detail[i - 1]); assert( td_n != NULL ); @@ -2679,28 +3157,138 @@ void dmi_memory_device_type_detail(xmlNode *node, u16 code) } } -void dmi_memory_device_speed(xmlNode *node, u16 code) + +void dmi_memory_device_speed(xmlNode *node, const char *tag, u16 code) { - xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Speed", NULL); + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) tag, NULL); assert( data_n != NULL ); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code == 0) { - dmixml_AddAttribute(data_n, "unkown", "1"); + dmixml_AddAttribute(data_n, "unknown", "1"); } else { - dmixml_AddAttribute(data_n, "speed_ns", "%.1f", (float) 1000 / code); - dmixml_AddAttribute(data_n, "unit", "MHz"); + dmixml_AddAttribute(data_n, "unit", "MT/s"); dmixml_AddTextContent(data_n, "%i", code); } } + +void dmi_memory_technology(xmlNode *node, u8 code) +{ + /* 7.18.6 */ + static const char *const technology[] = { + "Other", /* 0x01 */ + "Unknown", + "DRAM", + "NVDIMM-N", + "NVDIMM-F", + "NVDIMM-P", + "Intel Optane DC persistent memory" /* 0x07 */ + }; + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"MemoryTechnology", NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "dmispec", "7.18.6"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + if (code >= 0x01 && code <= 0x07) + dmixml_AddTextContent(data_n, "%s", technology[code - 0x01]); + else + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); +} + +void dmi_memory_operating_mode_capability(xmlNode *node, u16 code) +{ + /* 7.18.7 */ + static const char *const mode[] = { + "Other", /* 1 */ + "Unknown", + "Volatile memory", + "Byte-accessible persistent memory", + "Block-accessible persistent memory" /* 5 */ + }; + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"Memory Operating Mode Capability", NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "dmispec", "7.18.7"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + char list[99]; /* Update length if you touch the array above */ + if ((code & 0xFFFE) != 0) { + int i, off = 0; + list[0] = '\0'; + for (i = 1; i <= 5; i++) { + if (code & (1 << i)) + off += sprintf(list + off, off ? " %s" : "%s", mode[i - 1]); + } + dmixml_AddTextContent(data_n, "%s", list); + } +} + +void dmi_memory_manufacturer_id(xmlNode *node, u16 code) +{ + /* 7.18.8 */ + /* 7.18.10 */ + /* LSB is 7-bit Odd Parity number of continuation codes */ + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"Memory Manufacturer Id", NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "dmispec", "7.18.8/7.18.10"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + if (code != 0) { + dmixml_AddAttribute(data_n, "%s", "Bank"); + dmixml_AddTextContent(data_n, "%u", (code & 0x7F) + 1); + dmixml_AddAttribute(data_n, "%s", "Hex"); + dmixml_AddTextContent(data_n, "%u", code >> 8); + } else { + dmixml_AddAttribute(data_n, "unknown", "1"); + } +} + + +void dmi_memory_product_id(xmlNode *node, u16 code) +{ + /* 7.18.9 */ + /* 7.18.11 */ + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"Memory Product Id", NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "dmispec", "7.18.9/7.18.11"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + if (code != 0){ + dmixml_AddTextContent(data_n, "%u", code); + } else { + dmixml_AddAttribute(data_n, "unknown", "1"); + } +} + + +void dmi_memory_size(xmlNode *node, u64 code) +{ + /* 7.18.12 */ + /* 7.18.13 */ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"Memory Size", NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "dmispec", "7.18.12/7.18.13"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + if (code.h == 0xFFFFFFFF && code.l == 0xFFFFFFFF) { + dmixml_AddAttribute(data_n, "unknown", "1"); + } else if (code.h == 0x0 && code.l == 0x0) { + // empty tag + } else { + dmi_add_memory_size(data_n, code, 0); + } +} + /******************************************************************************* -* 3.3.19 32-bit Memory Error Information (Type 18) +* 7.19 32-bit Memory Error Information (Type 18) */ void dmi_memory_error_type(xmlNode *node, u8 code) { - /* 3.3.19.1 */ + /* 7.19.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -2719,19 +3307,19 @@ void dmi_memory_error_type(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Type", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.19.1"); + dmixml_AddAttribute(data_n, "dmispec", "7.19.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x0E) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_memory_error_granularity(xmlNode *node, u8 code) { - /* 3.3.19.2 */ + /* 7.19.2 */ static const char *granularity[] = { "Other", /* 0x01 */ "Unknown", @@ -2740,19 +3328,19 @@ void dmi_memory_error_granularity(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Granularity", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.19.2"); + dmixml_AddAttribute(data_n, "dmispec", "7.19.2"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x04) { dmixml_AddTextContent(data_n, "%s", granularity[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_memory_error_operation(xmlNode *node, u8 code) { - /* 3.3.19.3 */ + /* 7.19.3 */ static const char *operation[] = { "Other", /* 0x01 */ "Unknown", @@ -2762,13 +3350,13 @@ void dmi_memory_error_operation(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Operation", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.19.3"); + dmixml_AddAttribute(data_n, "dmispec", "7.19.3"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x05) { dmixml_AddTextContent(data_n, "%s", operation[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2797,32 +3385,45 @@ void dmi_32bit_memory_error_address(xmlNode *node, char *tagname, u32 code) } /******************************************************************************* -** 3.3.20 Memory Array Mapped Address (Type 19) +** 7.20 Memory Array Mapped Address (Type 19) */ void dmi_mapped_address_size(xmlNode *node, u32 code) { xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "RangeSize", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.19.2"); + dmixml_AddAttribute(data_n, "dmispec", "7.20"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code == 0) { dmixml_AddAttribute(data_n, "invalid", "1"); - } else if((code & 0x000FFFFF) == 0) { - dmixml_AddAttribute(data_n, "unit", "GB"); - dmixml_AddTextContent(data_n, "%i", code >> 20); - } else if((code & 0x000003FF) == 0) { - dmixml_AddAttribute(data_n, "unit", "MB"); - dmixml_AddTextContent(data_n, "%i", code >> 10); } else { - dmixml_AddAttribute(data_n, "unit", "KB"); - dmixml_AddTextContent(data_n, "%i", code); + u64 size; + + size.h = 0; + size.l = code; + dmi_add_memory_size(data_n, size, 1); + } +} + +void dmi_mapped_address_extended_size(xmlNode *node, u64 start, u64 end) +{ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "RangeSize", NULL); + assert( data_n != NULL ); + dmixml_AddAttribute(data_n, "dmispec", "7.20"); + dmixml_AddAttribute(data_n, "mode", "extended"); + dmixml_AddAttribute(data_n, "start_address", "0x%08x%08x", start.h, start.l); + dmixml_AddAttribute(data_n, "end_address", "0x%08x%08x", end.h, end.l); + + if(start.h == end.h && start.l == end.l) { + dmixml_AddAttribute(data_n, "invalid", "1"); + } else { + dmi_add_memory_size(data_n, u64_range(start, end), 0); } } /******************************************************************************* -** 3.3.21 Memory Device Mapped Address (Type 20) +** 7.21 Memory Device Mapped Address (Type 20) */ void dmi_mapped_address_row_position(xmlNode *node, u8 code) @@ -2831,7 +3432,7 @@ void dmi_mapped_address_row_position(xmlNode *node, u8 code) assert( data_n != NULL ); if(code == 0) { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } else if(code == 0xFF) { dmixml_AddAttribute(data_n, "unknown", "1"); } else { @@ -2864,12 +3465,12 @@ void dmi_mapped_address_interleaved_data_depth(xmlNode *node, u8 code) } /******************************************************************************* -** 3.3.22 Built-in Pointing Device (Type 21) +** 7.22 Built-in Pointing Device (Type 21) */ void dmi_pointing_device_type(xmlNode *node, u8 code) { - /* 3.3.22.1 */ + /* 7.22.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -2883,19 +3484,19 @@ void dmi_pointing_device_type(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "DeviceType", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.22.1"); + dmixml_AddAttribute(data_n, "dmispec", "7.22.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x09) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_pointing_device_interface(xmlNode *node, u8 code) { - /* 3.3.22.2 */ + /* 7.22.2 */ static const char *interface[] = { "Other", /* 0x01 */ "Unknown", @@ -2913,7 +3514,7 @@ void dmi_pointing_device_interface(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "DeviceInterface", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.22.2"); + dmixml_AddAttribute(data_n, "dmispec", "7.22.2"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x08) { @@ -2921,17 +3522,17 @@ void dmi_pointing_device_interface(xmlNode *node, u8 code) } else if(code >= 0xA0 && code <= 0xA2) { dmixml_AddTextContent(data_n, interface_0xA0[code - 0xA0]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } /******************************************************************************* -** 3.3.23 Portable Battery (Type 22) +** 7.23 Portable Battery (Type 22) */ void dmi_battery_chemistry(xmlNode *node, u8 code) { - /* 3.3.23.1 */ + /* 7.23.1 */ static const char *chemistry[] = { "Other", /* 0x01 */ "Unknown", @@ -2944,13 +3545,13 @@ void dmi_battery_chemistry(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "BatteryChemistry", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.22.2"); + dmixml_AddAttribute(data_n, "dmispec", "7.22.2"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x08) { dmixml_AddTextContent(data_n, "%s", chemistry[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2993,7 +3594,7 @@ void dmi_battery_maximum_error(xmlNode *node, u8 code) } /******************************************************************************* -** 3.3.24 System Reset (Type 23) +** 7.24 System Reset (Type 23) */ void dmi_system_reset_boot_option(xmlNode *node, const char *tagname, u8 code) @@ -3010,7 +3611,7 @@ void dmi_system_reset_boot_option(xmlNode *node, const char *tagname, u8 code) if( (code > 0) && (code < 4) ) { dmixml_AddTextContent(data_n, option[code - 0x1]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3042,7 +3643,7 @@ void dmi_system_reset_timer(xmlNode *node, const char *tagname, u16 code) } /******************************************************************************* - * 3.3.25 Hardware Security (Type 24) + * 7.25 Hardware Security (Type 24) */ void dmi_hardware_security_status(xmlNode *node, const char *tagname, u8 code) @@ -3060,7 +3661,7 @@ void dmi_hardware_security_status(xmlNode *node, const char *tagname, u8 code) } /******************************************************************************* -** 3.3.26 System Power Controls (Type 25) +** 7.26 System Power Controls (Type 25) */ #define DMI_POWER_CTRL_TIME_STR(dest, variant, data) \ @@ -3069,11 +3670,11 @@ void dmi_hardware_security_status(xmlNode *node, const char *tagname, u8 code) void dmi_power_controls_power_on(xmlNode *node, const char *tagname, const u8 * p) { - /* 3.3.26.1 */ + /* 7.26.1 */ char timestr[5][5]; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) tagname, NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.26.1"); + dmixml_AddAttribute(data_n, "dmispec", "7.26.1"); dmixml_AddAttribute(data_n, "flags", "0x%08x", p); DMI_POWER_CTRL_TIME_STR(timestr[0], dmi_bcd_range(p[0], 0x01, 0x12), p[0]) @@ -3088,12 +3689,12 @@ void dmi_power_controls_power_on(xmlNode *node, const char *tagname, const u8 * } /******************************************************************************* -* 3.3.27 Voltage Probe (Type 26) +* 7.27 Voltage Probe (Type 26) */ void dmi_voltage_probe_location(xmlNode *node, u8 code) { - /* 3.3.27.1 */ + /* 7.27.1 */ static const char *location[] = { "Other", /* 0x01 */ "Unknown", @@ -3109,19 +3710,19 @@ void dmi_voltage_probe_location(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Location", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.27.1"); + dmixml_AddAttribute(data_n, "dmispec", "7.27.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x0B) { dmixml_AddTextContent(data_n, "%s", location[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_probe_status(xmlNode *node, u8 code) { - /* 3.3.27.1 */ + /* 7.27.1 */ static const char *status[] = { "Other", /* 0x01 */ "Unknown", @@ -3132,13 +3733,13 @@ void dmi_probe_status(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Status", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.27.1"); + dmixml_AddAttribute(data_n, "dmispec", "7.27.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x06) { dmixml_AddTextContent(data_n, "%s", status[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3185,12 +3786,12 @@ void dmi_probe_accuracy(xmlNode *node, u16 code) } /******************************************************************************* -** 3.3.28 Cooling Device (Type 27) +** 7.28 Cooling Device (Type 27) */ void dmi_cooling_device_type(xmlNode *node, u8 code) { - /* 3.3.28.1 */ + /* 7.28.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -3208,7 +3809,7 @@ void dmi_cooling_device_type(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Type", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.28.1", code); + dmixml_AddAttribute(data_n, "dmispec", "7.28.1", code); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x09) { @@ -3216,7 +3817,7 @@ void dmi_cooling_device_type(xmlNode *node, u8 code) } else if(code >= 0x10 && code <= 0x11) { dmixml_AddTextContent(data_n, "%s", type_0x10[code - 0x10]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3235,12 +3836,12 @@ void dmi_cooling_device_speed(xmlNode *node, u16 code) } /******************************************************************************* -** 3.3.29 Temperature Probe (Type 28) +** 7.29 Temperature Probe (Type 28) */ void dmi_temperature_probe_location(xmlNode *node, u8 code) { - /* 3.3.29.1 */ + /* 7.29.1 */ static const char *location[] = { "Other", /* 0x01 */ "Unknown", @@ -3260,13 +3861,13 @@ void dmi_temperature_probe_location(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Location", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.29.1", code); + dmixml_AddAttribute(data_n, "dmispec", "7.29.1", code); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x0F) { dmixml_AddTextContent(data_n, "%s", location[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3299,7 +3900,7 @@ void dmi_temperature_probe_resolution(xmlNode *node, u16 code) } /******************************************************************************* -** 3.3.30 Electrical Current Probe (Type 29) +** 7.30 Electrical Current Probe (Type 29) */ void dmi_current_probe_value(xmlNode *node, const char *tagname, u16 code) @@ -3331,7 +3932,7 @@ void dmi_current_probe_resolution(xmlNode *node, u16 code) } /******************************************************************************* -** 3.3.33 System Boot Information (Type 32) +** 7.33 System Boot Information (Type 32) */ void dmi_system_boot_status(xmlNode *node, u8 code) @@ -3358,12 +3959,12 @@ void dmi_system_boot_status(xmlNode *node, u8 code) } else if(code >= 192) { dmixml_AddTextContent(data_n, "Product-specific"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } /******************************************************************************* -** 3.3.34 64-bit Memory Error Information (Type 33) +** 7.34 64-bit Memory Error Information (Type 33) */ void dmi_64bit_memory_error_address(xmlNode *node, const char *tagname, u64 code) @@ -3379,12 +3980,27 @@ void dmi_64bit_memory_error_address(xmlNode *node, const char *tagname, u64 code } /******************************************************************************* -** 3.3.35 Management Device (Type 34) +** 7.35 Management Device (Type 34) */ +/* + * Several boards have a bug where some type 34 structures have their + * length incorrectly set to 0x10 instead of 0x0B. This causes the + * first 5 characters of the device name to be trimmed. It's easy to + * check and fix, so do it, but warn. + */ +void dmi_fixup_type_34(struct dmi_header *h) +{ + u8 *p = h->data; + + if (h->length == 0x10 && is_printable(p + 0x0B, 0x10 - 0x0B)) { + h->length = 0x0B; + } +} + void dmi_management_device_type(xmlNode *node, u8 code) { - /* 3.3.35.1 */ + /* 7.35.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -3402,19 +4018,19 @@ void dmi_management_device_type(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Type", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.35.1", code); + dmixml_AddAttribute(data_n, "dmispec", "7.35.1", code); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x0D) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_management_device_address_type(xmlNode *node, u8 code) { - /* 3.3.35.2 */ + /* 7.35.2 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -3424,23 +4040,23 @@ void dmi_management_device_address_type(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "AddressType", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.35.2", code); + dmixml_AddAttribute(data_n, "dmispec", "7.35.2", code); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x05) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } /******************************************************************************* -** 3.3.38 Memory Channel (Type 37) +** 7.38 Memory Channel (Type 37) */ void dmi_memory_channel_type(xmlNode *node, u8 code) { - /* 3.3.38.1 */ + /* 7.38.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -3449,13 +4065,13 @@ void dmi_memory_channel_type(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Type", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.38.1", code); + dmixml_AddAttribute(data_n, "dmispec", "7.38.1", code); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x04) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3473,12 +4089,12 @@ void dmi_memory_channel_devices(xmlNode *node, u8 count, const u8 * p) } /******************************************************************************* -** 3.3.39 IPMI Device Information (Type 38) +** 7.39 IPMI Device Information (Type 38) */ void dmi_ipmi_interface_type(xmlNode *node, u8 code) { - /* 3.3.39.1 and IPMI 2.0, appendix C1, table C1-2 */ + /* 7.39.1 and IPMI 2.0, appendix C1, table C1-2 */ static const char *type[] = { "Unknown", /* 0x00 */ "KCS (Keyboard Control Style)", @@ -3488,13 +4104,13 @@ void dmi_ipmi_interface_type(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "InterfaceType", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.39.1", code); + dmixml_AddAttribute(data_n, "dmispec", "7.39.1", code); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code <= 0x04) { dmixml_AddTextContent(data_n, "%s", type[code]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3530,12 +4146,12 @@ void dmi_ipmi_register_spacing(xmlNode *node, u8 code) if(code <= 0x02) { dmixml_AddTextContent(data_n, "%s", spacing[code]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } /******************************************************************************* -** 3.3.40 System Power Supply (Type 39) +** 7.40 System Power Supply (Type 39) */ void dmi_power_supply_power(xmlNode *node, u16 code) @@ -3554,7 +4170,7 @@ void dmi_power_supply_power(xmlNode *node, u16 code) void dmi_power_supply_type(xmlNode *node, u8 code) { - /* 3.3.40.1 */ + /* 7.40.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", @@ -3567,19 +4183,19 @@ void dmi_power_supply_type(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Type", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.40.1"); + dmixml_AddAttribute(data_n, "dmispec", "7.40.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x08) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_power_supply_status(xmlNode *node, u8 code) { - /* 3.3.40.1 */ + /* 7.40.1 */ static const char *status[] = { "Other", /* 0x01 */ "Unknown", @@ -3589,20 +4205,20 @@ void dmi_power_supply_status(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Status", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.40.1"); + dmixml_AddAttribute(data_n, "dmispec", "7.40.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); dmixml_AddAttribute(data_n, "present", "1"); if(code >= 0x01 && code <= 0x05) { dmixml_AddTextContent(data_n, "%s", status[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } void dmi_power_supply_range_switching(xmlNode *node, u8 code) { - /* 3.3.40.1 */ + /* 7.40.1 */ static const char *switching[] = { "Other", /* 0x01 */ "Unknown", @@ -3613,18 +4229,18 @@ void dmi_power_supply_range_switching(xmlNode *node, u8 code) }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "VoltageRangeSwitching", NULL); assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "3.3.40.1"); + dmixml_AddAttribute(data_n, "dmispec", "7.40.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if(code >= 0x01 && code <= 0x06) { dmixml_AddTextContent(data_n, "%s", switching[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } /* -** 3.3.41 Additional Information (Type 40) +** 7.41 Additional Information (Type 40) ** ** Proper support of this entry type would require redesigning a large part of ** the code, so I am waiting to see actual implementations of it to decide @@ -3641,7 +4257,7 @@ void dmi_additional_info(xmlNode *node, const struct dmi_header *h) assert( node != NULL ); for(i = 0; i < count; i++) { - xmlNode *data_n = NULL, *str_n = NULL, *val_n = NULL; + xmlNode *data_n = NULL, *val_n = NULL; /* Check for short entries */ if(h->length < offset + 1) { @@ -3659,7 +4275,7 @@ void dmi_additional_info(xmlNode *node, const struct dmi_header *h) dmixml_AddAttribute(data_n, "ReferenceHandle", "0x%04x", WORD(p + 0x01)); dmixml_AddAttribute(data_n, "ReferenceOffset", "0x%02x", p[0x03]); - str_n = dmixml_AddTextChild(data_n, "String", "%s", dmi_string(h, p[0x04])); + dmixml_AddDMIstring(data_n, "String", h, p[0x04]); switch (length - 0x05) { case 1: @@ -3682,6 +4298,502 @@ void dmi_additional_info(xmlNode *node, const struct dmi_header *h) } } +/* + * 7.43 Management Controller Host Interface (Type 42) + */ + +xmlNode * dmi_management_controller_host_type(xmlNode *node, u8 code) +{ + /* DMTF DSP0239 (MCTP) version 1.1.0 */ + static const char *type[] = { + "KCS: Keyboard Controller Style", /* 0x02 */ + "8250 UART Register Compatible", + "16450 UART Register Compatible", + "16550/16550A UART Register Compatible", + "16650/16650A UART Register Compatible", + "16750/16750A UART Register Compatible", + "16850/16850A UART Register Compatible" /* 0x08 */ + }; + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "ManagementControllerHost", NULL); + assert( data_n != NULL ); + + dmixml_AddAttribute(data_n, "dmispec", "7.43"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + if (code >= 0x02 && code <= 0x08) { + dmixml_AddTextChild(data_n, "Type", "%s", type[code - 0x02]); + } else if (code == 0x40) { + dmixml_AddTextChild(data_n, "Type", "Network"); + } else if (code == 0xF0) { + dmixml_AddTextChild(data_n, "Type", "OEM"); + } else { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } + return data_n; +} + +//===================below should be checked========================== + +/* + * 7.43.2: Protocol Record Types + */ +void dmi_protocol_record_type(xmlNode *node, u8 code) +{ + const char *protocol[] = { + "Reserved", /* 0x0 */ + "Reserved", + "IPMI", + "MCTP", + "Redfish over IP" /* 0x4 */ + }; + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"ProtocolRecordType", NULL); + assert(data_n != NULL); + + dmixml_AddAttribute(data_n, "dmispec", "7.43.2"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + if (code <= 0x4) { + dmixml_AddTextContent(data_n, "%s", protocol[code]); + } else if (code == 0xF0) { + dmixml_AddTextContent(data_n, "OEM"); + } else { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } +} + +/* + * DSP0270: 8.6: Protocol IP Assignment types + */ +void dmi_protocol_assignment_type(xmlNode *node, u8 type) +{ + const char *assignment[] = { + "Unknown", /* 0x0 */ + "Static", + "DHCP", + "AutoConf", + "Host Selected" /* 0x4 */ + }; + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"ProtocolAssignmentType", NULL); + assert(data_n != NULL); + + if (type <= 0x4){ + dmixml_AddTextContent(data_n, "%s", assignment[type]); + } else { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } +} + +/* + * DSP0270: 8.6: Protocol IP Address type + */ +void dmi_address_type(xmlNode *node, u8 type) +{ + const char *addressformat[] = { + "Unknown", /* 0x0 */ + "IPv4", + "IPv6" /* 0x2 */ + }; + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"AddressType", NULL); + assert(data_n != NULL); + + if (type <= 0x2) { + dmixml_AddTextContent(data_n, "Type", "%s", addressformat[type]); + } else { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } +} + +/* + * DSP0270: 8.6 Protocol Address decode + */ +void dmi_address_decode(xmlNode *node, u8 *data, char *storage, u8 addrtype) +{ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"AdressDecode", NULL); + assert(data_n != NULL); + + if (addrtype == 0x1) {/* IPv4 */ + dmixml_AddAttribute(data_n, "Type", "ipv4"); + dmixml_AddTextContent(data_n, "%s", inet_ntop(AF_INET, data, storage, 64)); + } else if (addrtype == 0x2) {/* IPv6 */ + dmixml_AddAttribute(data_n, "Type", "ipv6"); + dmixml_AddTextContent(data_n, "%s", inet_ntop(AF_INET6, data, storage, 64)); + } else { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } +} + +/* + * DSP0270: 8.5: Parse the protocol record format + */ +void dmi_parse_protocol_record(xmlNode *node, u8 *rec) +{ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"ParseProtocolRecord", NULL); + assert(data_n != NULL); + + u8 rid; + u8 rlen; + u8 *rdata; + char buf[64]; + u8 assign_val; + u8 addrtype; + u8 hlen; + // const char *addrstr; + const char *hname; + // char attr[38]; + + /* DSP0270: 8.5: Protocol Identifier */ + rid = rec[0x0]; + /* DSP0270: 8.5: Protocol Record Length */ + rlen = rec[0x1]; + /* DSP0270: 8.5: Protocol Record Data */ + rdata = &rec[0x2]; + + dmixml_AddAttribute(data_n, "ProtocolID", "%02x", rid); + dmi_protocol_record_type(data_n, rid); + + /* + * Don't decode anything other than Redfish for now + * Note 0x4 is Redfish over IP in 7.43.2 + * and DSP0270: 8.5 + */ + if (rid != 0x4) { + return; + } + + /* + * Ensure that the protocol record is of sufficient length + * For RedFish that means rlen must be at least 91 bytes + * other protcols will need different length checks + */ + if (rlen < 91) { + return; + } + + /* + * DSP0270: 8.6: Redfish Over IP Service UUID + * Note: ver is hardcoded to 0x311 here just for + * convenience. It could get passed from the SMBIOS + * header, but that's a lot of passing of pointers just + * to get that info, and the only thing it is used for is + * to determine the endianess of the field. Since we only + * do this parsing on versions of SMBIOS after 3.1.1, and the + * endianess of the field is always little after version 2.6.0 + * we can just pick a sufficiently recent version here. + */ + xmlNode *subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "ServiceUUID"); + dmi_system_uuid(subdev_n, &rdata[0], 0x311); + subdev_n = NULL; + + /* + * DSP0270: 8.6: Redfish Over IP Host IP Assignment Type + * Note, using decimal indicies here, as the DSP0270 + * uses decimal, so as to make it more comparable + */ + assign_val = rdata[16]; + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "HostIPAssignmentType"); + dmi_protocol_assignment_type(subdev_n, assign_val); + subdev_n = NULL; + + /* DSP0270: 8.6: Redfish Over IP Host Address format */ + addrtype = rdata[17]; + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "HostIPAddressFormat"); + dmi_address_type(subdev_n, addrtype); + subdev_n = NULL; + + /* DSP0270: 8.6 IP Assignment types */ + /* We only use the Host IP Address and Mask if the assignment type is static */ + if (assign_val == 0x1 || assign_val == 0x3) { + /* DSP0270: 8.6: the Host IPv[4|6] Address */ + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "Address"); + dmi_address_decode(subdev_n, &rdata[18], buf, addrtype); + subdev_n = NULL; + + /* DSP0270: 8.6: Prints the Host IPv[4|6] Mask */ + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "Mask"); + dmi_address_decode(subdev_n, &rdata[34], buf, addrtype); + subdev_n = NULL; + } + + /* DSP0270: 8.6: Get the Redfish Service IP Discovery Type */ + assign_val = rdata[50]; + + /* Redfish Service IP Discovery type mirrors Host IP Assignment type */ + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServiceIPAddressType"); + dmi_protocol_assignment_type(subdev_n, assign_val); + subdev_n = NULL; + + /* DSP0270: 8.6: Get the Redfish Service IP Address Format */ + addrtype = rdata[51]; + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServiceIPAddressFormat"); + dmi_address_type(subdev_n, addrtype); + subdev_n = NULL; + + if (assign_val == 0x1 || assign_val == 0x3) { + u16 port; + u32 vlan; + + /* DSP0270: 8.6: Prints the Redfish IPv[4|6] Service Address */ + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServiceAddress"); + dmi_address_decode(subdev_n, &rdata[52], buf, addrtype); + subdev_n = NULL; + + /* DSP0270: 8.6: Prints the Redfish IPv[4|6] Service Mask */ + xmlNode *subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServiceMask"); + dmi_address_decode(subdev_n, &rdata[68], buf, addrtype); + subdev_n = NULL; + + /* DSP0270: 8.6: Redfish vlan and port info */ + port = WORD(&rdata[84]); + vlan = DWORD(&rdata[86]); + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServicePort"); + dmixml_AddAttribute(subdev_n, "RedfishServicePort", "%hu", port); + subdev_n = NULL; + + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServiceVlan"); + dmixml_AddAttribute(subdev_n, "RedfishServiceVlan", "%u", vlan); + subdev_n = NULL; + } + + /* DSP0270: 8.6: Redfish host length and name */ + hlen = rdata[90]; + + /* + * DSP0270: 8.6: The length of the host string + 91 (the minimum + * size of a protocol record) cannot exceed the record length + * (rec[0x1]) + */ + hname = (const char *)&rdata[91]; + if (hlen + 91 > rlen) { + hname = OUT_OF_SPEC; + hlen = strlen(OUT_OF_SPEC); + } + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServiceHostname"); + dmixml_AddTextContent(subdev_n, "%.*s", hlen, hname); + subdev_n = NULL; +} + +/* + * DSP0270: 8.3: Device type ennumeration + */ +void dmi_parse_device_type(xmlNode *node, u8 type) +{ + const char *devname[] = { + "USB", /* 0x2 */ + "PCI/PCIe" /* 0x3 */ + }; + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"ParseDeviceType", NULL); + assert(data_n != NULL); + + if (type >= 0x2 && type <= 0x3) { + dmixml_AddTextContent(data_n, "Type", "%s", devname[type - 0x2]); + } else if (type >= 0x80) { + dmixml_AddTextContent(data_n, "Type", "OEM"); + } else { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } +} + +void dmi_parse_controller_structure(xmlNode *node, struct dmi_header *h) +{ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "ControllerStructure", NULL); + assert(data_n != NULL); + + int i; + u8 *data = h->data; + /* Host interface type */ + u8 type; + /* Host Interface specific data length */ + u8 len; + u8 count; + u32 total_read; + + /* + * Minimum length of this struct is 0xB bytes + */ + if (h->length < 0xB) + return; + + /* + * Also need to ensure that the interface specific data length + * plus the size of the structure to that point don't exceed + * the defined length of the structure, or we will overrun its + * bounds + */ + len = data[0x5]; + total_read = len + 0x6; + + if (total_read > h->length) { + return; + } + type = data[0x4]; + + dmixml_AddAttribute(data_n, "Type", "%s", "HostInterfaceType"); + dmi_management_controller_host_type(data_n, type); + + /* + * The following decodes are code for Network interface host types only + * As defined in DSP0270 + */ + if (type != 0x40) { + return; + } + + if (len != 0) { + /* DSP0270: 8.3 Table 2: Device Type */ + type = data[0x6]; + + dmi_parse_device_type(data_n, type); + + if (type == 0x2 && len >= 5) { + /* USB Device Type - need at least 6 bytes */ + u8 *usbdata = &data[0x7]; + + /* USB Device Descriptor: idVendor */ + dmixml_AddTextContent(data_n, "idVendor", "0x%04x", WORD(&usbdata[0x0])); + + /* USB Device Descriptor: idProduct */ + dmixml_AddTextContent(data_n, "idProduct", "0x%04x", WORD(&usbdata[0x2])); + + /* + * USB Serial number is here, but its useless, don't + * bother decoding it + */ + } else if (type == 0x3 && len >= 9) { + /* PCI Device Type - Need at least 8 bytes */ + u8 *pcidata = &data[0x7]; + + /* PCI Device Descriptor: VendorID */ + dmixml_AddTextContent(data_n, "VendorID", "0x%04x", WORD(&pcidata[0x0])); + + /* PCI Device Descriptor: DeviceID */ + dmixml_AddTextContent(data_n, "DeviceID", "0x%04x", WORD(&pcidata[0x2])); + + /* PCI Device Descriptor: PCI SubvendorID */ + dmixml_AddTextContent(data_n, "SubVendorID", "0x%04x", WORD(&pcidata[0x4])); + + /* PCI Device Descriptor: PCI SubdeviceID */ + dmixml_AddTextContent(data_n, "SubDeviceID", "0x%04x", WORD(&pcidata[0x6])); + } else if (type == 0x4 && len >= 5) { + /* OEM Device Type - Need at least 4 bytes */ + u8 *oemdata = &data[0x7]; + + /* OEM Device Descriptor: IANA */ + dmixml_AddTextContent(data_n, "VendorID", "0x%02x:0x%02x:0x%02x:0x%02x", oemdata[0x0], oemdata[0x1], oemdata[0x2], oemdata[0x3]); + } + /* Don't mess with unknown types for now */ + } + + /* + * DSP0270: 8.2 and 8.5: Protocol record count and protocol records + * Move to the Protocol Count. + */ + data = &data[total_read]; + + /* + * We've validated up to 0x6 + len bytes, but we need to validate + * the next byte below, the count value. + */ + total_read++; + if (total_read > h->length) { + fprintf(stderr, "Total read length %d exceeds total structure length %d (handle 0x%04hx)\n", total_read, h->length, h->handle); + return; + } + + /* Get the protocol records count */ + count = data[0x0]; + if (count) { + u8 *rec = &data[0x1]; + for (i = 0; i < count; i++) { + /* + * Need to ensure that this record doesn't overrun + * the total length of the type 42 struct. Note the +2 + * is added for the two leading bytes of a protocol + * record representing the type and length bytes. + */ + total_read += rec[1] + 2; + if (total_read > h->length) { + fprintf(stderr, "Total read length %d exceeds total structure length %d (handle 0x%04hx, record %d)\n", total_read, h->length, h->handle, i + 1); + return; + } + + dmi_parse_protocol_record(data_n, rec); + + /* + * DSP0270: 8.6 + * Each record is rec[1] bytes long, starting at the + * data byte immediately following the length field. + * That means we need to add the byte for the rec id, + * the byte for the length field, and the value of the + * length field itself. + */ + rec += rec[1] + 2; + } + } +} + +/* + * 7.44 TPM Device (Type 43) + */ +void dmi_tpm_vendor_id(xmlNode *node, const u8 *p) +{ + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"TpmVendorId", NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "dmispec", "7.44"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", p); + + char vendor_id[5]; + int i; + + /* ASCII filtering */ + for (i = 0; i < 4 && p[i] != 0; i++) { + if (p[i] < 32 || p[i] >= 127) + vendor_id[i] = '.'; + else + vendor_id[i] = p[i]; + } + + /* Terminate the string */ + vendor_id[i] = '\0'; + + dmixml_AddTextContent(data_n, "VendorId", "%s", vendor_id); +} + +void dmi_tpm_characteristics(xmlNode *node, u64 code) +{ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "TpmCharacteristics", NULL); + assert(data_n != NULL); + + /* 7.1.1 */ + static const char *characteristics[] = { + "TPM Device characteristics not supported", /* 2 */ + "Family configurable via firmware update", + "Family configurable via platform software support", + "Family configurable via OEM proprietary mechanism" /* 5 */ + }; + int i; + + /* + * This isn't very clear what this bit is supposed to mean + */ + if (code.l & (1 << 2)) { + dmixml_AddTextContent(data_n, "%s", characteristics[0]); + } + + for (i = 3; i <= 5; i++) + if (code.l & (1 << i)) { + xmlNode *dev_n = xmlNewChild(data_n, NULL, (xmlChar *) "Device", NULL); + dmixml_AddAttribute(dev_n, "index", "%i", i); + dmixml_AddTextContent(dev_n, "%s", characteristics[i - 2]); + dev_n = NULL; + } +} + /******************************************************************************* ** Main */ @@ -3701,14 +4813,14 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmixml_AddTextChild(sect_n, "DMIdescription", "%s", dmiMajor->desc); switch (h->type) { - case 0: /* 3.3.1 BIOS Information */ + case 0: /* 7.1 BIOS Information */ if(h->length < 0x12) { break; } - dmixml_AddTextChild(sect_n, "Vendor", "%s", dmi_string(h, data[0x04])); - dmixml_AddTextChild(sect_n, "Version", "%s", dmi_string(h, data[0x05])); - dmixml_AddTextChild(sect_n, "ReleaseDate", "%s", dmi_string(h, data[0x08])); + dmixml_AddDMIstring(sect_n, "Vendor", h, data[0x04]); + dmixml_AddDMIstring(sect_n, "Version", h, data[0x05]); + dmixml_AddDMIstring(sect_n, "ReleaseDate", h, data[0x08]); /* * On IA-64, the BIOS base address will read 0 because @@ -3721,8 +4833,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_bios_runtime_size(sect_n, (0x10000 - WORD(data + 0x06)) << 4); } - sub_n = dmixml_AddTextChild(sect_n, "ROMsize", "%i", (data[0x09] + 1) << 6); - dmixml_AddAttribute(sub_n, "unit", "KB"); + dmi_bios_rom_size(sub_n, data[0x09], h->length < 0x1A ? 16 : WORD(data + 0x18)); sub_n = NULL; sub_n = xmlNewChild(sect_n, NULL, (xmlChar *) "Characteristics", NULL); @@ -3767,15 +4878,15 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade } break; - case 1: /* 3.3.2 System Information */ + case 1: /* 7.2 System Information */ if(h->length < 0x08) { break; } - dmixml_AddTextChild(sect_n, "Manufacturer", "%s", dmi_string(h, data[0x04])); - dmixml_AddTextChild(sect_n, "ProductName", "%s", dmi_string(h, data[0x05])); - dmixml_AddTextChild(sect_n, "Version", "%s", dmi_string(h, data[0x06])); - dmixml_AddTextChild(sect_n, "SerialNumber", "%s", dmi_string(h, data[0x07])); + dmixml_AddDMIstring(sect_n, "Manufacturer", h, data[0x04]); + dmixml_AddDMIstring(sect_n, "ProductName", h, data[0x05]); + dmixml_AddDMIstring(sect_n, "Version", h, data[0x06]); + dmixml_AddDMIstring(sect_n, "SerialNumber", h, data[0x07]); if(h->length < 0x19) { break; @@ -3789,29 +4900,29 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade break; } - dmixml_AddTextChild(sect_n, "SKUnumber", "%s", dmi_string(h, data[0x19])); - dmixml_AddTextChild(sect_n, "Family", "%s", dmi_string(h, data[0x1A])); + dmixml_AddDMIstring(sect_n, "SKUnumber", h, data[0x19]); + dmixml_AddDMIstring(sect_n, "Family", h, data[0x1A]); break; - case 2: /* 3.3.3 Base Board Information */ + case 2: /* 7.3 Base Board Information */ if(h->length < 0x08) { break; } - dmixml_AddTextChild(sect_n, "Manufacturer", "%s", dmi_string(h, data[0x04])); - dmixml_AddTextChild(sect_n, "ProductName", "%s", dmi_string(h, data[0x05])); - dmixml_AddTextChild(sect_n, "Version", "%s", dmi_string(h, data[0x06])); - dmixml_AddTextChild(sect_n, "SerialNumber", "%s", dmi_string(h, data[0x07])); + dmixml_AddDMIstring(sect_n, "Manufacturer", h, data[0x04]); + dmixml_AddDMIstring(sect_n, "ProductName", h, data[0x05]); + dmixml_AddDMIstring(sect_n, "Version", h, data[0x06]); + dmixml_AddDMIstring(sect_n, "SerialNumber", h, data[0x07]); if(h->length < 0x0F) { break; } - dmixml_AddTextChild(sect_n, "AssetTag", "%s", dmi_string(h, data[0x08])); + dmixml_AddDMIstring(sect_n, "AssetTag", h, data[0x08]); dmi_base_board_features(sect_n, data[0x09]); - dmixml_AddTextChild(sect_n, "ChassisLocation", "%s", dmi_string(h, data[0x0A])); + dmixml_AddDMIstring(sect_n, "ChassisLocation", h, data[0x0A]); dmixml_AddTextChild(sect_n, "ChassisHandle", "0x%04x", WORD(data + 0x0B)); dmi_base_board_type(sect_n, "Type", data[0x0D]); @@ -3823,17 +4934,17 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_base_board_handles(sect_n, data[0x0E], data + 0x0F); break; - case 3: /* 3.3.4 Chassis Information */ + case 3: /* 7.4 Chassis Information */ if(h->length < 0x09) { break; } - dmixml_AddTextChild(sect_n, "Manufacturer", "%s", dmi_string(h, data[0x04])); - dmi_chassis_type(sect_n, data[0x05] & 0x7F); + dmixml_AddDMIstring(sect_n, "Manufacturer", h, data[0x04]); + dmi_chassis_type(sect_n, data[0x05]); dmi_chassis_lock(sect_n, data[0x05] >> 7); - dmixml_AddTextChild(sect_n, "Version", "%s", dmi_string(h, data[0x06])); - dmixml_AddTextChild(sect_n, "SerialNumber", "%s", dmi_string(h, data[0x07])); - dmixml_AddTextChild(sect_n, "AssetTag", "%s", dmi_string(h, data[0x08])); + dmixml_AddDMIstring(sect_n, "Version", h, data[0x06]); + dmixml_AddDMIstring(sect_n, "SerialNumber", h, data[0x07]); + dmixml_AddDMIstring(sect_n, "AssetTag", h, data[0x08]); if(h->length < 0x0D) { break; @@ -3867,24 +4978,29 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade } dmi_chassis_elements(sect_n, data[0x13], data[0x14], data + 0x15); + if (h->length < 0x16 + data[0x13] * data[0x14]) { + break; + } + dmixml_AddDMIstring(sect_n, "SKUnumber", h, data[0x15 + data[0x13] * data[0x14]]); + break; - case 4: /* 3.3.5 Processor Information */ + case 4: /* 7.5 Processor Information */ if(h->length < 0x1A) { break; } - dmixml_AddTextChild(sect_n, "SocketDesignation", "%s", dmi_string(h, data[0x04])); + dmixml_AddDMIstring(sect_n, "SocketDesignation", h, data[0x04]); dmi_processor_type(sect_n, data[0x05]); - dmi_processor_family(sect_n, h); + dmi_processor_family(sect_n, h, ver); - dmi_processor_id(sect_n, data[0x06], data + 8, dmi_string(h, data[0x10])); + dmi_processor_id(sect_n, h); sub_n = xmlNewChild(sect_n, NULL, (xmlChar *) "Manufacturer", NULL); assert( sub_n != NULL ); - dmixml_AddTextChild(sub_n, "Vendor", dmi_string(h, data[0x07])); + dmixml_AddDMIstring(sub_n, "Vendor", h, data[0x07]); - dmixml_AddTextChild(sub_n, "Version", dmi_string(h, data[0x10])); + dmixml_AddDMIstring(sub_n, "Version", h, data[0x10]); sub_n = NULL; dmi_processor_voltage(sect_n, data[0x11]); @@ -3950,9 +5066,9 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade break; } - dmixml_AddTextChild(sect_n, "SerialNumber", "%s", dmi_string(h, data[0x20])); - dmixml_AddTextChild(sect_n, "AssetTag", "%s", dmi_string(h, data[0x21])); - dmixml_AddTextChild(sect_n, "PartNumber", "%s", dmi_string(h, data[0x22])); + dmixml_AddDMIstring(sect_n, "SerialNumber", h, data[0x20]); + dmixml_AddDMIstring(sect_n, "AssetTag", h, data[0x21]); + dmixml_AddDMIstring(sect_n, "PartNumber", h, data[0x22]); if(h->length < 0x28) { break; @@ -3977,7 +5093,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade sub_n = NULL; break; - case 5: /* 3.3.6 Memory Controller Information */ + case 5: /* 7.6 Memory Controller Information */ if(h->length < 0x0F) { break; } @@ -4020,12 +5136,12 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade data[0x0F + data[0x0E] * sizeof(u16)]); break; - case 6: /* 3.3.7 Memory Module Information */ + case 6: /* 7.7 Memory Module Information */ if(h->length < 0x0C) { break; } - dmixml_AddTextChild(sect_n, "SocketDesignation", "%s", dmi_string(h, data[0x04])); + dmixml_AddDMIstring(sect_n, "SocketDesignation", h, data[0x04]); dmi_memory_module_connections(sect_n, data[0x05]); dmi_memory_module_speed(sect_n, "ModuleSpeed", data[0x06]); dmi_memory_module_types(sect_n, "Type", WORD(data + 0x07)); @@ -4035,12 +5151,12 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_memory_module_error(sect_n, data[0x0B]); break; - case 7: /* 3.3.8 Cache Information */ + case 7: /* 7.8 Cache Information */ if(h->length < 0x0F) { break; } - dmixml_AddTextChild(sect_n, "SocketDesignation", dmi_string(h, data[0x04])); + dmixml_AddDMIstring(sect_n, "SocketDesignation", h, data[0x04]); dmixml_AddAttribute(sect_n, "Enabled", "%i", (WORD(data + 0x05) & 0x0080 ? 1 : 0)); dmixml_AddAttribute(sect_n, "Socketed", "%i", (WORD(data + 0x05) & 0x0008 ? 1 : 0)); dmixml_AddAttribute(sect_n, "Level", "%ld", ((WORD(data + 0x05) & 0x0007) + 1)); @@ -4051,8 +5167,16 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade sub_n = NULL; dmi_cache_location(sect_n, (WORD(data + 0x05) >> 5) & 0x0003); - dmi_cache_size(sect_n, "InstalledSize", WORD(data + 0x09)); - dmi_cache_size(sect_n, "MaximumSize", WORD(data + 0x07)); + + if (h->length >= 0x1B) + dmi_cache_size_2(sect_n, "InstalledSize", DWORD(data + 0x17)); + else + dmi_cache_size(sect_n, "InstalledSize", WORD(data + 0x09)); + + if (h->length >= 0x17) + dmi_cache_size_2(sect_n, "Maximumsize", DWORD(data + 0x13)); + else + dmi_cache_size(sect_n, "Maximumsize", WORD(data + 0x07)); dmi_cache_types(sect_n, "SupportedSRAMtypes", WORD(data + 0x0B)); dmi_cache_types(sect_n, "InstalledSRAMtypes", WORD(data + 0x0D)); @@ -4067,19 +5191,19 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_cache_associativity(sect_n, data[0x12]); break; - case 8: /* 3.3.9 Port Connector Information */ + case 8: /* 7.9 Port Connector Information */ if(h->length < 0x09) { break; } - sub_n = dmixml_AddTextChild(sect_n, "DesignatorRef", dmi_string(h, data[0x04])); + sub_n = dmixml_AddDMIstring(sect_n, "DesignatorRef", h, data[0x04]); assert( sub_n != NULL ); dmixml_AddAttribute(sub_n, "type", "internal"); sub_n = NULL; dmi_port_connector_type(sect_n, "internal", data[0x05]); - sub_n = dmixml_AddTextChild(sect_n, "DesignatorRef", dmi_string(h, data[0x06])); + sub_n = dmixml_AddDMIstring(sect_n, "DesignatorRef", h, data[0x06]); assert( sub_n != NULL ); dmixml_AddAttribute(sub_n, "type", "external"); sub_n = NULL; @@ -4088,12 +5212,12 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_port_type(sect_n, data[0x08]); break; - case 9: /* 3.3.10 System Slots */ + case 9: /* 7.10 System Slots */ if(h->length < 0x0C) { break; } - dmixml_AddTextChild(sect_n, "Designation", "%s", dmi_string(h, data[0x04])); + dmixml_AddDMIstring(sect_n, "Designation", h, data[0x04]); dmi_slot_bus_width(sect_n, data[0x06]); dmi_slot_type(sect_n, data[0x05]); @@ -4106,13 +5230,26 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade } else { dmi_slot_characteristics(sect_n, data[0x0B], data[0x0C]); } + + if(h->length < 0x11){ + break; + } + dmi_slot_segment_bus_func(sect_n, WORD(data + 0x0D), data[0x0F], data[0x10]); + + if (h->length < 0x13){ + break; + } + dmixml_AddAttribute(sect_n, "Databuswidth", "%i", data[0x11]); + + if( h->length - 0x13 >= data[0x12] * 5) + dmi_slot_peers(sect_n, data[0x12], data+0x13, h); break; - case 10: /* 3.3.11 On Board Devices Information */ + case 10: /* 7.11 On Board Devices Information */ dmi_on_board_devices(sect_n, "dmi_on_board_devices", h); break; - case 11: /* 3.3.12 OEM Strings */ + case 11: /* 7.12 OEM Strings */ if(h->length < 0x05) { break; } @@ -4120,7 +5257,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_oem_strings(sect_n, h); break; - case 12: /* 3.3.13 System Configuration Options */ + case 12: /* 7.13 System Configuration Options */ if(h->length < 0x05) { break; } @@ -4128,22 +5265,30 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_system_configuration_options(sect_n, h); break; - case 13: /* 3.3.14 BIOS Language Information */ + case 13: /* 7.14 BIOS Language Information */ if(h->length < 0x16) { break; } + if (ver >= 0x0201){ + dmixml_AddAttribute(sect_n, "Language_description_format", "%s", + dmi_bios_language_format(data[0x05])); + } + dmixml_AddAttribute(sect_n, "installable_languages", "%i", data[0x04]); - dmi_bios_languages(sect_n, h); + dmi_bios_languages(sect_n, h, data[0x05]); + + dmixml_AddAttribute(sect_n, "currently_installed_language", "%s", dmi_string(h, data[0x15])); + break; - case 14: /* 3.3.15 Group Associations */ + case 14: /* 7.15 Group Associations */ if(h->length < 0x05) { break; } - dmixml_AddTextChild(sect_n, "Name", "%s", dmi_string(h, data[0x04])); + dmixml_AddDMIstring(sect_n, "Name", h, data[0x04]); sub_n = xmlNewChild(sect_n, NULL, (xmlChar *) "Groups", NULL); assert( sub_n != NULL ); @@ -4151,7 +5296,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade sub_n = NULL; break; - case 15: /* 3.3.16 System Event Log */ + case 15: /* 7.16 System Event Log */ // SysEventLog - sect_n if(h->length < 0x14) { break; @@ -4186,7 +5331,6 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade // SysEventLog/Access/Header/Format - sub2_n dmi_event_log_header_type(sub2_n, data[0x14]); - sub2_n = NULL; sub_n = NULL; @@ -4208,7 +5352,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade sub_n = NULL; break; - case 16: /* 3.3.17 Physical Memory Array */ + case 16: /* 7.17 Physical Memory Array */ if(h->length < 0x0F) { break; } @@ -4217,11 +5361,11 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_memory_array_location(sect_n, data[0x04]); dmi_memory_array_use(sect_n, data[0x05]); dmi_memory_array_ec_type(sect_n, data[0x06]); - dmi_memory_array_capacity(sect_n, DWORD(data + 0x07)); - dmi_memory_array_error_handle(sect_n, WORD(data + 0x0B)); + dmi_memory_array_capacity(sect_n, h, data); + dmi_memory_array_error_handle(sect_n, WORD(data + 0x0D)); break; - case 17: /* 3.3.18 Memory Device */ + case 17: /* 7.18 Memory Device */ if(h->length < 0x15) { break; } @@ -4231,11 +5375,15 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_memory_device_width(sect_n, "TotalWidth", WORD(data + 0x08)); dmi_memory_device_width(sect_n, "DataWidth", WORD(data + 0x0A)); - dmi_memory_device_size(sect_n, WORD(data + 0x0C)); + if (h->length >= 0x20 && WORD(data + 0x0C) == 0x7FFF) { + dmi_memory_device_extended_size(sect_n, DWORD(data + 0x1C)); + } else { + dmi_memory_device_size(sect_n, WORD(data + 0x0C)); + } dmi_memory_device_form_factor(sect_n, data[0x0E]); dmi_memory_device_set(sect_n, data[0x0F]); - dmixml_AddTextChild(sect_n, "Locator", dmi_string(h, data[0x10])); - dmixml_AddTextChild(sect_n, "BankLocator", dmi_string(h, data[0x11])); + dmixml_AddDMIstring(sect_n, "Locator", h, data[0x10]); + dmixml_AddDMIstring(sect_n, "BankLocator", h, data[0x11]); dmi_memory_device_type(sect_n, data[0x12]); dmi_memory_device_type_detail(sect_n, WORD(data + 0x13)); @@ -4244,20 +5392,43 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade break; } - dmi_memory_device_speed(sect_n, WORD(data + 0x15)); + dmi_memory_device_speed(sect_n, "Speed", WORD(data + 0x15)); if(h->length < 0x1B) { break; } - dmixml_AddTextChild(sect_n, "Manufacturer", "%s", dmi_string(h, data[0x17])); - dmixml_AddTextChild(sect_n, "SerialNumber", "%s", dmi_string(h, data[0x18])); - dmixml_AddTextChild(sect_n, "AssetTag", "%s", dmi_string(h, data[0x19])); - dmixml_AddTextChild(sect_n, "PartNumber", "%s", dmi_string(h, data[0x1A])); + dmixml_AddDMIstring(sect_n, "Manufacturer", h, data[0x17]); + dmixml_AddDMIstring(sect_n, "SerialNumber", h, data[0x18]); + dmixml_AddDMIstring(sect_n, "AssetTag", h, data[0x19]); + dmixml_AddDMIstring(sect_n, "PartNumber", h, data[0x1A]); + + if(h->length < 0x1C) { + break; + } + + dmixml_AddTextChild(sect_n, "Rank", "%u", data[0x1B] & 0x0F); + + if(h->length < 0x22) { + break; + } + + dmi_memory_device_speed(sect_n, "CurrentClockSpeed", WORD(data + 0x20)); + + if(h->length < 0x28) { + break; + } + sub_n = xmlNewChild(sect_n, NULL, (xmlChar *) "MemoryVoltage", NULL); + assert( sub_n != NULL ); + dmi_memory_voltage_value(sub_n, "Minimum", WORD(data + 0x22)); + dmi_memory_voltage_value(sub_n, "Maximum", WORD(data + 0x24)); + dmi_memory_voltage_value(sub_n, "Current", WORD(data + 0x26)); + sub_n = NULL; + break; - case 18: /* 3.3.19 32-bit Memory Error Information */ - case 33: /* 3.3.34 64-bit Memory Error Information */ + case 18: /* 7.19 32-bit Memory Error Information */ + case 33: /* 7.34 64-bit Memory Error Information */ if( h->type == 18 ) { dmixml_AddAttribute(sect_n, "bits", "32"); } else { @@ -4288,37 +5459,58 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade } break; - case 19: /* 3.3.20 Memory Array Mapped Address */ + case 19: /* 7.20 Memory Array Mapped Address */ if(h->length < 0x0F) { break; } - dmixml_AddTextChild(sect_n, "StartAddress", "0x%08x%03x", - (DWORD(data + 0x04) >> 2), - (DWORD(data + 0x04) & 0x3) << 10); - dmixml_AddTextChild(sect_n, "EndAddress", "0x%08x%03x", - (DWORD(data + 0x08) >> 2), - ((DWORD(data + 0x08) & 0x3) << 10) + 0x3FF); - dmi_mapped_address_size(sect_n, DWORD(data + 0x08) - DWORD(data + 0x04) + 1); + if (h->length >= 0x1F && DWORD(data + 0x04) == 0xFFFFFFFF) { + u64 start, end; + + start = QWORD(data + 0x0F); + end = QWORD(data + 0x17); + dmi_mapped_address_extended_size(sect_n, start, end); + } else { + dmixml_AddTextChild(sect_n, "StartAddress", "0x%08x%03x", + (DWORD(data + 0x04) >> 2), + (DWORD(data + 0x04) & 0x3) << 10); + dmixml_AddTextChild(sect_n, "EndAddress", "0x%08x%03x", + (DWORD(data + 0x08) >> 2), + ((DWORD(data + 0x08) & 0x3) << 10) + 0x3FF); + dmi_mapped_address_size(sect_n, DWORD(data + 0x08) - DWORD(data + 0x04) + 1); + } + dmixml_AddTextChild(sect_n, "PhysicalArrayHandle", "0x%04x", WORD(data + 0x0C)); dmixml_AddTextChild(sect_n, "PartitionWidth", "%i", data[0x0F]); break; - case 20: /* 3.3.21 Memory Device Mapped Address */ + case 20: /* 7.21 Memory Device Mapped Address */ if(h->length < 0x13) { break; } - dmixml_AddTextChild(sect_n, "StartAddress", "0x%08x%03x", - (DWORD(data + 0x04) >> 2), - (DWORD(data + 0x04) & 0x3) << 10); + if (h->length >= 0x23 && DWORD(data + 0x04) == 0xFFFFFFFF){ + u64 start, end; + + start = QWORD(data + 0x13); + end = QWORD(data + 0x1B); - dmixml_AddTextChild(sect_n, "EndAddress", "0x%08x%03x", - (DWORD(data + 0x08) >> 2), - ((DWORD(data + 0x08) & 0x3) << 10) + 0x3FF); + dmixml_AddTextChild(sect_n, "StartAddress", "0x%08X%08Xk", + start.h, start.l); + dmixml_AddTextChild(sect_n, "StartAddress", "0x%08X%08Xk", + end.h, end.l); + dmi_mapped_address_extended_size(sect_n, start, end); + } else { + dmixml_AddTextChild(sect_n, "StartAddress", "0x%08x%03x", + (DWORD(data + 0x04) >> 2), + (DWORD(data + 0x04) & 0x3) << 10); - dmi_mapped_address_size(sect_n, DWORD(data + 0x08) - DWORD(data + 0x04) + 1); + dmixml_AddTextChild(sect_n, "EndAddress", "0x%08x%03x", + (DWORD(data + 0x08) >> 2), + ((DWORD(data + 0x08) & 0x3) << 10) + 0x3FF); + dmi_mapped_address_size(sect_n, DWORD(data + 0x08) - DWORD(data + 0x04) + 1); + } dmixml_AddTextChild(sect_n, "PhysicalDeviceHandle", "0x%04x", WORD(data + 0x0C)); dmixml_AddTextChild(sect_n, "MemArrayMappedAddrHandle", "0x%04x", WORD(data + 0x0E)); @@ -4328,7 +5520,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_mapped_address_interleaved_data_depth(sect_n, data[0x12]); break; - case 21: /* 3.3.22 Built-in Pointing Device */ + case 21: /* 7.22 Built-in Pointing Device */ if(h->length < 0x07) { break; } @@ -4338,31 +5530,31 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmixml_AddTextChild(sect_n, "Buttons", "%i", data[0x06]); break; - case 22: /* 3.3.23 Portable Battery */ + case 22: /* 7.23 Portable Battery */ if(h->length < 0x10) { break; } - dmixml_AddTextChild(sect_n, "Location", "%s", dmi_string(h, data[0x04])); - dmixml_AddTextChild(sect_n, "Manufacturer", "%s", dmi_string(h, data[0x05])); + dmixml_AddDMIstring(sect_n, "Location", h, data[0x04]); + dmixml_AddDMIstring(sect_n, "Manufacturer", h, data[0x05]); if(data[0x06] || h->length < 0x1A) { - dmixml_AddTextChild(sect_n, "ManufactureDate", "%s", dmi_string(h, data[0x06])); + dmixml_AddDMIstring(sect_n, "ManufactureDate", h, data[0x06]); } if(data[0x07] || h->length < 0x1A) { - dmixml_AddTextChild(sect_n, "SerialNumber", "%s", dmi_string(h, data[0x07])); + dmixml_AddDMIstring(sect_n, "SerialNumber", h, data[0x07]); } - dmixml_AddTextChild(sect_n, "Name", "%s", dmi_string(h, data[0x08])); + dmixml_AddDMIstring(sect_n, "Name", h, data[0x08]); if(data[0x09] != 0x02 || h->length < 0x1A) { dmi_battery_chemistry(sect_n, data[0x09]); } - dmi_battery_capacity(sect_n, WORD(data + 0x0A), (h->length < 0x1A ? 1 : data[0x15])); + dmi_battery_capacity(sect_n, WORD(data + 0x0A), (h->length < 0x16 ? 1 : data[0x15])); dmi_battery_voltage(sect_n, WORD(data + 0x0C)); - dmixml_AddTextChild(sect_n, "SBDSversion", "%s", dmi_string(h, data[0x0E])); + dmixml_AddDMIstring(sect_n, "SBDSversion", h, data[0x0E]); dmi_battery_maximum_error(sect_n, data[0x0F]); @@ -4380,13 +5572,13 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade (WORD(data + 0x12) & 0x1F)); } if(data[0x09] == 0x02) { - dmixml_AddTextChild(sect_n, "SBDSchemistry", "%s", dmi_string(h, data[0x14])); + dmixml_AddDMIstring(sect_n, "SBDSchemistry", h, data[0x14]); } dmixml_AddTextChild(sect_n, "OEMinformation", "0x%08x", DWORD(data + 0x16)); break; - case 23: /* 3.3.24 System Reset */ + case 23: /* 7.24 System Reset */ if(h->length < 0x0D) { break; } @@ -4415,7 +5607,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_system_reset_timer(sect_n, "Timeout", WORD(data + 0x0B)); break; - case 24: /* 3.3.25 Hardware Security */ + case 24: /* 7.25 Hardware Security */ if(h->length < 0x05) { break; } @@ -4427,7 +5619,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade break; - case 25: /* 3.3.26 System Power Controls */ + case 25: /* 7.26 System Power Controls */ if(h->length < 0x09) { break; } @@ -4435,14 +5627,14 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_power_controls_power_on(sect_n, "NextSchedPowerOn", data + 0x04); break; - case 26: /* 3.3.27 Voltage Probe */ + case 26: /* 7.27 Voltage Probe */ dmixml_AddAttribute(sect_n, "probetype", "Voltage"); if(h->length < 0x14) { break; } - dmixml_AddTextChild(sect_n, "Description", "%s", dmi_string(h, data[0x04])); + dmixml_AddDMIstring(sect_n, "Description", h, data[0x04]); dmi_voltage_probe_location(sect_n, data[0x05] & 0x1f); dmi_probe_status(sect_n, data[0x05] >> 5); @@ -4463,7 +5655,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_voltage_probe_value(sect_n, "NominalValue", WORD(data + 0x14)); break; - case 27: /* 3.3.28 Cooling Device */ + case 27: /* 7.28 Cooling Device */ if(h->length < 0x0C) { break; } @@ -4488,14 +5680,14 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_cooling_device_speed(sect_n, WORD(data + 0x0C)); break; - case 28: /* 3.3.29 Temperature Probe */ + case 28: /* 7.29 Temperature Probe */ dmixml_AddAttribute(sect_n, "probetype", "Temperature"); if(h->length < 0x14) { break; } - dmixml_AddTextChild(sect_n, "Description", "%s", dmi_string(h, data[0x04])); + dmixml_AddDMIstring(sect_n, "Description", h, data[0x04]); dmi_temperature_probe_location(sect_n,data[0x05] & 0x1F); dmi_probe_status(sect_n, data[0x05] >> 5); @@ -4514,14 +5706,14 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_temperature_probe_value(sect_n, "NominalValue", WORD(data + 0x14)); break; - case 29: /* 3.3.30 Electrical Current Probe */ + case 29: /* 7.30 Electrical Current Probe */ dmixml_AddAttribute(sect_n, "probetype", "Electrical Current"); if(h->length < 0x14) { break; } - dmixml_AddTextChild(sect_n, "Description", dmi_string(h, data[0x04])); + dmixml_AddDMIstring(sect_n, "Description", h, data[0x04]); dmi_voltage_probe_location(sect_n, data[5] & 0x1F); dmi_probe_status(sect_n, data[0x05] >> 5); @@ -4541,21 +5733,28 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_current_probe_value(sect_n, "NominalValue", WORD(data + 0x14)); break; - case 30: /* 3.3.31 Out-of-band Remote Access */ + case 30: /* 7.31 Out-of-band Remote Access */ if(h->length < 0x06) { break; } - dmixml_AddTextChild(sect_n, "ManufacturerName", "%s", dmi_string(h, data[0x04])); + dmixml_AddDMIstring(sect_n, "ManufacturerName", h, data[0x04]); dmixml_AddAttribute(sect_n, "InboundConnectionEnabled", "%i", data[0x05] & (1 << 0) ? 1 : 0); dmixml_AddAttribute(sect_n, "OutboundConnectionEnabled", "%i", data[0x05] & (1 << 1) ? 1 : 0); break; - case 31: /* 3.3.32 Boot Integrity Services Entry Point */ - dmixml_AddAttribute(sect_n, "NOT_IMPLEMENTED", "1"); + case 31: /* 7.32 Boot Integrity Services Entry Point */ + if(h->length < 0x1C){ + break; + } + + dmixml_AddAttribute(sect_n, "Checksum", "%s", checksum(data, h->length) ? "OK" : "Invalid"); + dmixml_AddAttribute(sect_n, "16BitEntryPointAddress", "%04X:%04X", + DWORD(data + 0x08) >> 16, DWORD(data + 0x08) & 0xFFFF); + dmixml_AddAttribute(sect_n, "32BitEntryPointAddress", "0x%08X", DWORD(data + 0x0C)); break; - case 32: /* 3.3.33 System Boot Information */ + case 32: /* 7.33 System Boot Information */ if(h->length < 0x0B) { break; } @@ -4563,27 +5762,27 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_system_boot_status(sect_n, data[0x0A]); break; - case 34: /* 3.3.35 Management Device */ + case 34: /* 7.35 Management Device */ dmixml_AddAttribute(sect_n, "mgmtype", ""); if(h->length < 0x0B) { break; } - dmixml_AddTextChild(sect_n, "Description", "%s", dmi_string(h, data[0x04])); + dmixml_AddDMIstring(sect_n, "Description", h, data[0x04]); dmi_management_device_type(sect_n, data[0x05]); dmixml_AddTextChild(sect_n, "Address", "0x%08x", DWORD(data + 0x06)); dmi_management_device_address_type(sect_n, data[0x0A]); break; - case 35: /* 3.3.36 Management Device Component */ + case 35: /* 7.36 Management Device Component */ dmixml_AddAttribute(sect_n, "mgmtype", "Component"); if(h->length < 0x0B) { break; } - dmixml_AddTextChild(sect_n, "Description", dmi_string(h, data[0x04])); + dmixml_AddDMIstring(sect_n, "Description", h, data[0x04]); dmixml_AddTextChild(sect_n, "ManagementDeviceHandle", "0x%04x", WORD(data + 0x05)); dmixml_AddTextChild(sect_n, "ComponentHandle", "0x%04x", WORD(data + 0x07)); @@ -4592,7 +5791,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade } break; - case 36: /* 3.3.37 Management Device Threshold Data */ + case 36: /* 7.37 Management Device Threshold Data */ dmixml_AddAttribute(sect_n, "mgmtype", "Threshold Data"); if(h->length < 0x10) { @@ -4637,7 +5836,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade sub_n = NULL; break; - case 37: /* 3.3.38 Memory Channel */ + case 37: /* 7.38 Memory Channel */ if(h->length < 0x07) { break; } @@ -4658,7 +5857,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade sub_n = NULL; break; - case 38: /* 3.3.39 IPMI Device Information */ + case 38: /* 7.39 IPMI Device Information */ /* * We use the word "Version" instead of "Revision", conforming to * the IPMI specification. @@ -4684,7 +5883,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade sub_n = NULL; dmi_ipmi_base_address(sect_n, data[0x04], data + 0x08, - h->length < 0x12 ? 0 : (data[0x10] >> 5) & 1); + h->length < 0x11 ? 0 : (data[0x10] >> 4) & 1); if(h->length < 0x12) { break; @@ -4713,7 +5912,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade sub_n = NULL; break; - case 39: /* 3.3.40 System Power Supply */ + case 39: /* 7.40 System Power Supply */ if(h->length < 0x10) { break; } @@ -4722,13 +5921,13 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmixml_AddAttribute(sect_n, "UnitGroup", "%i", data[0x04]); } - dmixml_AddTextChild(sect_n, "Location", "%s", dmi_string(h, data[0x05])); - dmixml_AddTextChild(sect_n, "Name", "%s", dmi_string(h, data[0x06])); - dmixml_AddTextChild(sect_n, "Manufacturer", "%s", dmi_string(h, data[0x07])); - dmixml_AddTextChild(sect_n, "SerialNumber", "%s", dmi_string(h, data[0x08])); - dmixml_AddTextChild(sect_n, "AssetTag", "%s", dmi_string(h, data[0x09])); - dmixml_AddTextChild(sect_n, "ModelPartNumber", "%s", dmi_string(h, data[0x0A])); - dmixml_AddTextChild(sect_n, "Revision", "%s", dmi_string(h, data[0x0B])); + dmixml_AddDMIstring(sect_n, "Location", h, data[0x05]); + dmixml_AddDMIstring(sect_n, "Name", h, data[0x06]); + dmixml_AddDMIstring(sect_n, "Manufacturer", h, data[0x07]); + dmixml_AddDMIstring(sect_n, "SerialNumber", h, data[0x08]); + dmixml_AddDMIstring(sect_n, "AssetTag", h, data[0x09]); + dmixml_AddDMIstring(sect_n, "ModelPartNumber", h, data[0x0A]); + dmixml_AddDMIstring(sect_n, "Revision", h, data[0x0B]); dmi_power_supply_power(sect_n, WORD(data + 0x0C)); @@ -4771,9 +5970,8 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade sub_n = NULL; break; - case 40: /* 3.3.41 Additional Information */ + case 40: /* 7.41 Additional Information */ dmixml_AddAttribute(sect_n, "subtype", "AdditionalInformation"); - dmixml_AddAttribute(sect_n, "dmispec", "3.3.41"); if(h->length < 0x0B) { break; @@ -4782,15 +5980,12 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_additional_info(sect_n, h); break; - case 41: /* 3.3.42 Onboard Device Extended Information */ - dmixml_AddAttribute(sect_n, "subtype", "OnboardDeviceExtendedInformation"); - dmixml_AddAttribute(sect_n, "dmispec", "3.3.42"); - + case 41: /* 7.42 Onboard Device Extended Information */ if(h->length < 0x0B) { break; } - dmixml_AddTextChild(sect_n, "ReferenceDesignation", "%s", dmi_string(h, data[0x04])); + dmixml_AddDMIstring(sect_n, "ReferenceDesignation", h, data[0x04]); sub_n = xmlNewChild(sect_n, NULL, (xmlChar *) "OnboardDevice", NULL); dmi_on_board_devices_type(sub_n, data[0x05] & 0x7F); @@ -4801,8 +5996,67 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade sub_n = NULL; break; - case 126: /* 3.3.43 Inactive */ - case 127: /* 3.3.44 End Of Table */ + case 42: /* 7.43 Management Controller Host Interface */ + if (ver < 0x0302){ + if (h->length < 0x05){ + break; + } + dmixml_AddAttribute(sect_n, "subtype", "InterfaceType"); + dmi_management_controller_host_type(sect_n, data[0x04]); + /* + * There you have a type-dependent, variable-length + * part in the middle of the structure, with no + * length specifier, so no easy way to decode the + * common, final part of the structure. What a pity. + */ + if (h->length < 0x09) { + break; + } + if (data[0x04] == 0xF0) { /* OEM */ + dmixml_AddAttribute(sect_n, "subtype", "VendorID"); + dmixml_AddTextContent(sect_n, "0x%02X%02X%02X%02X\n", + data[0x05], data[0x06], data[0x07], + data[0x08]); + } + sub_n = NULL; + } else { + dmi_parse_controller_structure(sect_n, h); + } + break; + case 43: + if (h->length < 0x1B){ + break; + } + dmi_tpm_vendor_id(sect_n, data + 0x04); + switch (data[0x08]) { + case 0x01: + /* + * We skip the first 2 bytes, which are + * redundant with the above, and uncoded + * in a silly way. + */ + dmixml_AddTextContent(sect_n, "FirmwareRevision", "%u", data[0x0C]); + dmixml_AddTextContent(sect_n, "FirmwareRevision", "%u", data[0x0D]); + break; + case 0x02: + /* + * We skip the next 4 bytes, as their + * format is not standardized and their + * usefulness seems limited anyway. + */ + dmixml_AddTextContent(sect_n, "FirmwareRevision", "%i", DWORD(data + 0x0A) >> 16); + dmixml_AddTextContent(sect_n, "FirmwareRevision", "%i", DWORD(data + 0x0A) & 0xFFFF); + break; + } + dmixml_AddDMIstring(sect_n, "Description", h, data[0x12]); + dmi_tpm_characteristics(sect_n, QWORD(data + 0x13)); + if (h->length < 0x1F){ + break; + } + dmixml_AddAttribute(sect_n, "OEMSpecificInformation", "0x%08X", DWORD(data + 0x1B)); + break; + case 126: /* 7.43 Inactive */ + case 127: /* 7.44 End Of Table */ break; default: @@ -4842,8 +6096,9 @@ dmi_codes_major *find_dmiMajor(const struct dmi_header *h) return NULL; } -static void dmi_table(int type, u32 base, u16 len, u16 num, u16 ver, const char *devmem, xmlNode *xmlnode) +static void dmi_table(Log_t *logp, int type, u32 base, u32 len, u16 num, u32 ver, const char *devmem, u32 flags, xmlNode *xmlnode) { + static u8 version_added = 0; u8 *buf; u8 *data; int i = 0; @@ -4865,23 +6120,40 @@ static void dmi_table(int type, u32 base, u16 len, u16 num, u16 ver, const char info_n = NULL; } - if((buf = mem_chunk(base, len, devmem)) == NULL) { - fprintf(stderr, "Table is unreachable, sorry." -#ifndef USE_MMAP - "Try compiling dmidecode with -DUSE_MMAP."; -#endif - "\n"); - return; - } - - data = buf; - while(i < num && data + 4 <= buf + len) { /* 4 is the length of an SMBIOS structure header */ - + if(flags & FLAG_NO_FILE_OFFSET){ + /* + * When reading from sysfs or from a dump file, the file may be + * shorter than announced. For SMBIOS v3 this is expcted, as we + * only know the maximum table size, not the actual table size. + * For older implementations (and for SMBIOS v3 too), this + * would be the result of the kernel truncating the table on + * parse error. + */ + size_t size = len; + buf = read_file(logp, flags & FLAG_NO_FILE_OFFSET ? 0 : base, &size, devmem); + if (num && size != (size_t)len){ + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "Wrong DMI structures length: %i bytes announced, only %lu bytes available.\n", len, (unsigned long)size ); + } + len = size; + } else { + buf = mem_chunk(logp, base, len, devmem); + } + + if (ver > SUPPORTED_SMBIOS_VER){ + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "# SMBIOS implementations newer than version %u.%u.%u are not\n fully supported by this version of dmidecode.\n", SUPPORTED_SMBIOS_VER >> 16, (SUPPORTED_SMBIOS_VER >> 8) & 0xFF, SUPPORTED_SMBIOS_VER & 0xFF); + } + + if( version_added == 0 ) { + dmixml_AddAttribute(xmlnode, "smbios_version", "%u.%u", ver >> 8, ver & 0xFF); + version_added = 1; + } + + data = buf; + while((i < num||!num) && data + 4 <= buf + len) { /* 4 is the length of an SMBIOS structure header */ u8 *next; struct dmi_header h; to_dmi_header(&h, data); - /* ** If a short entry is found (less than 4 bytes), not only it ** is invalid, but we cannot reliably locate the next entry. @@ -4889,8 +6161,9 @@ static void dmi_table(int type, u32 base, u16 len, u16 num, u16 ver, const char ** table is broken. */ if(h.length < 4) { - fprintf(stderr, "Invalid entry length (%i). DMI table is broken! Stop.", - (unsigned int)h.length); + log_append(logp, LOGFL_NORMAL, LOG_WARNING, + "Invalid entry length (%i) for type %i. DMI table is broken! Stop.", + (unsigned int)h.length, type); break; } @@ -4899,8 +6172,13 @@ static void dmi_table(int type, u32 base, u16 len, u16 num, u16 ver, const char */ /* assign vendor for vendor-specific decodes later */ - if(h.type == 0 && h.length >= 5) { - dmi_set_vendor(dmi_string(&h, data[0x04])); + if(h.type == 1 && h.length >= 5) { + dmi_set_vendor(&h); + } + + /* Fixup a common mistake */ + if(h.type == 34){ + dmi_fixup_type_34(&h); } /* look for the next handle */ @@ -4909,7 +6187,6 @@ static void dmi_table(int type, u32 base, u16 len, u16 num, u16 ver, const char next++; } next += 2; - xmlNode *handle_n = NULL; if( h.type == type ) { if(next - buf <= len) { @@ -4933,9 +6210,18 @@ static void dmi_table(int type, u32 base, u16 len, u16 num, u16 ver, const char } else { handle_n = xmlNewChild(xmlnode, NULL, (xmlChar *) "DMIerror", NULL); assert( handle_n != NULL ); - dmixml_AddTextContent(handle_n, "Data is truncated"); + dmixml_AddTextContent(handle_n, "Data is truncated %i bytes on type 0x%02X", + (next - buf - len), h.type); dmixml_AddAttribute(handle_n, "type", "%i", h.type); dmixml_AddAttribute(handle_n, "truncated", "1"); + dmixml_AddAttribute(handle_n, "length", "%i", (next - buf)); + dmixml_AddAttribute(handle_n, "expected_length", "%i", len); + + + log_append(logp, LOGFL_NODUPS, LOG_WARNING, + "DMI/SMBIOS type 0x%02X is exceeding the expected buffer " + "size by %i bytes. Will not decode this entry.", + h.type, (next - buf - len)); } dmixml_AddAttribute(handle_n, "handle", "0x%04x", h.handle); dmixml_AddAttribute(handle_n, "size", "%d", h.length); @@ -4954,17 +6240,71 @@ static void dmi_table(int type, u32 base, u16 len, u16 num, u16 ver, const char dmixml_AddAttribute(handle_n, "notfound", "1"); } - if(i != num) - fprintf(stderr, "Wrong DMI structures count: %d announced, only %d decoded.\n", num, - i); - if(data - buf != len) - fprintf(stderr, - "Wrong DMI structures length: %d bytes announced, structures occupy %d bytes.\n", - len, (unsigned int)(data - buf)); + if(i != num) { + log_append(logp, LOGFL_NODUPS, LOG_WARNING, + "Wrong DMI structures count: %d announced, only %d decoded.", num, i); + } + if(data - buf != len) { + log_append(logp, LOGFL_NODUPS, LOG_WARNING, + "Wrong DMI structures length: %d bytes announced, structures occupy %d bytes.", + len, (unsigned int)(data - buf)); + } free(buf); } +int _smbios3_decode_check(u8 *buf){ + int check = (!checksum(buf, buf[0x06])) ? 0 : 1; + return check; +} + +xmlNode *smbios3_decode_get_version(u8 * buf, const char *devmem) +{ + int check = _smbios3_decode_check(buf); + + xmlNode *data_n = xmlNewNode(NULL, (xmlChar *) "DMIversion"); + assert( data_n != NULL ); + + dmixml_AddAttribute(data_n, "type", "SMBIOS"); + + if(check == 1) { + // u32 ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; + dmixml_AddTextContent(data_n, "SMBIOS %i.%i.%i present", buf[0x07], buf[0x08], buf[0x09]); + dmixml_AddAttribute(data_n, "version", "%i.%i.%i", buf[0x07], buf[0x08],buf[0x09]); + } else if(check == 0) { + dmixml_AddTextContent(data_n, "No SMBIOS nor DMI entry point found"); + dmixml_AddAttribute(data_n, "unknown", "1"); + } + return data_n; +} + +int smbios3_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode) +{ + u32 ver; + u64 offset; + + /* Don't let checksum run beyond the buffer */ + if (buf[0x06] > 0x20) + { + return 0; + } + + int check = _smbios3_decode_check(buf); + if (check == 1) + { + ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; + offset = QWORD(buf + 0x10); + + if (!(flags & FLAG_NO_FILE_OFFSET) && offset.h && sizeof(off_t) < 8) + { + return 0; + } + dmi_table(logp, type, ((off_t)offset.h << 32) | offset.l, DWORD(buf+0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT, xmlnode); + } + + return check; +} + int _smbios_decode_check(u8 * buf) { int check = (!checksum(buf, buf[0x05]) || memcmp(buf + 0x10, "_DMI_", 5) != 0 || @@ -4991,7 +6331,8 @@ xmlNode *smbios_decode_get_version(u8 * buf, const char *devmem) _M = 0; switch (ver) { case 0x021F: - _m = 31; + case 0x0221: + _m = ver & 0xFF; _M = 3; ver = 0x0203; break; @@ -5017,7 +6358,7 @@ xmlNode *smbios_decode_get_version(u8 * buf, const char *devmem) return data_n; } -int smbios_decode(int type, u8 *buf, const char *devmem, xmlNode *xmlnode) +int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode) { int check = _smbios_decode_check(buf); @@ -5026,15 +6367,16 @@ int smbios_decode(int type, u8 *buf, const char *devmem, xmlNode *xmlnode) switch (ver) { case 0x021F: + case 0x0221: ver = 0x0203; break; case 0x0233: ver = 0x0206; break; } - //printf(">>%d @ %d, %d<<\n", DWORD(buf+0x18), WORD(buf+0x16), WORD(buf+0x1C)); - dmi_table(type, DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C), ver, devmem, - xmlnode); + // printf(">>%d @ %d, %d<<\n", DWORD(buf+0x18), WORD(buf+0x16), WORD(buf+0x1C)); + dmi_table(logp, type, DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C), ver, devmem, + flags, xmlnode); } return check; } @@ -5072,13 +6414,13 @@ xmlNode *legacy_decode_get_version(u8 * buf, const char *devmem) return data_n; } -int legacy_decode(int type, u8 *buf, const char *devmem, xmlNode *xmlnode) +int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode) { int check = _legacy_decode_check(buf); if(check == 1) - dmi_table(type, DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C), - ((buf[0x0E] & 0xF0) << 4) + (buf[0x0E] & 0x0F), devmem, xmlnode); + dmi_table(logp, type, DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C), + ((buf[0x0E] & 0xF0) << 4) + (buf[0x0E] & 0x0F), devmem, flags, xmlnode); return check; } diff --git a/src/dmidecode.h b/src/dmidecode.h index 10412c6..8279b74 100644 --- a/src/dmidecode.h +++ b/src/dmidecode.h @@ -21,6 +21,14 @@ #include #include "dmihelper.h" +#include "dmierror.h" + +#define FLAG_NO_FILE_OFFSET (1 << 0) +#define FLAG_STOP_AT_EOT (1 << 1) + +#define SYS_FIRMWARE_DIR "/sys/firmware/dmi/tables" +#define SYS_ENTRY_FILE SYS_FIRMWARE_DIR "/smbios_entry_point" +#define SYS_TABLE_FILE SYS_FIRMWARE_DIR "/DMI" struct dmi_header { u8 type; @@ -29,14 +37,17 @@ struct dmi_header { u8 *data; }; -void dmi_dump(xmlNode *node, struct dmi_header * h); +int is_printable(const u8 *data, int len); +void dmi_dump(xmlNode *node, struct dmi_header *h); xmlNode *dmi_decode(xmlNode *parent_n, dmi_codes_major *dmiMajor, struct dmi_header * h, u16 ver); void to_dmi_header(struct dmi_header *h, u8 * data); +xmlNode *smbios3_decode_get_version(u8 * buf, const char *devmem); xmlNode *smbios_decode_get_version(u8 * buf, const char *devmem); xmlNode *legacy_decode_get_version(u8 * buf, const char *devmem); -int smbios_decode(int type, u8 *buf, const char *devmem, xmlNode *xmlnode); -int legacy_decode(int type, u8 *buf, const char *devmem, xmlNode *xmlnode); +int smbios3_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode); +int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode); +int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode); const char *dmi_string(const struct dmi_header *dm, u8 s); void dmi_system_uuid(xmlNode *node, const u8 * p, u16 ver); diff --git a/src/dmidecodemodule.c b/src/dmidecodemodule.c index 5c74124..efa730b 100644 --- a/src/dmidecodemodule.c +++ b/src/dmidecodemodule.c @@ -44,30 +44,54 @@ #include #include "libxml_wrap.h" -#include "xmlpythonizer.h" #include "dmidecodemodule.h" #include "dmixml.h" #include "dmierror.h" +#include "dmilog.h" +#include "xmlpythonizer.h" #include "version.h" #include "dmidump.h" #include +#if (PY_VERSION_HEX < 0x03030000) +char *PyUnicode_AsUTF8(PyObject *unicode) { + PyObject *as_bytes = PyUnicode_AsUTF8String(unicode); + if (!as_bytes) { + return NULL; + } + + return PyBytes_AsString(as_bytes); +} +#endif + static void init(options *opt) { - /* sanity check */ - if(sizeof(u8) != 1 || sizeof(u16) != 2 || sizeof(u32) != 4 || '\0' != 0) - fprintf(stderr, "%s: compiler incompatibility\n", "dmidecodemodule"); + int efi; + size_t fp; - opt->devmem = DEFAULT_MEM_DEV; opt->dumpfile = NULL; opt->flags = 0; opt->type = -1; opt->dmiversion_n = NULL; opt->mappingxml = NULL; opt->python_xml_map = strdup(PYTHON_XML_MAP); + opt->logdata = log_init(); + + efi = address_from_efi(opt->logdata, &fp); + if(efi == EFI_NOT_FOUND){ + opt->devmem = DEFAULT_MEM_DEV; + } else { + opt->devmem = SYS_TABLE_FILE; + } + + /* sanity check */ + if(sizeof(u8) != 1 || sizeof(u16) != 2 || sizeof(u32) != 4 || '\0' != 0) { + log_append(opt->logdata, LOGFL_NORMAL, LOG_WARNING, + "%s: compiler incompatibility", "dmidecodemodule"); + } } -int parse_opt_type(const char *arg) +int parse_opt_type(Log_t *logp, const char *arg) { while(*arg != '\0') { int val; @@ -75,11 +99,11 @@ int parse_opt_type(const char *arg) val = strtoul(arg, &next, 0); if(next == arg) { - fprintf(stderr, "Invalid type keyword: %s\n", arg); + log_append(logp, LOGFL_NODUPS, LOG_ERR, "Invalid type keyword: %s", arg); return -1; } if(val > 0xff) { - fprintf(stderr, "Invalid type number: %i\n", val); + log_append(logp, LOGFL_NODUPS, LOG_ERR, "Invalid type number: %i", val); return -1; } @@ -101,69 +125,151 @@ xmlNode *dmidecode_get_version(options *opt) int efi; u8 *buf = NULL; xmlNode *ver_n = NULL; + size_t size; - /* Set default option values */ + /* + * First, if devmem is available, set default as DEFAULT_MEM_DEV + * Set default option values + */ if( opt->devmem == NULL ) { - opt->devmem = DEFAULT_MEM_DEV; + efi = address_from_efi(opt->logdata, &fp); + if(efi == EFI_NOT_FOUND){ + opt->devmem = DEFAULT_MEM_DEV; + } else { + opt->devmem = SYS_TABLE_FILE; + } } /* Read from dump if so instructed */ if(opt->dumpfile != NULL) { //. printf("Reading SMBIOS/DMI data from file %s.\n", dumpfile); - if((buf = mem_chunk(0, 0x20, opt->dumpfile)) != NULL) { - if(memcmp(buf, "_SM_", 4) == 0) { + if((buf = mem_chunk(opt->logdata, 0, 0x20, opt->dumpfile)) != NULL) { + if (memcmp(buf, "_SM3_", 5) == 0) { + ver_n = smbios3_decode_get_version(buf, opt->dumpfile); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } else if (memcmp(buf, "_SM_", 4) == 0) { ver_n = smbios_decode_get_version(buf, opt->dumpfile); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) found++; - } - } else if(memcmp(buf, "_DMI_", 5) == 0) { + } else if (memcmp(buf, "_DMI_", 5) == 0) { ver_n = legacy_decode_get_version(buf, opt->dumpfile); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) found++; - } } - } - } else { /* Read from /dev/mem */ - /* First try EFI (ia64, Intel-based Mac) */ - efi = address_from_efi(&fp); - if(efi == EFI_NOT_FOUND) { - /* Fallback to memory scan (x86, x86_64) */ - if((buf = mem_chunk(0xF0000, 0x10000, opt->devmem)) != NULL) { - for(fp = 0; fp <= 0xFFF0; fp += 16) { - if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { - ver_n = smbios_decode_get_version(buf + fp, opt->devmem); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - fp += 16; - } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { - ver_n = legacy_decode_get_version (buf + fp, opt->devmem); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - } - } - } - } else if(efi == EFI_NO_SMBIOS) { - ver_n = NULL; } else { - // Process as EFI - if((buf = mem_chunk(fp, 0x20, opt->devmem)) != NULL) { - ver_n = smbios_decode_get_version(buf, opt->devmem); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - //. TODO: dmixml_AddAttribute(dmixml_n, "efi_address", efiAddress); - } + ver_n = NULL; + goto exit_free; } + } - if( buf != NULL ) { - free(buf); - } - if( !found ) { - fprintf(stderr, "No SMBIOS nor DMI entry point found, sorry."); - } - return ver_n; + + /* + * First try reading from sysfs tables. The entry point file could + * contain one of several types of entry points, so read enough for + * the largest one, then determine what type it contains. + */ + size = 0x20; + if ( (buf = read_file(opt->logdata, 0, &size, SYS_ENTRY_FILE)) != NULL ){ + if(size >= 24 && memcmp(buf, "_SM3_", 5) == 0){ + ver_n = smbios3_decode_get_version(buf, opt->devmem); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0 ){ + ver_n = smbios_decode_get_version(buf, opt->devmem); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0){ + ver_n = legacy_decode_get_version (buf, opt->devmem); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } + + if(found) + goto done; + } else { + ver_n = NULL; + goto exit_free; + } + + /* Read from /dev/mem */ + /* Next try EFI (ia64, Intel-based Mac) */ + efi = address_from_efi(opt->logdata, &fp); + switch(efi){ + case EFI_NOT_FOUND: + goto memory_scan; + case EFI_NO_SMBIOS: + ver_n = NULL; + goto exit_free; + } + + if((buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem)) == NULL){ + ver_n = NULL; + goto exit_free; + } + + if(memcmp(buf, "_SM3_", 5) == 0){ + ver_n = smbios3_decode_get_version(buf, opt->devmem); + if(dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } else if (memcmp(buf, "_SM_", 4) == 0 ) { + ver_n = smbios_decode_get_version(buf, opt->devmem); + if(dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } + + goto done; + +memory_scan: +#if defined __i386__ || defined __x86_64__ + /* Fallback to memory scan (x86, x86_64) */ + if((buf = mem_chunk(opt->logdata, 0xF0000, 0x10000, opt->devmem)) == NULL) { + ver_n = NULL; + goto exit_free; + } + + /* Look for a 64-bit entry point first */ + for (fp = 0; fp <= 0xFFE0; fp+= 16){ + if(memcmp(buf+fp, "_SM3_", 5) == 0){ + ver_n = smbios3_decode_get_version(buf+fp, opt->devmem); + if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { + found++; + goto done; + } + } + } + + /* If none found, look for a 32-bit entry point */ + for(fp = 0; fp <= 0xFFF0; fp += 16) { + if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { + ver_n = smbios_decode_get_version(buf + fp, opt->devmem); + if ( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { + found++; + goto done; + } + fp += 16; + } else if (memcmp(buf + fp, "_DMI_", 5) == 0) { + ver_n = legacy_decode_get_version (buf + fp, opt->devmem); + if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { + found++; + goto done; + } + } + } +#endif + +done: + if(!found){ + log_append(opt->logdata, LOGFL_NODUPS, LOG_WARNING, + "No SMBIOS nor DMI entry point found, sorry."); + } + +exit_free: + if (buf != NULL) + free(buf); + + return ver_n; + } int dmidecode_get_xml(options *opt, xmlNode* dmixml_n) @@ -179,60 +285,131 @@ int dmidecode_get_xml(options *opt, xmlNode* dmixml_n) size_t fp; int efi; u8 *buf = NULL; + size_t size; const char *f = opt->dumpfile ? opt->dumpfile : opt->devmem; if(access(f, R_OK) < 0) { - fprintf(stderr, "Permission denied to memory file/device (%s)", f); + log_append(opt->logdata, LOGFL_NORMAL, + LOG_WARNING, "Permission denied to memory file/device (%s)", f); return 0; } /* Read from dump if so instructed */ if(opt->dumpfile != NULL) { - // printf("Reading SMBIOS/DMI data from file %s.\n", dumpfile); - if((buf = mem_chunk(0, 0x20, opt->dumpfile)) != NULL) { - if(memcmp(buf, "_SM_", 4) == 0) { - if(smbios_decode(opt->type, buf, opt->dumpfile, dmixml_n)) - found++; - } else if(memcmp(buf, "_DMI_", 5) == 0) { - if(legacy_decode(opt->type, buf, opt->dumpfile, dmixml_n)) - found++; + if((buf = mem_chunk(opt->logdata, 0, 0x20, opt->dumpfile)) == NULL) { + ret = 1; + goto exit_free; + } + if(memcmp(buf, "_SM3_", 5) == 0){ + if(smbios3_decode(opt->logdata, opt->type, buf,opt->dumpfile, 0, dmixml_n)) + found++; + } else if (memcmp(buf, "_SM_", 4) == 0){ + if(smbios_decode(opt->logdata, opt->type, buf, opt->dumpfile, 0, dmixml_n)) + found++; + } else if (memcmp(buf, "_DMI_", 5) == 0){ + if(legacy_decode(opt->logdata, opt->type, buf, opt->dumpfile, 0, dmixml_n)) + found++; + } + goto done; + } + + /* + * First try reading from sysfs tables. The entry point file could + * contain one of several types of entry points, so read enough for + * the largest one, then determine what type it contains. + */ + size = 0x20; + if ( (buf = read_file(opt->logdata, 0, &size, SYS_ENTRY_FILE)) != NULL){ + if ( size >= 24 && memcmp(buf, "_SM3_", 5) == 0) { + if (smbios3_decode(opt->logdata, opt->type, buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dmixml_n)) + found++; + } else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0){ + if (smbios_decode(opt->logdata, opt->type, buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dmixml_n)) + found++; + } else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0){ + if (legacy_decode(opt->logdata, opt->type, buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dmixml_n)) + found++; + } + if (found) + goto done; + } else { + ret = 1; + goto done; + } + + /* Next try EFI (ia64, Intel-based Mac) */ + efi = address_from_efi(opt->logdata, &fp); + switch(efi){ + case EFI_NOT_FOUND: + goto memory_scan; + case EFI_NO_SMBIOS: + ret = 1; + goto exit_free; + } + + if((buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem)) == NULL ){ + ret = 1; + goto exit_free; + } + + if (memcmp(buf, "_SM3_", 5) == 0){ + if (smbios3_decode(opt->logdata, opt->type, buf + fp, opt->devmem, 0, dmixml_n)) + found++; + } else if (memcmp(buf, "_SM_", 4) == 0){ + if(smbios_decode(opt->logdata, opt->type, buf + fp, opt->devmem, 0, dmixml_n)) + found++; + } + + goto done; + +memory_scan: +#if defined __i386__ || defined __x86_64__ + if((buf = mem_chunk(opt->logdata, 0xF0000, 0x10000, opt->devmem)) == NULL) + { + ret = 1; + goto exit_free; + } + + /* Look for a 64-bit entry point first */ + for (fp = 0; fp <= 0xFFE0; fp += 16){ + if (memcmp(buf + fp, "_SM3_", 5) == 0) + { + if(smbios3_decode(opt->logdata, opt->type, + buf + fp, opt->devmem, 0, dmixml_n)){ + found++; + goto done; } - } else { - ret = 1; } - } else { /* Read from /dev/mem */ - /* First try EFI (ia64, Intel-based Mac) */ - efi = address_from_efi(&fp); - if(efi == EFI_NOT_FOUND) { - /* Fallback to memory scan (x86, x86_64) */ - if((buf = mem_chunk(0xF0000, 0x10000, opt->devmem)) != NULL) { - for(fp = 0; fp <= 0xFFF0; fp += 16) { - if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { - if(smbios_decode(opt->type, buf + fp, opt->devmem, dmixml_n)) { - found++; - fp += 16; - } - } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { - if(legacy_decode(opt->type, buf + fp, opt->devmem, dmixml_n)) - found++; - } - } - } else - ret = 1; - } else if(efi == EFI_NO_SMBIOS) { - ret = 1; - } else { - if((buf = mem_chunk(fp, 0x20, opt->devmem)) == NULL) - ret = 1; - else if(smbios_decode(opt->type, buf, opt->devmem, dmixml_n)) + } + + /* If none found, look for a 32-bit entry point */ + for(fp = 0; fp <= 0xFFF0; fp += 16) { + if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { + if(smbios_decode(opt->logdata, opt->type, + buf + fp, opt->devmem, 0, dmixml_n)) { found++; - // TODO: dmixml_AddAttribute(dmixml_n, "efi_address", "0x%08x", efiAddress); + goto done; + } + } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { + if(legacy_decode(opt->logdata, opt->type, + buf + fp, opt->devmem, 0, dmixml_n)) { + found++; + goto done; + } + } } +#endif + +done: + if( !found ) { + log_append(opt->logdata, LOGFL_NODUPS, LOG_WARNING, + "No SMBIOS nor DMI entry point found, sorry."); } - if(ret == 0) { + +exit_free: + if(buf != NULL) free(buf); - } - //muntrace(); + return ret; } @@ -261,6 +438,7 @@ xmlNode *__dmidecode_xml_getsection(options *opt, const char *section) { // Fetch the Mapping XML file if( (group_n = load_mappingxml(opt)) == NULL) { + xmlFreeNode(dmixml_n); // Exception already set by calling function return NULL; } @@ -297,9 +475,13 @@ xmlNode *__dmidecode_xml_getsection(options *opt, const char *section) { } // Parse the typeid string to a an integer - opt->type = parse_opt_type(typeid); + opt->type = parse_opt_type(opt->logdata, typeid); if(opt->type == -1) { - PyReturnError(PyExc_RuntimeError, "Invalid type id '%s'", typeid); + char *err = log_retrieve(opt->logdata, LOG_ERR); + log_clear_partial(opt->logdata, LOG_ERR, 0); + _pyReturnError(PyExc_RuntimeError, "Invalid type id '%s' -- %s", typeid, err); + free(err); + return NULL; } // Parse the DMI data and put the result into dmixml_n node chain. @@ -318,14 +500,21 @@ xmlNode *__dmidecode_xml_getsection(options *opt, const char *section) { static PyObject *dmidecode_get_group(options *opt, const char *section) { + int efi; + size_t fp; PyObject *pydata = NULL; xmlNode *dmixml_n = NULL; ptzMAP *mapping = NULL; /* Set default option values */ if( opt->devmem == NULL ) { - opt->devmem = DEFAULT_MEM_DEV; - } + efi = address_from_efi(opt->logdata, &fp); + if(efi == EFI_NOT_FOUND){ + opt->devmem = DEFAULT_MEM_DEV; + } else { + opt->devmem = SYS_TABLE_FILE; + } + } opt->flags = 0; // Decode the dmidata into an XML node @@ -336,7 +525,7 @@ static PyObject *dmidecode_get_group(options *opt, const char *section) } // Convert the retrieved XML nodes to a Python dictionary - mapping = dmiMAP_ParseMappingXML_GroupName(opt->mappingxml, section); + mapping = dmiMAP_ParseMappingXML_GroupName(opt->logdata, opt->mappingxml, section); if( mapping == NULL ) { // Exception already set xmlFreeNode(dmixml_n); @@ -344,7 +533,7 @@ static PyObject *dmidecode_get_group(options *opt, const char *section) } // Generate Python dict out of XML node - pydata = pythonizeXMLnode(mapping, dmixml_n); + pydata = pythonizeXMLnode(opt->logdata, mapping, dmixml_n); // Clean up and return the resulting Python dictionary ptzmap_Free(mapping); @@ -356,11 +545,18 @@ static PyObject *dmidecode_get_group(options *opt, const char *section) xmlNode *__dmidecode_xml_gettypeid(options *opt, int typeid) { + int efi; + size_t fp; xmlNode *dmixml_n = NULL; /* Set default option values */ if( opt->devmem == NULL ) { - opt->devmem = DEFAULT_MEM_DEV; + efi = address_from_efi(opt->logdata, &fp); + if(efi == EFI_NOT_FOUND){ + opt->devmem = DEFAULT_MEM_DEV; + } else { + opt->devmem = SYS_TABLE_FILE; + } } opt->flags = 0; @@ -373,6 +569,7 @@ xmlNode *__dmidecode_xml_gettypeid(options *opt, int typeid) // Fetch the Mapping XML file if( load_mappingxml(opt) == NULL) { + xmlFreeNode(dmixml_n); return NULL; } @@ -399,7 +596,7 @@ static PyObject *dmidecode_get_typeid(options *opt, int typeid) } // Convert the retrieved XML nodes to a Python dictionary - mapping = dmiMAP_ParseMappingXML_TypeID(opt->mappingxml, opt->type); + mapping = dmiMAP_ParseMappingXML_TypeID(opt->logdata, opt->mappingxml, opt->type); if( mapping == NULL ) { // FIXME: Should we raise an exception here? // Now it passes the unit-test @@ -407,7 +604,7 @@ static PyObject *dmidecode_get_typeid(options *opt, int typeid) } // Generate Python dict out of XML node - pydata = pythonizeXMLnode(mapping, dmixml_n); + pydata = pythonizeXMLnode(opt->logdata, mapping, dmixml_n); // Clean up and return the resulting Python dictionary ptzmap_Free(mapping); @@ -460,7 +657,12 @@ static PyObject *dmidecode_get_slot(PyObject * self, PyObject * args) static PyObject *dmidecode_get_section(PyObject *self, PyObject *args) { - char *section = PyString_AsString(args); + char *section = NULL; + if (PyUnicode_Check(args)) { + section = PyUnicode_AsUTF8(args); + } else if (PyBytes_Check(args)) { + section = PyBytes_AsString(args); + } if( section != NULL ) { return dmidecode_get_group(global_options, section); @@ -568,7 +770,7 @@ static PyObject *dmidecode_dump(PyObject * self, PyObject * null) stat(f, &_buf); if( (access(f, F_OK) != 0) || ((access(f, W_OK) == 0) && S_ISREG(_buf.st_mode)) ) { - if( dump(DEFAULT_MEM_DEV, f) ) { + if( dump(SYS_TABLE_FILE, f) ) { Py_RETURN_TRUE; } } @@ -578,7 +780,7 @@ static PyObject *dmidecode_dump(PyObject * self, PyObject * null) static PyObject *dmidecode_get_dev(PyObject * self, PyObject * null) { PyObject *dev = NULL; - dev = PyString_FromString((global_options->dumpfile != NULL + dev = PYTEXT_FROMSTRING((global_options->dumpfile != NULL ? global_options->dumpfile : global_options->devmem)); Py_INCREF(dev); return dev; @@ -586,42 +788,64 @@ static PyObject *dmidecode_get_dev(PyObject * self, PyObject * null) static PyObject *dmidecode_set_dev(PyObject * self, PyObject * arg) { - if(PyString_Check(arg)) { + char *f = NULL; + if(PyUnicode_Check(arg)) { + f = PyUnicode_AsUTF8(arg); + } else if(PyBytes_Check(arg)) { + f = PyBytes_AsString(arg); + } + if(f) { struct stat buf; - char *f = PyString_AsString(arg); if( (f != NULL) && (global_options->dumpfile != NULL ) && (strcmp(global_options->dumpfile, f) == 0) ) { Py_RETURN_TRUE; } + if( (f == NULL) || (strlen(f) < 0) ) { + PyReturnError(PyExc_RuntimeError, "set_dev() file name string cannot be empty"); + } - stat(f, &buf); + errno = 0; + if( stat(f, &buf) < 0 ) { + if( errno == ENOENT ) { + // If this file does not exist, that's okay. + // python-dmidecode will create it. + global_options->dumpfile = strdup(f); + Py_RETURN_TRUE; + } + PyReturnError(PyExc_RuntimeError, strerror(errno)); + } if(S_ISCHR(buf.st_mode)) { - if(memcmp(PyString_AsString(arg), "/dev/mem", 8) == 0) { + if(memcmp(f, "/dev/mem", 8) == 0) { if( global_options->dumpfile != NULL ) { free(global_options->dumpfile); global_options->dumpfile = NULL; } Py_RETURN_TRUE; } else { - Py_RETURN_FALSE; + PyReturnError(PyExc_RuntimeError, "Invalid memory device: %s", f); } - } else if(!S_ISDIR(buf.st_mode)) { + } else if(S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode) ) { global_options->dumpfile = strdup(f); Py_RETURN_TRUE; } } - Py_RETURN_FALSE; + PyReturnError(PyExc_RuntimeError, "set_dev(): Invalid input"); } static PyObject *dmidecode_set_pythonxmlmap(PyObject * self, PyObject * arg) { - if(PyString_Check(arg)) { + char *fname = NULL; + + if (PyUnicode_Check(arg)) { + fname = PyUnicode_AsUTF8(arg); + } else if (PyBytes_Check(arg)) { + fname = PyBytes_AsString(arg); + } + if (fname) { struct stat fileinfo; - char *fname = PyString_AsString(arg); memset(&fileinfo, 0, sizeof(struct stat)); - if( stat(fname, &fileinfo) != 0 ) { PyReturnError(PyExc_IOError, "Could not access the file '%s'", fname); } @@ -635,6 +859,29 @@ static PyObject *dmidecode_set_pythonxmlmap(PyObject * self, PyObject * arg) } +static PyObject * dmidecode_get_warnings(PyObject *self, PyObject *null) +{ + char *warn = NULL; + PyObject *ret = NULL; + + warn = log_retrieve(global_options->logdata, LOG_WARNING); + if( warn ) { + ret = PYTEXT_FROMSTRING(warn); + free(warn); + } else { + ret = Py_None; + } + return ret; +} + + +static PyObject * dmidecode_clear_warnings(PyObject *self, PyObject *null) +{ + log_clear_partial(global_options->logdata, LOG_WARNING, 1); + Py_RETURN_TRUE; +} + + static PyMethodDef DMIDataMethods[] = { {(char *)"dump", dmidecode_dump, METH_NOARGS, (char *)"Dump dmidata to set file"}, {(char *)"get_dev", dmidecode_get_dev, METH_NOARGS, @@ -666,14 +913,24 @@ static PyMethodDef DMIDataMethods[] = { {(char *)"pythonmap", dmidecode_set_pythonxmlmap, METH_O, (char *) "Use another python dict map definition. The default file is " PYTHON_XML_MAP}, - {(char *)"xmlapi", dmidecode_xmlapi, METH_KEYWORDS, + {(char *)"xmlapi", dmidecode_xmlapi, METH_VARARGS | METH_KEYWORDS, (char *) "Internal API for retrieving data as raw XML data"}, + + {(char *)"get_warnings", dmidecode_get_warnings, METH_NOARGS, + (char *) "Retrieve warnings from operations"}, + + {(char *)"clear_warnings", dmidecode_clear_warnings, METH_NOARGS, + (char *) "Clear all warnings"}, + {NULL, NULL, 0, NULL} }; void destruct_options(void *ptr) { +#ifdef IS_PY3K + ptr = PyCapsule_GetPointer(ptr, NULL); +#endif options *opt = (options *) ptr; if( opt->mappingxml != NULL ) { @@ -696,11 +953,40 @@ void destruct_options(void *ptr) opt->dumpfile = NULL; } + if( opt->logdata != NULL ) { + char *warn = NULL; + + log_clear_partial(opt->logdata, LOG_WARNING, 0); + warn = log_retrieve(opt->logdata, LOG_WARNING); + if( warn ) { + fprintf(stderr, "\n** COLLECTED WARNINGS **\n%s** END OF WARNINGS **\n\n", warn); + free(warn); + } + log_close(opt->logdata); + } + free(ptr); } +#ifdef IS_PY3K +static struct PyModuleDef dmidecodemod_def = { + PyModuleDef_HEAD_INIT, + "dmidecodemod", + NULL, + -1, + DMIDataMethods, + NULL, + NULL, + NULL, + NULL +}; -PyMODINIT_FUNC initdmidecodemod(void) +PyMODINIT_FUNC +PyInit_dmidecodemod(void) +#else +PyMODINIT_FUNC +initdmidecodemod(void) +#endif { char *dmiver = NULL; PyObject *module = NULL; @@ -711,21 +997,36 @@ PyMODINIT_FUNC initdmidecodemod(void) xmlXPathInit(); opt = (options *) malloc(sizeof(options)+2); + if (opt == NULL) + MODINITERROR; + memset(opt, 0, sizeof(options)+2); init(opt); +#ifdef IS_PY3K + module = PyModule_Create(&dmidecodemod_def); +#else module = Py_InitModule3((char *)"dmidecodemod", DMIDataMethods, "Python extension module for dmidecode"); +#endif + if (module == NULL) { + free(opt); + MODINITERROR; + } - version = PyString_FromString(VERSION); + version = PYTEXT_FROMSTRING(VERSION); Py_INCREF(version); PyModule_AddObject(module, "version", version); opt->dmiversion_n = dmidecode_get_version(opt); dmiver = dmixml_GetContent(opt->dmiversion_n); - PyModule_AddObject(module, "dmi", dmiver ? PyString_FromString(dmiver) : Py_None); + PyModule_AddObject(module, "dmi", dmiver ? PYTEXT_FROMSTRING(dmiver) : Py_None); // Assign this options struct to the module as well with a destructor, that way it will // clean up the memory for us. - PyModule_AddObject(module, "options", PyCObject_FromVoidPtr(opt, destruct_options)); + // TODO: destructor has wrong type under py3? + PyModule_AddObject(module, "options", PyCapsule_New(opt, NULL, destruct_options)); global_options = opt; +#ifdef IS_PY3K + return module; +#endif } diff --git a/src/dmidecodemodule.h b/src/dmidecodemodule.h index c0be3a1..044317e 100644 --- a/src/dmidecodemodule.h +++ b/src/dmidecodemodule.h @@ -66,12 +66,14 @@ xmlNode *dmidecode_get_version(options *); extern void dmi_dump(xmlNode *node, struct dmi_header *h); -extern int address_from_efi(size_t * address); +extern int address_from_efi(Log_t *logp, size_t * address); extern void to_dmi_header(struct dmi_header *h, u8 * data); -extern int smbios_decode(int type, u8 *buf, const char *devmem, xmlNode *node); -extern int legacy_decode(int type, u8 *buf, const char *devmem, xmlNode *node); +extern int smbios3_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *node); +extern int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *node); +extern int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *node); +extern xmlNode *smbios3_decode_get_version(u8 * buf, const char *devmem); extern xmlNode *smbios_decode_get_version(u8 * buf, const char *devmem); extern xmlNode *legacy_decode_get_version(u8 * buf, const char *devmem); -extern void *mem_chunk(size_t base, size_t len, const char *devmem); +extern void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem); PyMODINIT_FUNC initdmidecode(void); diff --git a/src/dmidump.c b/src/dmidump.c index a07c975..07f24e9 100644 --- a/src/dmidump.c +++ b/src/dmidump.c @@ -51,106 +51,216 @@ static void overwrite_dmi_address(u8 * buf) buf[0x0B] = 0; } -int dumpling(u8 * buf, const char *dumpfile, u8 mode) +/* Same thing for SMBIOS3 entry points */ +static void overwrite_smbios3_address(u8 *buf) { - u32 base; - u16 len; - - if(mode == NON_LEGACY) { - if(!checksum(buf, buf[0x05]) || !memcmp(buf + 0x10, "_DMI_", 5) == 0 || - !checksum(buf + 0x10, 0x0F)) - return 0; - base = DWORD(buf + 0x18); - len = WORD(buf + 0x16); - } else { - if(!checksum(buf, 0x0F)) - return 0; - base = DWORD(buf + 0x08); - len = WORD(buf + 0x06); + buf[0x05] += buf[0x10] + buf[0x11] + buf[0x12] + buf[0x13] + + buf[0x14] + buf[0x15] + buf[0x16] + buf[0x17] - 32; + buf[0x10] = 32; + buf[0x11] = 0; + buf[0x12] = 0; + buf[0x13] = 0; + buf[0x14] = 0; + buf[0x15] = 0; + buf[0x16] = 0; + buf[0x17] = 0; +} + +void dmi_table_dump(const u8 *buf, u32 len, const char *dumpfile) +{ + write_dump(32, len, buf, dumpfile, 0); +} + +void dmi_table(off_t base, u32 len, u16 num, u32 ver, const char *devmem, + u32 flags, const char *dumpfile) +{ + u8 *buf; + size_t size = len; + + buf = read_file(NULL, flags & FLAG_NO_FILE_OFFSET ? 0 : base, + &size, devmem); + len = size; + + if (buf == NULL) + { + printf("read failed\n"); } + dmi_table_dump(buf, len, dumpfile); + free(buf); +} - u8 *buff; +static int smbios3_decode(u8 *buf, const char *devmem, u32 flags, const char *dumpfile) +{ + u32 ver; + u64 offset; + offset = QWORD(buf + 0x10); + ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; - if((buff = mem_chunk(base, len, DEFAULT_MEM_DEV)) != NULL) { - //. Part 1. -#ifdef NDEBUG - printf("# Writing %d bytes to %s.\n", len, dumpfile); -#endif - write_dump(32, len, buff, dumpfile, 0); - free(buff); + if (!checksum(buf, buf[0x06])) + return 0; - //. Part 2. - if(mode != LEGACY) { - u8 crafted[32]; + dmi_table(((off_t)offset.h << 32) | offset.l,DWORD(buf + 0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT, dumpfile); - memcpy(crafted, buf, 32); - overwrite_dmi_address(crafted + 0x10); -#ifdef NDEBUG - printf("# Writing %d bytes to %s.\n", crafted[0x05], dumpfile); -#endif - write_dump(0, crafted[0x05], crafted, dumpfile, 1); - } else { - u8 crafted[16]; - - memcpy(crafted, buf, 16); - overwrite_dmi_address(crafted); -#ifdef NDEBUG - printf("# Writing %d bytes to %s.\n", 0x0F, dumpfile); -#endif - write_dump(0, 0x0F, crafted, dumpfile, 1); - } - } else { - fprintf(stderr, "Failed to read table, sorry.\n"); + u8 crafted[32]; + memcpy(crafted, buf, 32); + overwrite_smbios3_address(crafted); + //overwrite_dmi_address(crafted); + //printf("Writing %d bytes to %s.",crafted[0x06], dumpfile); + write_dump(0, crafted[0x06], crafted, dumpfile, 1); + return 1; +} + +static int smbios_decode(u8 *buf, const char *devmem, u32 flags, const char *dumpfile) +{ + u16 ver; + if (!checksum(buf, buf[0x05]) + || memcmp(buf + 0x10, "_DMI_", 5) != 0 + || !checksum(buf + 0x10, 0x0F)) + return 0; + + ver = (buf[0x06] << 8) + buf[0x07]; + switch (ver) + { + case 0x021F: + case 0x0221: + ver = 0x0203; + break; + case 0x0233: + ver = 0x0206; + break; } - //. TODO: Cleanup + + dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C), + ver << 8, devmem, flags, dumpfile); + + u8 crafted[32]; + memcpy(crafted, buf, 32); + overwrite_dmi_address(crafted + 0x10); + write_dump(0, crafted[0x05], crafted, dumpfile, 1); + return 1; } +static int legacy_decode(u8 *buf, const char *devmem, u32 flags, const char *dumpfile) +{ + u8 crafted[16]; + + //dmi_table(); + dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C), + ((buf[0x0E] & 0xF0) << 12) + ((buf[0x0E] & 0x0F) << 8), + devmem, flags, dumpfile); + + memcpy(crafted, buf, 16); + overwrite_smbios3_address(crafted); + write_dump(0, 0x0F, crafted, dumpfile, 1); + + return 1; +} int dump(const char *memdev, const char *dumpfile) { - /* On success, return found, otherwise return -1 */ + /* On success, return found, otherwise return 0 */ int ret = 0; int found = 0; size_t fp; int efi; u8 *buf; + size_t size; + + /* + * First try reading from sysfs tables. The entry point file could + * contain one of several types of entry points, so read enough for + * the largest one, then determine what type it contains. + */ + size = 0x20; + if ( (buf = read_file(NULL, 0, &size, SYS_ENTRY_FILE)) != NULL){ + if (size >= 24 && memcmp(buf, "_SM3_", 5) == 0){ + if (smbios3_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dumpfile)) + found++; + } else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0) { + if (smbios_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dumpfile)) + found++; + } else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0){ + if (legacy_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dumpfile)) + found++; + } + if (found){ + ret = 1; + goto exit_free; + } + } /* First try EFI (ia64, Intel-based Mac) */ - efi = address_from_efi(&fp); - if(efi == EFI_NOT_FOUND) { - /* Fallback to memory scan (x86, x86_64) */ - if((buf = mem_chunk(0xF0000, 0x10000, memdev)) != NULL) { - for(fp = 0; fp <= 0xFFF0; fp += 16) { - if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { - if(dumpling(buf + fp, dumpfile, NON_LEGACY)) - found++; - fp += 16; - } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { - if(dumpling(buf + fp, dumpfile, LEGACY)) - found++; - } - } - } else - ret = -1; - } else if(efi == EFI_NO_SMBIOS) { - ret = -1; - } else { - if((buf = mem_chunk(fp, 0x20, memdev)) == NULL) - ret = -1; - else if(dumpling(buf, dumpfile, NON_LEGACY)) + efi = address_from_efi(NULL, &fp); + switch(efi) + { + case EFI_NOT_FOUND: + goto memory_scan; + case EFI_NO_SMBIOS: + ret = 1; + goto exit_free; + } + + if ((buf = mem_chunk(NULL, fp, 0x20, memdev )) == NULL){ + ret = 1; + goto exit_free; + } + + if (memcmp(buf, "_SM3_", 5) == 0){ + if(smbios3_decode(buf, memdev, 0, dumpfile)) + found++; + } else if (memcmp(buf, "_SM_", 4) == 0){ + if(smbios_decode(buf, memdev, 0, dumpfile)) found++; } + goto done; - if(ret == 0) { - free(buf); - if(!found) { - ret = -1; +memory_scan: +#if defined __i386__ || defined __x86_64__ + /* Fallback to memory scan (x86, x86_64) */ + if((buf = mem_chunk(NULL, 0xF0000, 0x10000, memdev)) == NULL) { + ret = 1; + goto exit_free; + } + + /* Look for a 64-bit entry point first */ + for(fp = 0; fp <= 0xFFF0; fp += 16){ + if(memcmp(buf + fp, "_SM3_", 5) == 0 && fp <= 0xFFE0){ + if(smbios3_decode(buf + fp, memdev, 0, dumpfile)){ + found++; + goto done; + } } } - return ret == 0 ? found : ret; + /* If none found, look for a 32-bit entry point */ + for(fp = 0; fp <= 0xFFF0; fp += 16) { + if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { + if(smbios_decode(buf + fp, memdev, 0, dumpfile)){ + found++; + goto done; + } + } else if (memcmp(buf+fp, "_DMI_", 5) == 0){ + if(legacy_decode(buf+fp, memdev, 0, dumpfile)){ + found++; + goto done; + } + } + } +#endif + +done: + if(!found){ + printf("No SMBIOS nor DMI entry point found, sorry.\n"); + } + free(buf); + +exit_free: + if (!found) + free(buf); + + return ret; } diff --git a/src/dmidump.h b/src/dmidump.h index 3c12248..a025829 100644 --- a/src/dmidump.h +++ b/src/dmidump.h @@ -32,6 +32,13 @@ #define NON_LEGACY 0 #define LEGACY 1 +#define FLAG_NO_FILE_OFFSET (1 << 0) +#define FLAG_STOP_AT_EOT (1 << 1) + +#define SYS_FIRMWARE_DIR "/sys/firmware/dmi/tables" +#define SYS_ENTRY_FILE SYS_FIRMWARE_DIR "/smbios_entry_point" +#define SYS_TABLE_FILE SYS_FIRMWARE_DIR "/DMI" + int dump(const char *memdev, const char *dumpfile); #endif diff --git a/src/dmierror.c b/src/dmierror.c index d64b4b9..7054cd8 100644 --- a/src/dmierror.c +++ b/src/dmierror.c @@ -52,7 +52,6 @@ void _pyReturnError(void *exception, const char *fname, int line, const char *fm va_start(ap, fmt); buf = (char *) malloc(4098); - memset(buf, 0, 4098); if( buf == NULL ) { // Backup routine if we can't get the needed memory @@ -64,6 +63,7 @@ void _pyReturnError(void *exception, const char *fname, int line, const char *fm return; } + memset(buf, 0, 4098); // Set the error state and message snprintf(buf, 4096, "[%s:%i] %s", fname, line, fmt); PyErr_Format(exception, buf, ap); diff --git a/src/dmihelper.h b/src/dmihelper.h index d89c024..3811392 100644 --- a/src/dmihelper.h +++ b/src/dmihelper.h @@ -53,6 +53,7 @@ #include #include "types.h" +#include "dmilog.h" #define MAXVAL 1024 @@ -64,61 +65,55 @@ typedef struct _dmi_codes_major { } dmi_codes_major; static const dmi_codes_major dmiCodesMajor[] = { - {0, "3.3.1", "BIOS Information", "BIOSinfo"}, - {1, "3.3.2", "System Information", "SystemInfo"}, - {2, "3.3.3", "Base Board Information", "BaseBoardInfo"}, - {3, "3.3.4", "Chassis Information", "ChassisInfo"}, - {4, "3.3.5", "Processor Information", "ProcessorInfo"}, - {5, "3.3.6", "Memory Controller Information", "MemoryCtrlInfo"}, - {6, "3.3.7", "Memory Module Information", "MemoryModuleInfo"}, - {7, "3.3.8", "Cache Information", "CacheInfo"}, - {8, "3.3.9", "Port Connector Information", "PortConnectorInfo"}, - {9, "3.3.10", "System Slots", "SystemSlots"}, - {10, "3.3.11", "On Board Devices Information", "OnBoardDevicesInfo"}, - {11, "3.3.12", "OEM Strings", "OEMstrings"}, - {12, "3.3.13", "System Configuration Options", "SysConfigOptions"}, - {13, "3.3.14", "BIOS Language Information", "BIOSlanguage"}, - {14, "3.3.15", "Group Associations", "GroupAssoc"}, - {15, "3.3.16", "System Event Log", "SysEventLog"}, - {16, "3.3.17", "Physical Memory Array", "PhysicalMemoryArray"}, - {17, "3.3.18", "Memory Device", "MemoryDevice"}, - {18, "3.3.19", "32-bit Memory Error Information", "MemoryErrorInfo"}, - {19, "3.3.20", "Memory Array Mapped Address", "MemoryArrayMappedAddress"}, - {20, "3.3.21", "Memory Device Mapped Address", "MemoryDeviceMappedAddress"}, - {21, "3.3.22", "Built-in Pointing Device", "BuiltIntPointingDevice"}, - {22, "3.3.23", "Portable Battery", "PortableBattery"}, - {23, "3.3.24", "System Reset", "SystemReset"}, - {24, "3.3.25", "Hardware Security", "HardwareSecurity"}, - {25, "3.3.26", "System Power Controls", "SystemPowerCtrls"}, - {26, "3.3.27", "Voltage Probe", "Probe"}, - {27, "3.3.28", "Cooling Device", "CoolingDevice"}, - {28, "3.3.29", "Temperature Probe", "Probe"}, - {29, "3.3.30", "Electrical Current Probe", "Probe"}, - {30, "3.3.31", "Out-of-band Remote Access", "RemoteAccess"}, - {31, "3.3.32", "Boot Integrity Services Entry Point", "BootIntegrity"}, - {32, "3.3.33", "System Boot Information", "SystemBootInfo"}, - {33, "3.3.34", "64-bit Memory Error Information", "MemoryErrorInfo"}, - {34, "3.3.35", "Management Device", "ManagementDevice"}, - {35, "3.3.36", "Management Device Component", "ManagementDevice"}, - {36, "3.3.37", "Management Device Threshold Data", "ManagementDevice"}, - {37, "3.3.38", "Memory Channel", "MemoryChannel"}, - {38, "3.3.39", "IPMI Device Information", "IPMIdeviceInfo"}, - {39, "3.3.40", "System Power Supply", "SystemPowerSupply"}, - {40, "3.3.41", "-------------------", "Unknown"}, - {41, "3.3.42", "-------------------", "Unknown"}, - {126, "3.3.41", "Inactive", "Inactive"}, - {127, "3.3.42", "End Of Table", "EndOfTable"}, + {0, "7.1", "BIOS Information", "BIOSinfo"}, + {1, "7.2", "System Information", "SystemInfo"}, + {2, "7.3", "Base Board Information", "BaseBoardInfo"}, + {3, "7.4", "Chassis Information", "ChassisInfo"}, + {4, "7.5", "Processor Information", "ProcessorInfo"}, + {5, "7.6", "Memory Controller Information", "MemoryCtrlInfo"}, + {6, "7.7", "Memory Module Information", "MemoryModuleInfo"}, + {7, "7.8", "Cache Information", "CacheInfo"}, + {8, "7.9", "Port Connector Information", "PortConnectorInfo"}, + {9, "7.10", "System Slots", "SystemSlots"}, + {10, "7.11", "On Board Devices Information", "OnBoardDevicesInfo"}, + {11, "7.12", "OEM Strings", "OEMstrings"}, + {12, "7.13", "System Configuration Options", "SysConfigOptions"}, + {13, "7.14", "BIOS Language Information", "BIOSlanguage"}, + {14, "7.15", "Group Associations", "GroupAssoc"}, + {15, "7.16", "System Event Log", "SysEventLog"}, + {16, "7.17", "Physical Memory Array", "PhysicalMemoryArray"}, + {17, "7.18", "Memory Device", "MemoryDevice"}, + {18, "7.19", "32-bit Memory Error Information", "MemoryErrorInfo"}, + {19, "7.20", "Memory Array Mapped Address", "MemoryArrayMappedAddress"}, + {20, "7.21", "Memory Device Mapped Address", "MemoryDeviceMappedAddress"}, + {21, "7.22", "Built-in Pointing Device", "BuiltIntPointingDevice"}, + {22, "7.23", "Portable Battery", "PortableBattery"}, + {23, "7.24", "System Reset", "SystemReset"}, + {24, "7.25", "Hardware Security", "HardwareSecurity"}, + {25, "7.26", "System Power Controls", "SystemPowerCtrls"}, + {26, "7.27", "Voltage Probe", "Probe"}, + {27, "7.28", "Cooling Device", "CoolingDevice"}, + {28, "7.29", "Temperature Probe", "Probe"}, + {29, "7.30", "Electrical Current Probe", "Probe"}, + {30, "7.31", "Out-of-band Remote Access", "RemoteAccess"}, + {31, "7.32", "Boot Integrity Services Entry Point", "BootIntegrity"}, + {32, "7.33", "System Boot Information", "SystemBootInfo"}, + {33, "7.34", "64-bit Memory Error Information", "MemoryErrorInfo"}, + {34, "7.35", "Management Device", "ManagementDevice"}, + {35, "7.36", "Management Device Component", "ManagementDevice"}, + {36, "7.37", "Management Device Threshold Data", "ManagementDevice"}, + {37, "7.38", "Memory Channel", "MemoryChannel"}, + {38, "7.39", "IPMI Device Information", "IPMIdeviceInfo"}, + {39, "7.40", "System Power Supply", "SystemPowerSupply"}, + {40, "7.41", "-------------------", "Unknown"}, + {41, "7.42", "Onboard Device Extended Information", "OnBoardDevicesExtendedInfo"}, + {41, "7.43", "Management Controller Host Interface", "MgmntCtrltHostIntf"}, + {126, "7.44", "Inactive", "Inactive"}, + {127, "7.45", "End Of Table", "EndOfTable"}, + {-1, NULL, NULL, NULL} }; -typedef struct _dmi_minor { - long id; - dmi_codes_major *major; - char *key; - char value[MAXVAL]; - struct _dmi_minor *next; -} dmi_minor; - /*** dmiopt.h ***/ typedef struct _options { const char *devmem; @@ -128,6 +123,7 @@ typedef struct _options { char *python_xml_map; xmlNode *dmiversion_n; char *dumpfile; + Log_t *logdata; } options; #endif diff --git a/src/dmilog.c b/src/dmilog.c new file mode 100644 index 0000000..80b2ac3 --- /dev/null +++ b/src/dmilog.c @@ -0,0 +1,223 @@ +/* + * 2009 (C) David Sommerseth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open unpatent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + */ + +/** + * @file dmilog.h + * @brief A simple log module + * @author David Sommerseth + */ + +#include +#include +#include +#include + +#include "dmilog.h" + +/** + * Allocates memory for a new Log_t record + * + * @return Returns a pointer to a new Log_t record, otherwise NULL on error + */ +Log_t * log_init() +{ + Log_t *ret = NULL; + + ret = (Log_t *) calloc(1, sizeof(Log_t)+2); + if( !ret ) { + fprintf(stderr, "** ERROR ** Could not allocate memory for log data\n"); + return ret; + } + ret->level = -1; // Initialised - chain header pointer always have -1. + return ret; +} + + + + +/** + * Registers a new log entry + * + * @param logp Pointer to an allocated Log_t record. New records will be appended to the end + * @param flags Log flags, to specify logging behaviour + * @param level syslog log level values. LOG_ERR and LOG_WARNING are allowed + * @param fmt stdarg based string with the log contents + * + * @return Returns 1 on successful registration of log entry, otherwise -1 and error is printed to stderr + * unless LOGFL_NOSTDERR is set in flags. + */ +int log_append(Log_t *logp, Log_f flags, int level, const char *fmt, ...) +{ + Log_t *ptr = NULL; + va_list ap; + char logmsg[4098]; + + // Prepare log message + memset(&logmsg, 0, 4098); + va_start(ap, fmt); + vsnprintf(logmsg, 4096, fmt, ap); + va_end(ap); + + // Go the end of the record chain + ptr = logp; + while( ptr && ptr->next ) { + // Ignore duplicated messages if LOGFL_NODUPS is set + if( (flags & LOGFL_NODUPS) && ptr->next && ptr->next->message + && (strcmp(ptr->next->message, logmsg) == 0) ) { + return 1; + } + ptr = ptr->next; + } + + if( ptr && ((level == LOG_ERR) || (level == LOG_WARNING)) ) { + ptr->next = log_init(); + if( ptr->next ) { + ptr->next->level = level; + ptr->next->message = strdup(logmsg); + return 1; + } + } + + if( !(flags & LOGFL_NOSTDERR) ) { + if( logp ) { + // Only print this if we logp is pointing somewhere. + // If it is NULL, the caller did not establish a log + // buffer on purpose (like dmidump.c) - thus this is + // not an error with saving the log entry. + fprintf(stderr, "** ERROR ** Failed to save log entry\n"); + } + fprintf(stderr, "%s\n", logmsg); + } + return -1; +} + + +/** + * Retrieve all log entries in the Log_t record chain with the corresponding log level. + * One string will be returned, with all log entries separated with newline. + * + * @param logp Pointer to Log_t record chain with log data + * @param level Log entries to retrieve + * + * @return Returns a pointer to a buffer with all log lines. This must be freed after usage. + */ +char * log_retrieve(Log_t *logp, int level) +{ + char *ret = NULL; + size_t len = 0; + Log_t *ptr = NULL; + + if( !logp ) { + return NULL; + } + + for( ptr = logp; ptr != NULL; ptr = ptr->next ) { + if( ptr && ptr->level == level ) { + if( ret ) { + ret = realloc(ret, strlen(ptr->message)+len+3); + } else { + ret = calloc(1, strlen(ptr->message)+2); + } + + if( !ret ) { + fprintf(stderr, + "** ERROR ** Could not allocate log retrieval memory buffer\n"); + return NULL; + } + strcat(ret, ptr->message); + strcat(ret, "\n"); + ptr->read++; + len = strlen(ret); + } + } + return ret; +} + + +/** + * Remove only log records of a particular log level from the log chain. Only + * records that have been read (by using log_retrieve()) will be removed unless + * the unread argument == 1. + * + * @param logp Pointer to log chain to work on + * @param level Log level to remove + * @param unread Set to 1 to also clear unread log entriesz + * + * @return Returns number of removed elements. + */ +size_t log_clear_partial(Log_t *logp, int level, int unread) +{ + Log_t *ptr = NULL, *prev = NULL; + size_t elmnt = 0; + + if( !logp ) { + return 0; + } + + prev = logp; + for( ptr = logp->next; ptr != NULL; ptr = ptr->next ) { + if( !ptr ) { + break; + } + + // Only remove log entries which is of the expected log level + // and that have been read. + if( (ptr->level == level) && ((unread == 1) || (ptr->read > 0)) ) { + prev->next = ptr->next; + if( ptr->message ) { + free(ptr->message); + ptr->message = NULL; + } + free(ptr); + ptr = prev; + elmnt++; + } + prev = ptr; + } + + return elmnt; +} + + +/** + * Free all memory used by a Log_t pointer chain. + * + * @param logp Pointer to log entries to free up. + */ +void log_close(Log_t *logp) +{ + Log_t *ptr = NULL, *next = NULL; + + ptr = logp; + while( ptr ) { + next = ptr->next; + ptr->next = NULL; + if( ptr->message ) { + free(ptr->message); + ptr->message = NULL; + } + free(ptr); + ptr = next; + } +} diff --git a/src/dmilog.h b/src/dmilog.h new file mode 100644 index 0000000..76c87b6 --- /dev/null +++ b/src/dmilog.h @@ -0,0 +1,63 @@ +/* + * 2009 (C) David Sommerseth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open unpatent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + */ + +/** + * @file dmilog.h + * @brief A simple log module + * @author David Sommerseth + */ + + +#ifndef DMILOG_H +#define DMILOG_H + +#include +#include + +/** + * Struct defining log records. Organised as a pointer chain. + */ +struct _Log_t { + int level; /**< Log type, based on syslog levels (LOG_ERR|LOG_WARNING) */ + char *message; /**< Formated log text */ + unsigned int read; /**< Number of times this log entry has been read */ + struct _Log_t *next; /**< Next log entry */ +}; +typedef struct _Log_t Log_t; + +/** + * Log flags. These flags can be OR'ed together + */ +typedef enum { LOGFL_NORMAL = 1, /**< Normal behaviour, log everything and use stderr on errors */ + LOGFL_NODUPS = 2, /**< Don't log messages we already have logged */ + LOGFL_NOSTDERR = 4 /**< Don't use stderr even if log functions fails */ +} Log_f; + +Log_t * log_init(); +int log_append(Log_t *logp, Log_f flags, int level, const char *fmt, ...); +char * log_retrieve(Log_t *logp, int level); +size_t log_clear_partial(Log_t *logp, int level, int unread); +void log_close(Log_t *logp); + +#endif diff --git a/src/dmioem.c b/src/dmioem.c index 361810a..055b39f 100644 --- a/src/dmioem.c +++ b/src/dmioem.c @@ -40,10 +40,19 @@ static enum DMI_VENDORS dmi_vendor = VENDOR_UNKNOWN; * value if we know how to decode at least one specific entry type for * that vendor. */ -void dmi_set_vendor(const char *s) +void dmi_set_vendor(const struct dmi_header *h) { - if(strcmp(s, "HP") == 0) + const char *vendor; + + if( !h || !h->data ) { + return; + } + vendor = dmi_string(h, h->data[0x04]); + if( !vendor ) { + return; + } else if(strcmp(vendor, "HP") == 0) { dmi_vendor = VENDOR_HP; + } } /* @@ -84,7 +93,7 @@ static int dmi_decode_hp(struct dmi_header *h) */ printf(h->type == 221 ? "HP BIOS iSCSI NIC PCI and MAC Information\n" : - "HP BIOS NIC PCI and MAC Information\n"); + "HP BIOS NIC PXE PCI and MAC Information\n"); nic = 1; ptr = 4; while(h->length >= ptr + 8) { diff --git a/src/dmioem.h b/src/dmioem.h index b1b4af8..9ad25bf 100644 --- a/src/dmioem.h +++ b/src/dmioem.h @@ -22,5 +22,5 @@ struct dmi_header; -void dmi_set_vendor(const char *s); +void dmi_set_vendor(const struct dmi_header *h); int dmi_decode_oem(struct dmi_header *h); diff --git a/src/dmixml.c b/src/dmixml.c index 5d9f1a1..682acc7 100644 --- a/src/dmixml.c +++ b/src/dmixml.c @@ -41,6 +41,8 @@ #include #include +#include "dmidecode.h" +#include "dmilog.h" #include "dmixml.h" /** @@ -91,13 +93,18 @@ xmlAttr *dmixml_AddAttribute(xmlNode *node, const char *atrname, const char *fmt xmlAttr *res = NULL; va_list ap; - if( (node == NULL) || (atrname == NULL) || (fmt == NULL) ) { + if( (node == NULL) || (atrname == NULL) ) { return NULL; } atrname_s = xmlCharStrdup(atrname); assert( atrname_s != NULL ); + if( fmt == NULL ) { + res = xmlNewProp(node, atrname_s, NULL); + goto exit; + } + va_start(ap, fmt); val_s = dmixml_buildstr(2048, fmt, ap); va_end(ap); @@ -105,8 +112,9 @@ xmlAttr *dmixml_AddAttribute(xmlNode *node, const char *atrname, const char *fmt res = xmlNewProp(node, atrname_s, (xmlStrcmp(val_s, (xmlChar *) "(null)") == 0 ? NULL : val_s)); - free(atrname_s); free(val_s); + exit: + free(atrname_s); assert( res != NULL ); return res; @@ -128,13 +136,18 @@ xmlNode *dmixml_AddTextChild(xmlNode *node, const char *tagname, const char *fmt xmlNode *res = NULL; va_list ap; - if( (node == NULL) || (tagname == NULL) || (fmt == NULL) ) { + if( (node == NULL) || (tagname == NULL) ) { return NULL; } tagname_s = xmlCharStrdup(tagname); assert( tagname_s != NULL ); + if( fmt == NULL ) { + res = xmlNewChild(node, NULL, tagname_s, NULL); + goto exit; + } + va_start(ap, fmt); val_s = dmixml_buildstr(2048, fmt, ap); va_end(ap); @@ -143,13 +156,66 @@ xmlNode *dmixml_AddTextChild(xmlNode *node, const char *tagname, const char *fmt res = xmlNewTextChild(node, NULL, tagname_s, (xmlStrcmp(val_s, (xmlChar *) "(null)") == 0 ? NULL : val_s)); - free(tagname_s); free(val_s); + exit: + free(tagname_s); assert( res != NULL ); return res; } +/** + * A variant of dmixml_AddTextChild() which will do dmi_string() decoding instead of a plain string. + * If the dmi_string() function returns NULL, it will instead add a XML node attribute 'badindex' + * @author David Sommerseth + * @param xmlNode* Pointer to the current node which will get the text child + * @param const char* Name of the new tag + * @param const struct dmi_header* Pointer to the DMI table header + * @param u8 DMI table index of the information to be extracted and used in the XML node + * @return xmlNode* Pointer to the new tag. On errors the return value will be NULL. On fatal + * errors and assert() call will be done. + */ +xmlNode *dmixml_AddDMIstring(xmlNode *node, const char *tagname, const struct dmi_header *dm, u8 s) { + xmlChar *tagname_s = NULL; + xmlNode *res = NULL; + const char *dmistr; + + if( (node == NULL) || (tagname == NULL) ) { + return NULL; + } + + tagname_s = xmlCharStrdup(tagname); + assert( tagname_s != NULL ); + + if(s == 0) { + res = xmlNewChild(node, NULL, tagname_s, NULL); + dmixml_AddAttribute(res, "not_specified", "1"); + return res; + } + + dmistr = dmi_string(dm, s); + if( dmistr == NULL ) { + res = xmlNewChild(node, NULL, tagname_s, NULL); + dmixml_AddAttribute(res, "badindex", "1"); + } else { + xmlChar *ret = NULL; + xmlChar *ptr = NULL; + xmlChar *val_s = xmlCharStrdup(dmistr); + // Right trim the string + ret = val_s; + ptr = ret + xmlStrlen(ret) - 1; + while( (ptr >= ret) && (*ptr == ' ') ) { + *ptr = 0; + ptr--; + } + // Do not add any contents if the string contents is "(null)" + res = xmlNewTextChild(node, NULL, tagname_s, + (xmlStrcmp(val_s, (xmlChar *) "(null)") == 0 ? NULL : val_s)); + free(val_s); + } + return res; +} + /** * Adds a text node child to the given XML node. If input is NULL, the tag contents will be empty. * @author David Sommerseth @@ -164,7 +230,9 @@ xmlNode *dmixml_AddTextContent(xmlNode *node, const char *fmt, ...) va_list ap; if( (node == NULL) || (fmt == NULL) ) { - return NULL; + // Return node and not NULL, as node may not be NULL but fmt can be, + // thus doing a similar string check (val_s != "(null)") as later on + return node; } va_start(ap, fmt); @@ -323,7 +391,7 @@ inline char *dmixml_GetNodeContent(xmlNode *node, const char *key) { * which of the elements to be extracted. * @return char* Points at the return buffer if a value is found, otherwise NULL is returned. */ -char *dmixml_GetXPathContent(char *buf, size_t buflen, xmlXPathObject *xpo, int idx) { +char *dmixml_GetXPathContent(Log_t *logp, char *buf, size_t buflen, xmlXPathObject *xpo, int idx) { memset(buf, 0, buflen); if( xpo == NULL ) { @@ -351,9 +419,9 @@ char *dmixml_GetXPathContent(char *buf, size_t buflen, xmlXPathObject *xpo, int break; default: - fprintf(stderr, "dmixml_GetXPathContent(...):: " - "Do not know how to handle XPath type %i\n", - xpo->type); + log_append(logp, LOGFL_NORMAL, LOG_WARNING, "dmixml_GetXPathContent(...):: " + "Do not know how to handle XPath type %i", + xpo->type); return NULL; } return buf; diff --git a/src/dmixml.h b/src/dmixml.h index 3dc32e5..28ba2b7 100644 --- a/src/dmixml.h +++ b/src/dmixml.h @@ -32,8 +32,11 @@ #define foreach_xmlnode(n, itn) for( itn = n; itn != NULL; itn = itn->next ) +struct dmi_header; + xmlAttr *dmixml_AddAttribute(xmlNode *node, const char *atrname, const char *fmt, ...); xmlNode *dmixml_AddTextChild(xmlNode *node, const char *tagname, const char *fmt, ...); +xmlNode *dmixml_AddDMIstring(xmlNode *node, const char *tagname, const struct dmi_header *dm, u8 s); xmlNode *dmixml_AddTextContent(xmlNode *node, const char *fmt, ...); char *dmixml_GetAttrValue(xmlNode *node, const char *key); @@ -72,8 +75,8 @@ xmlNode *__dmixml_FindNodeByAttr(xmlNode *, const char *, const char *, const ch xmlNode *dmixml_FindNode(xmlNode *, const char *key); -inline char *dmixml_GetContent(xmlNode *node); -inline char *dmixml_GetNodeContent(xmlNode *node, const char *key); -char *dmixml_GetXPathContent(char *buf, size_t buflen, xmlXPathObject *xpo, int idx); +char *dmixml_GetContent(xmlNode *node); +char *dmixml_GetNodeContent(xmlNode *node, const char *key); +char *dmixml_GetXPathContent(Log_t *logp, char *buf, size_t buflen, xmlXPathObject *xpo, int idx); #endif diff --git a/src/efi.c b/src/efi.c index 9802171..e519257 100644 --- a/src/efi.c +++ b/src/efi.c @@ -28,6 +28,8 @@ #include #include #include + +#include "dmilog.h" #include "efi.h" /** @@ -42,11 +44,12 @@ * @param size_t* * @return returns EFI_NOT_FOUND or EFI_NO_SMBIOS */ -int address_from_efi(size_t * address) +int address_from_efi(Log_t *logp, size_t * address) { FILE *efi_systab; - const char *filename; + const char *filename = NULL; char linebuf[64]; + const char *eptype; int ret; *address = 0; /* Prevent compiler warning */ @@ -65,9 +68,10 @@ int address_from_efi(size_t * address) char *addrp = strchr(linebuf, '='); *(addrp++) = '\0'; - if(strcmp(linebuf, "SMBIOS") == 0) { + if(strcmp(linebuf, "SMBIOS3") == 0 + || strcmp(linebuf, "SMBIOS") == 0) { *address = strtoul(addrp, NULL, 0); - printf("# SMBIOS entry point at 0x%08lx\n", (unsigned long)*address); + eptype = linebuf; ret = 0; break; } @@ -75,8 +79,13 @@ int address_from_efi(size_t * address) if(fclose(efi_systab) != 0) perror(filename); - if(ret == EFI_NO_SMBIOS) - fprintf(stderr, "%s: SMBIOS entry point missing\n", filename); + if(ret == EFI_NO_SMBIOS) { + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "%s: SMBIOS entry point missing", filename); + } + + if(ret == 0){ + log_append(logp, LOGFL_NODUPS, LOG_DEBUG, "%s: entry point at 0x%08llx", eptype, (unsigned long long)*address); + } return ret; } diff --git a/src/efi.h b/src/efi.h index 240fb01..dc03834 100644 --- a/src/efi.h +++ b/src/efi.h @@ -30,6 +30,6 @@ #define EFI_NOT_FOUND (-1) #define EFI_NO_SMBIOS (-2) -int address_from_efi(size_t * address); +int address_from_efi(Log_t *logp, size_t * address); #endif diff --git a/src/pymap.xml b/src/pymap.xml index a07512c..d021d00 100644 --- a/src/pymap.xml +++ b/src/pymap.xml @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -858,6 +887,7 @@ + diff --git a/src/setup-dbg.py b/src/setup-dbg.py index 9602abc..9bbeb21 100644 --- a/src/setup-dbg.py +++ b/src/setup-dbg.py @@ -42,6 +42,7 @@ # misc info dmidec_version = get_version() +macros = get_macros() # # Python setup @@ -66,6 +67,7 @@ "src/dmidecode.c", "src/dmixml.c", "src/dmierror.c", + "src/dmilog.c", "src/xmlpythonizer.c", "src/efi.c", "src/dmidump.c" @@ -73,8 +75,9 @@ include_dirs = incdir, library_dirs = libdir, libraries = libs, - undef_macros = [ "NDEBUG" ] + undef_macros = [ "NDEBUG" ], + define_macros = macros ) ], - py_modules = [ "dmidecode" ] + py_modules = [ "dmidecode-dbg" ] ) diff --git a/src/setup.py b/src/setup.py index d33db64..aecad71 100644 --- a/src/setup.py +++ b/src/setup.py @@ -42,6 +42,7 @@ # misc info dmidec_version = get_version() +macros = get_macros() # # Python setup @@ -66,6 +67,7 @@ "src/dmidecode.c", "src/dmixml.c", "src/dmierror.c", + "src/dmilog.c", "src/xmlpythonizer.c", "src/efi.c", "src/dmidump.c" @@ -73,7 +75,8 @@ include_dirs = incdir, library_dirs = libdir, libraries = libs, - undef_macros = [ "NDEBUG" ] + undef_macros = [ "NDEBUG" ], + define_macros = macros ) ], py_modules = [ "dmidecode" ] diff --git a/src/setup_common.py b/src/setup_common.py index fdf5c8c..aec1f9b 100644 --- a/src/setup_common.py +++ b/src/setup_common.py @@ -26,17 +26,19 @@ # are deemed to be part of the source code. # -import commands, sys +import subprocess, sys +if sys.version_info[0] < 3: + import commands as subprocess from os import path as os_path from distutils.sysconfig import get_python_lib # libxml2 - C flags def libxml2_include(incdir): - (res, libxml2_cflags) = commands.getstatusoutput("xml2-config --cflags") + (res, libxml2_cflags) = subprocess.getstatusoutput("xml2-config --cflags") if res != 0: - print "Could not build python-dmidecode." - print "Could not run xml2-config, is libxml2 installed?" - print "Also the development libraries?" + print("Could not build python-dmidecode.") + print("Could not run xml2-config, is libxml2 installed?") + print("Also the development libraries?") sys.exit(1) # Parse the xml2-config --cflags response @@ -52,11 +54,11 @@ def libxml2_lib(libdir, libs): if os_path.exists("/etc/debian_version"): #. XXX: Debian Workaround... libdir.append("/usr/lib/pymodules/python%d.%d"%sys.version_info[0:2]) - (res, libxml2_libs) = commands.getstatusoutput("xml2-config --libs") + (res, libxml2_libs) = subprocess.getstatusoutput("xml2-config --libs") if res != 0: - print "Could not build python-dmidecode." - print "Could not run xml2-config, is libxml2 installed?" - print "Also the development libraries?" + print("Could not build python-dmidecode.") + print("Could not run xml2-config, is libxml2 installed?") + print("Also the development libraries?") sys.exit(1) # Parse the xml2-config --libs response @@ -91,3 +93,11 @@ def get_version(): return version +def get_macros(): + "Sets macros which is relevant for all setup*.py files" + + macros = [] + if sys.byteorder == 'big': + macros.append(("ALIGNMENT_WORKAROUND", None)) + return macros + diff --git a/src/types.h b/src/types.h index 5f3dcd4..218f31a 100644 --- a/src/types.h +++ b/src/types.h @@ -57,7 +57,7 @@ typedef struct { } u64; #endif -#ifdef ALIGNMENT_WORKAROUND +#if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN) static inline u64 U64(u32 low, u32 high) { u64 self; @@ -69,20 +69,18 @@ static inline u64 U64(u32 low, u32 high) } #endif -#ifdef ALIGNMENT_WORKAROUND -# ifdef BIGENDIAN -# define WORD(x) (u16)((x)[1]+((x)[0]<<8)) -# define DWORD(x) (u32)((x)[3]+((x)[2]<<8)+((x)[1]<<16)+((x)[0]<<24)) -# define QWORD(x) (U64(DWORD(x+4), DWORD(x))) -# else /* BIGENDIAN */ -# define WORD(x) (u16)((x)[0]+((x)[1]<<8)) -# define DWORD(x) (u32)((x)[0]+((x)[1]<<8)+((x)[2]<<16)+((x)[3]<<24)) -# define QWORD(x) (U64(DWORD(x), DWORD(x+4))) -# endif /* BIGENDIAN */ -#else /* ALIGNMENT_WORKAROUND */ +/* + * Per SMBIOS v2.8.0 and later, all structures assume a little-endian + * ordering convention. + */ +#if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN) +#define WORD(x) (u16)((x)[0] + ((x)[1] << 8)) +#define DWORD(x) (u32)((x)[0] + ((x)[1] << 8) + ((x)[2] << 16) + ((x)[3] << 24)) +#define QWORD(x) (U64(DWORD(x), DWORD(x + 4))) +#else /* ALIGNMENT_WORKAROUND || BIGENDIAN */ #define WORD(x) (u16)(*(const u16 *)(x)) #define DWORD(x) (u32)(*(const u32 *)(x)) #define QWORD(x) (*(const u64 *)(x)) -#endif /* ALIGNMENT_WORKAROUND */ +#endif /* ALIGNMENT_WORKAROUND || BIGENDIAN */ #endif diff --git a/src/util.c b/src/util.c index 014b75d..7f61e55 100644 --- a/src/util.c +++ b/src/util.c @@ -44,12 +44,13 @@ #include #include #include +#include #include "types.h" #include "util.h" +#include "dmilog.h" -#ifndef USE_MMAP -static int myread(int fd, u8 * buf, size_t count, const char *prefix) +static int myread(Log_t *logp, int fd, u8 * buf, size_t count, const char *prefix) { ssize_t r = 1; size_t r2 = 0; @@ -68,13 +69,12 @@ static int myread(int fd, u8 * buf, size_t count, const char *prefix) if(r2 != count) { close(fd); - fprintf(stderr, "%s: Unexpected end of file\n", prefix); + log_append(logp, LOGFL_NORMAL, LOG_WARNING, "%s: Unexpected end of file", prefix); return -1; } return 0; } -#endif int checksum(const u8 * buf, size_t len) { @@ -86,30 +86,149 @@ int checksum(const u8 * buf, size_t len) return (sum == 0); } +/* + * Reads all of file from given offset, up to max_len bytes. + * A buffer of at most max_len bytes is allocated by this function, and + * needs to be freed by the caller. + * This provides a similar usage model to mem_chunk() + * + * Returns a pointer to the allocated buffer, or NULL on error, and + * sets max_len to the length actually read. + */ +void *read_file(Log_t *logp, off_t base, size_t *max_len, const char *filename) +{ + struct stat statbuf; + int fd; + u8 *p; + /* + * Don't print error message on missing file, as we will try to read + * files that may or may not be present. + */ + if ((fd = open(filename, O_RDONLY)) == -1) + { + if (errno != ENOENT) + perror(filename); + return NULL; + } + + /* + * Check file size, don't allocate more than can be read. + */ + if (fstat(fd, &statbuf) == 0) + { + if (base >= statbuf.st_size) + { + fprintf(stderr, "%s: Can't read data beyond EOF\n", + filename); + p = NULL; + goto out; + } + if (*max_len > (size_t)statbuf.st_size - base) + *max_len = statbuf.st_size - base; + } + + if ((p = malloc(*max_len)) == NULL) + { + perror("malloc"); + goto out; + } + + if (lseek(fd, base, SEEK_SET) == -1) + { + fprintf(stderr, "%s: ", filename); + perror("lseek"); + goto err_free; + } + if (myread(logp, fd, p, *max_len, filename) == 0) + goto out; + +err_free: + free(p); + p = NULL; + +out: + if (close(fd) == -1) + perror(filename); + + return p; +} + +/* Static global variables which should only + * be used by the sigill_handler() + */ +static int sigill_error = 0; +static Log_t *sigill_logobj = NULL; + +void sigill_handler(int ignore_this) { + sigill_error = 1; + if( sigill_logobj ) { + log_append(sigill_logobj, LOGFL_NODUPS, LOG_WARNING, + "SIGILL signal caught in mem_chunk()"); + } else { + fprintf(stderr, + "** WARNING ** SIGILL signal caught in mem_chunk()\n"); + } +} + +static void safe_memcpy(void *dest, const void *src, size_t n) +{ +#ifdef USE_SLOW_MEMCPY + size_t i; + + for (i = 0; i < n; i++) + *((u8 *)dest + i) = *((const u8 *)src + i); +#else + memcpy(dest, src, n); +#endif +} + /* * Copy a physical memory chunk into a memory buffer. * This function allocates memory. */ -void *mem_chunk(size_t base, size_t len, const char *devmem) +void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) { void *p; - int fd; + int fd = -1; #ifdef USE_MMAP - size_t mmoffset; + struct stat statbuf; + size_t mmoffset; void *mmp; #endif - - if((fd = open(devmem, O_RDONLY)) == -1) { - perror(devmem); - return NULL; + sigill_logobj = logp; + signal(SIGILL, sigill_handler); + if(sigill_error || (fd = open(devmem, O_RDONLY)) == -1) { + log_append(logp, LOGFL_NORMAL, LOG_WARNING, + "Failed to open memory buffer (%s): %s", + devmem, strerror(errno)); + p = NULL; + goto exit; } - if((p = malloc(len)) == NULL) { - perror("malloc"); - return NULL; + if(sigill_error || (p = malloc(len)) == NULL) { + log_append(logp, LOGFL_NORMAL, LOG_WARNING,"malloc: %s", strerror(errno)); + p = NULL; + goto exit; } #ifdef USE_MMAP + if (sigill_error || fstat(fd, &statbuf) == -1 ) + { + log_append(logp, LOGFL_NORMAL, LOG_WARNING,"fstat: %s", strerror(errno)); + goto err_free; + } + + /* + * mmap() will fail with SIGBUS if trying to map beyond the end of + * the file. + */ + if ((sigill_error || S_ISREG(statbuf.st_mode)) && (__off_t)(base + (off_t)len) > statbuf.st_size ) + { + log_append(logp, LOGFL_NORMAL, LOG_WARNING, + "mmap: Can't map beyond end of file %s: %s", + devmem, strerror(errno)); + goto err_free; + } #ifdef _SC_PAGESIZE mmoffset = base % sysconf(_SC_PAGESIZE); #else @@ -120,64 +239,102 @@ void *mem_chunk(size_t base, size_t len, const char *devmem) * but to workaround problems many people encountered when trying * to read from /dev/mem using regular read() calls. */ - mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset); - if(mmp == MAP_FAILED) { - fprintf(stderr, "%s: ", devmem); - perror("mmap"); - free(p); - return NULL; + mmp = mmap(NULL, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset); + if(sigill_error || (mmp == MAP_FAILED)) { + log_append(logp, LOGFL_NORMAL, LOG_WARNING, "%s (mmap): %s", devmem, strerror(errno)); + goto try_read; } - memcpy(p, (u8 *) mmp + mmoffset, len); + safe_memcpy(p, (u8 *) mmp + mmoffset, len); - if(munmap(mmp, mmoffset + len) == -1) { - fprintf(stderr, "%s: ", devmem); - perror("munmap"); - } -#else /* USE_MMAP */ - if(lseek(fd, base, SEEK_SET) == -1) { - fprintf(stderr, "%s: ", devmem); - perror("lseek"); + if (sigill_error) { + log_append(logp, LOGFL_NODUPS, LOG_WARNING, + "Failed to do memcpy() due to SIGILL signal"); free(p); - return NULL; + p = NULL; + goto exit; } - if(myread(fd, p, len, devmem) == -1) { + if(sigill_error || (munmap(mmp, mmoffset + len) == -1)) { + log_append(logp, LOGFL_NORMAL, LOG_WARNING, "%s (munmap): %s", devmem, strerror(errno)); free(p); - return NULL; + p = NULL; + goto exit; } + goto exit; + +try_read: #endif /* USE_MMAP */ + if (lseek(fd, base, SEEK_SET) == -1 ) + { + log_append(logp, LOGFL_NORMAL, LOG_WARNING, "%s (lseek): %s", devmem, strerror(errno)); + goto err_free; + } - if(close(fd) == -1) + if(sigill_error || (myread(logp, fd, p, len, devmem) == 0)) { + free(p); + p = NULL; + goto exit; + } + +err_free: + free(p); + p = NULL; + +exit: + if (fd >= 0) { + if(close(fd) == -1) perror(devmem); + } + signal(SIGILL, SIG_DFL); + sigill_logobj = NULL; return p; } +/* Returns end - start + 1, assuming start < end */ +u64 u64_range(u64 start, u64 end) +{ + u64 res; + + res.h = end.h - start.h; + res.l = end.l - start.l; + + if (end.l < start.l) + res.h--; + if (++res.l == 0) + res.h++; + + return res; +} + int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add) { FILE *f; - f = fopen(dumpfile, add ? "r+b" : "wb"); - if(!f) { + if (!f) + { fprintf(stderr, "%s: ", dumpfile); perror("fopen"); return -1; } - if(fseek(f, base, SEEK_SET) != 0) { + if (fseek(f, base, SEEK_SET) != 0) + { fprintf(stderr, "%s: ", dumpfile); perror("fseek"); goto err_close; } - if(fwrite(data, len, 1, f) != 1) { + if (fwrite(data, len, 1, f) != 1) + { fprintf(stderr, "%s: ", dumpfile); perror("fwrite"); goto err_close; } - if(fclose(f)) { + if (fclose(f)) + { fprintf(stderr, "%s: ", dumpfile); perror("fclose"); return -1; @@ -185,8 +342,7 @@ int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, return 0; - err_close: +err_close: fclose(f); return -1; } - diff --git a/src/util.h b/src/util.h index 3effd0c..3c803c0 100644 --- a/src/util.h +++ b/src/util.h @@ -22,9 +22,12 @@ #include #include "types.h" +#include "dmilog.h" #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) int checksum(const u8 * buf, size_t len); -void *mem_chunk(size_t base, size_t len, const char *devmem); +void *read_file( Log_t *logp, off_t base, size_t *len, const char *filename); +void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem); int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add); +u64 u64_range(u64 start, u64 end); diff --git a/src/version.h b/src/version.h index 70ea80d..68d060d 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define VERSION "3.10.6" +#define VERSION "3.12.3" diff --git a/src/xmlpythonizer.c b/src/xmlpythonizer.c index ba018eb..9dbf079 100644 --- a/src/xmlpythonizer.c +++ b/src/xmlpythonizer.c @@ -82,8 +82,10 @@ #include "util.h" #include "dmixml.h" #include "dmierror.h" +#include "dmilog.h" #include "xmlpythonizer.h" #include "version.h" +#include "compat.h" /** @@ -279,7 +281,7 @@ void ptzmap_Dump_func(const ptzMAP *ptr, int level) * @param const char* String value containing the key/value type * @return ptzTYPES The type value */ -inline ptzTYPES _convert_maptype(const char *str) { +inline ptzTYPES _convert_maptype(Log_t *logp, const char *str) { if( strcmp(str, "string") == 0 ) { return ptzSTR; } else if( strcmp(str, "constant") == 0 ) { @@ -303,7 +305,8 @@ inline ptzTYPES _convert_maptype(const char *str) { } else if( strcmp(str, "list:dict") == 0 ) { return ptzLIST_DICT; } else { - fprintf(stderr, "Unknown field type: %s - defaulting to 'constant'\n", str); + log_append(logp, LOGFL_NORMAL, LOG_WARNING, + "Unknown field type: %s - defaulting to 'constant'", str); return ptzCONST; } } @@ -315,7 +318,7 @@ inline ptzTYPES _convert_maptype(const char *str) { * @param xmlNode* Node of the starting point for the parsing * @return ptzMAP* The ptzMAP version of the XML definition */ -ptzMAP *_do_dmimap_parsing_typeid(xmlNode *node) { +ptzMAP *_do_dmimap_parsing_typeid(Log_t *logp, xmlNode *node) { ptzMAP *retmap = NULL; xmlNode *ptr_n = NULL, *map_n = NULL;; @@ -352,10 +355,10 @@ ptzMAP *_do_dmimap_parsing_typeid(xmlNode *node) { // Get the attributes defining key, keytype, value and valuetype key = dmixml_GetAttrValue(ptr_n, "key"); - type_key = _convert_maptype(dmixml_GetAttrValue(ptr_n, "keytype")); + type_key = _convert_maptype(logp, dmixml_GetAttrValue(ptr_n, "keytype")); value = dmixml_GetAttrValue(ptr_n, "value"); - type_value = _convert_maptype(dmixml_GetAttrValue(ptr_n, "valuetype")); + type_value = _convert_maptype(logp, dmixml_GetAttrValue(ptr_n, "valuetype")); rootpath = dmixml_GetAttrValue(ptr_n, "rootpath"); @@ -374,7 +377,7 @@ ptzMAP *_do_dmimap_parsing_typeid(xmlNode *node) { // Recursion retmap = ptzmap_Add(retmap, rootpath, type_key, key, type_value, (type_value == ptzLIST_DICT ? value : NULL), - _do_dmimap_parsing_typeid(ptr_n->children->next)); + _do_dmimap_parsing_typeid(logp, ptr_n->children->next)); } else { char *tmpstr = NULL; @@ -452,7 +455,7 @@ xmlNode *dmiMAP_GetRootElement(xmlDoc *mapdoc) { * @param const char* The typeid to parse to a ptzMAP * @return ptzMAP* The parsed result of the XML nodes */ -ptzMAP *_dmimap_parse_mapping_node_typeid(xmlNode *mapnode, const char *typeid) { +ptzMAP *_dmimap_parse_mapping_node_typeid(Log_t *logp, xmlNode *mapnode, const char *typeid) { xmlNode *node = NULL; assert( mapnode != NULL); @@ -461,12 +464,12 @@ ptzMAP *_dmimap_parse_mapping_node_typeid(xmlNode *mapnode, const char *typeid) node = dmixml_FindNodeByAttr_NoCase(mapnode, "TypeMap", "id", typeid); if( node == NULL ) { // No exception handling possible here, as we don't return PyObject - fprintf(stderr,"** WARNING: Could not find any XML->Python " - "mapping for type ID '%s'", typeid); + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "** WARNING: Could not find any XML->Python " + "mapping for type ID '%s'", typeid); return NULL; } // Create an internal map structure and return this structure - return _do_dmimap_parsing_typeid(node); + return _do_dmimap_parsing_typeid(logp, node); } @@ -477,7 +480,7 @@ ptzMAP *_dmimap_parse_mapping_node_typeid(xmlNode *mapnode, const char *typeid) * @param const char* The Type ID to create the map for * @return ptzMAP* The parsed XML containing as a ptzMAP */ -ptzMAP *dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, int typeid) { +ptzMAP *dmiMAP_ParseMappingXML_TypeID(Log_t *logp, xmlDoc *xmlmap, int typeid) { xmlNode *node = NULL; char typeid_s[16]; @@ -492,7 +495,7 @@ ptzMAP *dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, int typeid) { // Find the section node = dmixml_FindNode(node, "TypeMapping"); assert( node != NULL ); - return _dmimap_parse_mapping_node_typeid(node, typeid_s); + return _dmimap_parse_mapping_node_typeid(logp, node, typeid_s); } @@ -505,7 +508,7 @@ ptzMAP *dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, int typeid) { * @param xmlDoc* A pointer to the source map, used for further parsing of each type defined in the GroupMapping * @return ptzMAP* The resulting ptzMAP of the parsed xmlNode group mapping */ -ptzMAP *_do_dmimap_parsing_group(xmlNode *node, xmlDoc *xmlmap) { +ptzMAP *_do_dmimap_parsing_group(Log_t *logp, xmlNode *node, xmlDoc *xmlmap) { ptzMAP *retmap = NULL; xmlNode *ptr_n = NULL, *map_n = NULL, *typemap = NULL; char *type_id; @@ -548,7 +551,7 @@ ptzMAP *_do_dmimap_parsing_group(xmlNode *node, xmlDoc *xmlmap) { if( (type_id = dmixml_GetAttrValue(ptr_n, "id")) != NULL) { ptzMAP *map = NULL; - map = _dmimap_parse_mapping_node_typeid(typemap, type_id); + map = _dmimap_parse_mapping_node_typeid(logp, typemap, type_id); if( map ) { retmap = ptzmap_AppendMap(retmap, map); } @@ -566,13 +569,13 @@ ptzMAP *_do_dmimap_parsing_group(xmlNode *node, xmlDoc *xmlmap) { * @param const char* Defines which group mapping to parse to a ptzMAP * @return ptzMAP* The parsed XML mapping in a ptzMAP */ -ptzMAP *dmiMAP_ParseMappingXML_GroupName(xmlDoc *xmlmap, const char *mapname) { +ptzMAP *dmiMAP_ParseMappingXML_GroupName(Log_t *logp, xmlDoc *xmlmap, const char *mapname) { xmlNode *node = NULL; // Validate the XML mapping document and get the root element node = dmiMAP_GetRootElement(xmlmap); if( node == NULL ) { - PyReturnError(PyExc_RuntimeError, "No valid mapping XML recieved"); + PyReturnError(PyExc_RuntimeError, "No valid mapping XML received"); } // Find the section @@ -589,7 +592,7 @@ ptzMAP *dmiMAP_ParseMappingXML_GroupName(xmlDoc *xmlmap, const char *mapname) { } // Create an internal map structure and return this structure - return _do_dmimap_parsing_group(node, xmlmap); + return _do_dmimap_parsing_group(logp, node, xmlmap); } @@ -600,7 +603,7 @@ ptzMAP *dmiMAP_ParseMappingXML_GroupName(xmlDoc *xmlmap, const char *mapname) { * @param const char * String which contains the value to be converted to a Python value * @return PyObject * The converted value as a Python object */ -inline PyObject *StringToPyObj(ptzMAP *val_m, const char *instr) { +static inline PyObject *StringToPyObj(Log_t *logp, ptzMAP *val_m, const char *instr) { PyObject *value; const char *workstr = NULL; @@ -644,7 +647,7 @@ inline PyObject *StringToPyObj(ptzMAP *val_m, const char *instr) { switch( val_m->type_value ) { case ptzINT: case ptzLIST_INT: - value = PyInt_FromLong(atoi(workstr)); + value = PYNUMBER_FROMLONG(atoi(workstr)); break; case ptzFLOAT: @@ -659,11 +662,13 @@ inline PyObject *StringToPyObj(ptzMAP *val_m, const char *instr) { case ptzSTR: case ptzLIST_STR: - value = PyString_FromString(workstr); + value = PyBytes_FromString(workstr); break; default: - fprintf(stderr, "Invalid type '%i' for value '%s'\n", val_m->type_value, instr); + log_append(logp, LOGFL_NODUPS, LOG_WARNING, + "Invalid type '%i' for value '%s'", + val_m->type_value, instr); value = Py_None; } return value; @@ -706,7 +711,9 @@ xmlXPathObject *_get_xpath_values(xmlXPathContext *xpctx, const char *xpath) { * @returns char* Returns a pointer to the return buffer (parameter 1) if key value * is found, or NULL if not found */ -char *_get_key_value(char *key, size_t buflen, ptzMAP *map_p, xmlXPathContext *xpctx, int idx) { +char *_get_key_value(Log_t *logp, char *key, size_t buflen, + ptzMAP *map_p, xmlXPathContext *xpctx, int idx) +{ xmlXPathObject *xpobj = NULL; memset(key, 0, buflen); @@ -723,7 +730,7 @@ char *_get_key_value(char *key, size_t buflen, ptzMAP *map_p, xmlXPathContext *x if( xpobj == NULL ) { return NULL; } - if( dmixml_GetXPathContent(key, buflen, xpobj, idx) == NULL ) { + if( dmixml_GetXPathContent(logp, key, buflen, xpobj, idx) == NULL ) { xmlXPathFreeObject(xpobj); return NULL; } @@ -731,7 +738,7 @@ char *_get_key_value(char *key, size_t buflen, ptzMAP *map_p, xmlXPathContext *x break; default: - fprintf(stderr, "Unknown key type: %i\n", map_p->type_key); + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "Unknown key type: %i", map_p->type_key); return NULL; } // We consider to have a key, if the first byte is a readable @@ -765,7 +772,7 @@ char *_get_key_value(char *key, size_t buflen, ptzMAP *map_p, xmlXPathContext *x * @param ptzMAP* Pointer to the current mapping entry being parsed * @param xmlXPathObject* Pointer to XPath object containing the data value(s) for the dictionary */ -inline void _add_xpath_result(PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *map_p, xmlXPathObject *value) { +static inline void _add_xpath_result(Log_t *logp, PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *map_p, xmlXPathObject *value) { int i = 0; char *key = NULL; char *val = NULL; @@ -784,22 +791,22 @@ inline void _add_xpath_result(PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *m break; } if( value->nodesetval->nodeNr == 0 ) { - if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { + if( _get_key_value(logp, key, 256, map_p, xpctx, 0) != NULL ) { PyADD_DICT_VALUE(pydat, key, Py_None); } } else { for( i = 0; i < value->nodesetval->nodeNr; i++ ) { - if( _get_key_value(key, 256, map_p, xpctx, i) != NULL ) { - dmixml_GetXPathContent(val, 4097, value, i); - PyADD_DICT_VALUE(pydat, key, StringToPyObj(map_p, val)); + if( _get_key_value(logp, key, 256, map_p, xpctx, i) != NULL ) { + dmixml_GetXPathContent(logp, val, 4097, value, i); + PyADD_DICT_VALUE(pydat, key, StringToPyObj(logp, map_p, val)); } } } break; default: - if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { - dmixml_GetXPathContent(val, 4097, value, 0); - PyADD_DICT_VALUE(pydat, key, StringToPyObj(map_p, val)); + if( _get_key_value(logp, key, 256, map_p, xpctx, 0) != NULL ) { + dmixml_GetXPathContent(logp, val, 4097, value, 0); + PyADD_DICT_VALUE(pydat, key, StringToPyObj(logp, map_p, val)); } break; } @@ -819,7 +826,9 @@ inline void _add_xpath_result(PyObject *pydat, xmlXPathContext *xpctx, ptzMAP *m * @param int For debug purpose only, to keep track of which element being parsed * @return PyObject* Pointer to the input Python dictionary */ -PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int elmtid) { +PyObject *_deep_pythonize(Log_t *logp, PyObject *retdata, + ptzMAP *map_p, xmlNode *data_n, int elmtid) +{ char *key = NULL; xmlXPathContext *xpctx = NULL; xmlDoc *xpdoc = NULL; @@ -841,10 +850,13 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int // Extract value switch( map_p->type_value ) { case ptzCONST: - if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { - value = PyString_FromString(map_p->value); + if( _get_key_value(logp, key, 256, map_p, xpctx, 0) != NULL ) { + value = PyBytes_FromString(map_p->value); PyADD_DICT_VALUE(retdata, key, value); } else { + xmlXPathFreeContext(xpctx); + xmlFreeDoc(xpdoc); + free(key); PyReturnError(PyExc_ValueError, "Could not get key value: %s [%i] (Defining key: %s)", map_p->rootpath, elmtid, map_p->key); } @@ -856,7 +868,7 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int case ptzBOOL: xpo = _get_xpath_values(xpctx, map_p->value); if( xpo != NULL ) { - _add_xpath_result(retdata, xpctx, map_p, xpo); + _add_xpath_result(logp, retdata, xpctx, map_p, xpo); xmlXPathFreeObject(xpo); } break; @@ -867,7 +879,7 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int case ptzLIST_BOOL: xpo = _get_xpath_values(xpctx, map_p->value); if( xpo != NULL ) { - if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { + if( _get_key_value(logp, key, 256, map_p, xpctx, 0) != NULL ) { if( (xpo->nodesetval != NULL) && (xpo->nodesetval->nodeNr > 0) ) { value = PyList_New(0); @@ -883,7 +895,7 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { char *valstr = NULL; valstr = (char *) malloc(4098); - dmixml_GetXPathContent(valstr, 4097, xpo, i); + dmixml_GetXPathContent(logp, valstr, 4097, xpo, i); // If we have a fixed list and we have a index value for the list if( (map_p->fixed_list_size > 0) && (map_p->list_index != NULL) ) { @@ -893,12 +905,13 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int map_p->list_index); if( idx != NULL ) { PyList_SetItem(value, atoi(idx)-1, - StringToPyObj(map_p, valstr) + StringToPyObj(logp, + map_p, valstr) ); } } else { // No list index - append the value - PyList_Append(value, StringToPyObj(map_p, valstr)); + PyList_Append(value,StringToPyObj(logp,map_p,valstr)); } free(valstr); } @@ -908,6 +921,10 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int PyADD_DICT_VALUE(retdata, key, value); xmlXPathFreeObject(xpo); } else { + xmlXPathFreeObject(xpo); + xmlXPathFreeContext(xpctx); + xmlFreeDoc(xpdoc); + free(key); PyReturnError(PyExc_ValueError, "Could not get key value: " "%s [%i] (Defining key: %s)", map_p->rootpath, elmtid, map_p->key); @@ -920,13 +937,16 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int if( map_p->child == NULL ) { break; } - if( _get_key_value(key, 256, map_p, xpctx, 0) == NULL ) { + if( _get_key_value(logp, key, 256, map_p, xpctx, 0) == NULL ) { + xmlXPathFreeContext(xpctx); + xmlFreeDoc(xpdoc); + free(key); PyReturnError(PyExc_ValueError, "Could not get key value: %s [%i] (Defining key: %s)", map_p->rootpath, elmtid, map_p->key); } // Use recursion when procession child elements - value = pythonizeXMLnode(map_p->child, data_n); + value = pythonizeXMLnode(logp, map_p->child, data_n); PyADD_DICT_VALUE(retdata, key, (value != NULL ? value : Py_None)); break; @@ -934,7 +954,10 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int if( map_p->child == NULL ) { break; } - if( _get_key_value(key, 256, map_p, xpctx, 0) == NULL ) { + if( _get_key_value(logp, key, 256, map_p, xpctx, 0) == NULL ) { + xmlXPathFreeContext(xpctx); + xmlFreeDoc(xpdoc); + free(key); PyReturnError(PyExc_ValueError, "Could not get key value: %s [%i] (Defining key: %s)", map_p->rootpath, elmtid, map_p->key); @@ -946,6 +969,9 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int if( xpo != NULL ) { xmlXPathFreeObject(xpo); } + xmlXPathFreeContext(xpctx); + xmlFreeDoc(xpdoc); + free(key); PyReturnError(PyExc_ValueError, "Could not get key value: %s [%i] (Defining key: %s)", map_p->rootpath, elmtid, map_p->key); @@ -966,7 +992,7 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { PyObject *dataset = NULL; - dataset = pythonizeXMLnode(map_p->child, xpo->nodesetval->nodeTab[i]); + dataset = pythonizeXMLnode(logp, map_p->child, xpo->nodesetval->nodeTab[i]); if( dataset != NULL ) { // If we have a fixed list and we have a index value for the list if( (map_p->fixed_list_size > 0) && (map_p->list_index != NULL) ) { @@ -981,6 +1007,10 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int PyList_Append(value, dataset); } } else { + xmlXPathFreeObject(xpo); + xmlXPathFreeContext(xpctx); + xmlFreeDoc(xpdoc); + free(key); // If NULL, something is wrong - exception is already set. return NULL; } @@ -990,7 +1020,7 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int break; default: - fprintf(stderr, "Unknown value type: %i\n", map_p->type_value); + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "Unknown value type: %i", map_p->type_value); break; } @@ -1007,7 +1037,7 @@ PyObject *_deep_pythonize(PyObject *retdata, ptzMAP *map_p, xmlNode *data_n, int * @param ptzMAP* The map descriping the resulting Python dictionary * @param xmlNode* XML node pointer to the source data to be used for populating the Python dictionary */ -PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { +PyObject *pythonizeXMLnode(Log_t *logp, ptzMAP *in_map, xmlNode *data_n) { xmlXPathContext *xpctx = NULL; xmlDoc *xpdoc = NULL; PyObject *retdata = NULL; @@ -1037,6 +1067,8 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { xpctx = xmlXPathNewContext(xpdoc); if( xpctx == NULL ) { + xmlFreeDoc(xpdoc); + free(key); PyReturnError(PyExc_MemoryError, "Could not setup new XPath context"); } xpctx->node = data_n; @@ -1046,12 +1078,16 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { for( i = 0; i < xpo->nodesetval->nodeNr; i++ ) { xpctx->node = xpo->nodesetval->nodeTab[i]; - if( _get_key_value(key, 256, map_p, xpctx, 0) != NULL ) { - PyObject *res = _deep_pythonize(retdata, map_p, + if( _get_key_value(logp, key, 256, map_p, xpctx, 0) != NULL ) { + PyObject *res = _deep_pythonize(logp, retdata, map_p, xpo->nodesetval->nodeTab[i], i); if( res == NULL ) { // Exit if we get NULL - something is wrong //and exception is set + xmlXPathFreeObject(xpo); + xmlXPathFreeContext(xpctx); + xmlFreeDoc(xpdoc); + free(key); return NULL; } } @@ -1061,18 +1097,20 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { } #ifdef DEBUG else { - fprintf(stderr, "** pythonizeXMLnode :: Could not locate node for key value: " - "root path '%s', key '%s'\n", map_p->rootpath, map_p->key); + log_append(logp, LOGFL_NODUPS, LOG_WARNING, + "** pythonizeXMLnode :: Could not locate node for key value: " + "root path '%s', key '%s'", map_p->rootpath, map_p->key); } #endif if( xpo != NULL ) { xmlXPathFreeObject(xpo); xpo = NULL; } } else { - PyObject *res = _deep_pythonize(retdata, map_p, data_n, 0); + PyObject *res = _deep_pythonize(logp, retdata, map_p, data_n, 0); if( res == NULL ) { // Exit if we get NULL - something is wrong //and exception is set + free(key); return NULL; } } @@ -1088,12 +1126,12 @@ PyObject *pythonizeXMLnode(ptzMAP *in_map, xmlNode *data_n) { * @param ptzMAP* The map descriping the resulting Python dictionary * @param xmlDoc* XML document pointer to the source data to be used for populating the Python dictionary */ -PyObject *pythonizeXMLdoc(ptzMAP *map, xmlDoc *doc) +PyObject *pythonizeXMLdoc(Log_t *logp, ptzMAP *map, xmlDoc *doc) { xmlNode *node = NULL; node = xmlDocGetRootElement(doc); - return pythonizeXMLnode(map, node); + return pythonizeXMLnode(logp, map, node); } diff --git a/src/xmlpythonizer.h b/src/xmlpythonizer.h index df60140..e6c58bc 100644 --- a/src/xmlpythonizer.h +++ b/src/xmlpythonizer.h @@ -49,12 +49,12 @@ typedef struct ptzMAP_s { } ptzMAP; xmlNode *dmiMAP_GetRootElement(xmlDoc *mapdoc); -ptzMAP *dmiMAP_ParseMappingXML_TypeID(xmlDoc *xmlmap, int typeid); -ptzMAP *dmiMAP_ParseMappingXML_GroupName(xmlDoc *xmlmap, const char *mapname); +ptzMAP *dmiMAP_ParseMappingXML_TypeID(Log_t *logp, xmlDoc *xmlmap, int typeid); +ptzMAP *dmiMAP_ParseMappingXML_GroupName(Log_t *logp, xmlDoc *xmlmap, const char *mapname); #define ptzmap_Free(ptr) { ptzmap_Free_func(ptr); ptr = NULL; } void ptzmap_Free_func(ptzMAP *ptr); -PyObject *pythonizeXMLdoc(ptzMAP *map, xmlDoc *xmldoc); -PyObject *pythonizeXMLnode(ptzMAP *map, xmlNode *nodes); +PyObject *pythonizeXMLdoc(Log_t *logp, ptzMAP *map, xmlDoc *xmldoc); +PyObject *pythonizeXMLnode(Log_t *logp, ptzMAP *map, xmlNode *nodes); #endif // _XMLPYTHONIZER_H diff --git a/unit-tests/Makefile b/unit-tests/Makefile index 01706a3..0b8af8e 100644 --- a/unit-tests/Makefile +++ b/unit-tests/Makefile @@ -1,33 +1,7 @@ -## This one is important to get right ... -## We need to link in the libxml2mod.so file from here -PYLIBDIR := /usr/lib64/python2.5/site-packages -PYLIBDIR := /usr/lib/python-support/python-libxml2/python2.5 +PY_BIN := python3 -# Defaults, should be fine -CFLAGS=-I. $(shell xml2-config --cflags) -g -Wall $(shell python-config --cflags) - -LIBS=$(shell xml2-config --libs) -lxml2mod $(shell python-config --libs) -LIBDIR=-L $(PYLIBDIR) - -.SUFFIX=.c .o .so - -all : test - -demomodule.so : demo.o dmixml.o - @echo "Linking: $@" - @gcc -fPIC --shared -o $@ $^ $(LIBS) $(LIBDIR) - -.c.o : - @echo "Compiling $<" - @gcc -fPIC -c $< $(CFLAGS) - -#test : demomodule.so test : - @echo "==========================================" - @echo " Running proof-of-concept code" - @echo "==========================================" - @echo "" - @python unit + $(PY_BIN) unit -vv clean : rm -f *.{py[oc],o,so} *~ diff --git a/unit-tests/POCDemo.py b/unit-tests/POCDemo.py deleted file mode 100644 index 475a62b..0000000 --- a/unit-tests/POCDemo.py +++ /dev/null @@ -1,12 +0,0 @@ -import libxml2 -import demomodule # This is our core module - -class POCDemo: - """Demo of a wrapper class to return proper python libxml2 objects""" - - def GetXMLdoc(self): - return libxml2.xmlDoc( _obj = demomodule.dump_doc() ) - - def GetXMLnode(self): - return libxml2.xmlNode( _obj = demomodule.dump_node() ) - diff --git a/unit-tests/demo.c b/unit-tests/demo.c deleted file mode 100644 index 265f3cb..0000000 --- a/unit-tests/demo.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For the avoidance of doubt the "preferred form" of this code is one which - * is in an open unpatent encumbered format. Where cryptographic key signing - * forms part of the process of creating an executable the information - * including keys needed to generate an equivalently functional executable - * are deemed to be part of the source code. - */ - -#include "demo.h" - -xmlNode *gen_nodes(const char *entry ) { - xmlNode *c_xmlNode_root = NULL; - xmlNode *c_xmlNode_tag = NULL; - - // Prepare a root node - c_xmlNode_root = xmlNewNode(NULL, (xmlChar *) "dmixml_demo"); - assert( c_xmlNode_root != NULL ); - - dmixml_AddAttribute(c_xmlNode_root, "entrypoint", "%s", entry); - - // Populate XML - dmixml_AddTextChild(c_xmlNode_root, "Test", "Yes, just testing"); - - c_xmlNode_tag = dmixml_AddTextChild(c_xmlNode_root, "tag1", "Another test"); - dmixml_AddAttribute(c_xmlNode_tag, "TestTagID", "%i", 1); - - c_xmlNode_tag = c_xmlNode_root; - int i; - for(i = 0; i <= 3; ++i) { - c_xmlNode_tag = xmlNewChild(c_xmlNode_tag, NULL, (xmlChar *) "subtag", NULL); - dmixml_AddAttribute(c_xmlNode_tag, "SubLevel", "%i", i); - } - dmixml_AddTextContent(c_xmlNode_tag, "%s - Adding data to the tag at sublevel %i", "TEST", i-1); - - return c_xmlNode_root; -} - - - - -PyObject* demo_dump_doc() { - PyObject *py_xmlDoc = NULL; - xmlDoc *c_xmlDoc = NULL; - - // Create an XML document - c_xmlDoc = xmlNewDoc((xmlChar *) "1.0"); - assert( c_xmlDoc != NULL ); - - // Generate XML nodes and assign the root node to the document - xmlDocSetRootElement( c_xmlDoc, gen_nodes("demo_dump_doc") ); - - py_xmlDoc = libxml_xmlDocPtrWrap((xmlDocPtr) c_xmlDoc); - Py_INCREF(py_xmlDoc); - - return py_xmlDoc; -} - -PyObject* demo_dump_node() { - PyObject *py_xmlNode = NULL; - xmlNode *nodes = NULL; - - nodes = gen_nodes("demo_dump_node"); - py_xmlNode = libxml_xmlNodePtrWrap((xmlNodePtr) nodes); - Py_INCREF(py_xmlNode); - - return py_xmlNode; -} - - - -static PyMethodDef DemoMethods[] = { - { "dump_doc", demo_dump_doc, METH_NOARGS, (char *)"Return an XML document" }, - { "dump_node", demo_dump_node, METH_NOARGS, (char *)"Retuen an XML node" }, - { NULL, NULL, 0, NULL } -}; - -PyMODINIT_FUNC initdemomodule(void) { - PyObject *module = - Py_InitModule3((char *)"demomodule", DemoMethods, - "LibXML2 DMIDecode Proof-of-Concept Python Module"); - - PyObject *version = PyString_FromString("0.10"); - Py_INCREF(version); - PyModule_AddObject(module, "version", version); -} diff --git a/unit-tests/demo.h b/unit-tests/demo.h deleted file mode 100644 index 21a5468..0000000 --- a/unit-tests/demo.h +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include -#include - -#include -#include "libxml_wrap.h" - -#include "dmixml.h" - -extern PyObject* demo_dump(void); -PyMODINIT_FUNC initdemomodule(void); -PyObject* demo_dump_doc(void); -PyObject* demo_dump_node(void); diff --git a/unit-tests/dmixml.c b/unit-tests/dmixml.c deleted file mode 100644 index dbca0c3..0000000 --- a/unit-tests/dmixml.c +++ /dev/null @@ -1,248 +0,0 @@ -/* Simplified XML API for dmidecode - * - * Copyright 2009 David Sommerseth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For the avoidance of doubt the "preferred form" of this code is one which - * is in an open unpatent encumbered format. Where cryptographic key signing - * forms part of the process of creating an executable the information - * including keys needed to generate an equivalently functional executable - * are deemed to be part of the source code. - */ - -#include -#include -#include - -#include -#include -#include - -// Internal function for dmixml_* functions ... builds up a variable xmlChar* string -xmlChar *dmixml_buildstr(size_t len, const char *fmt, va_list ap) { - xmlChar *ret = NULL, *xmlfmt = NULL; - xmlChar *ptr = NULL; - - ret = (xmlChar *) malloc(len+2); - assert( ret != NULL ); - memset(ret, 0, len+2); - - xmlfmt = xmlCharStrdup(fmt); - assert( xmlfmt != NULL ); - - xmlStrVPrintf(ret, len, xmlfmt, ap); - free(xmlfmt); - - // Right trim the string - ptr = ret + xmlStrlen(ret)-1; - while( (ptr >= ret) && (*ptr == ' ') ) { - *ptr = 0; - ptr--; - } - return ret; -} - - -// Adds an XML property/attribute to the given XML node -// -// xmldata_n = ""; -// dmixml_AddAttribute(xmldata_n, "value", "1234"); -// gives: xmldata_n = "properties; aptr != NULL; aptr = aptr->next ) { - if( xmlStrcmp(aptr->name, key_s) == 0 ) { - free(key_s); key_s = NULL; - // FIXME: Should find better way how to return UTF-8 data - return (char *)(aptr->children != NULL ? aptr->children->content : NULL); - } - } - free(key_s); key_s = NULL; - return NULL; -} - -xmlNode *dmixml_FindNode(xmlNode *node, const char *key) { - xmlNode *ptr_n = NULL; - xmlChar *key_s = NULL; - - if( node->children == NULL ) { - return NULL; - } - - key_s = xmlCharStrdup(key); - assert( key_s != NULL ); - - for( ptr_n = node->children; ptr_n != NULL; ptr_n = ptr_n->next ) { - if( (ptr_n->type == XML_ELEMENT_NODE) - && (xmlStrcmp(ptr_n->name, key_s) == 0) ) { - free(key_s); key_s = NULL; - return ptr_n; - } - } - free(key_s); key_s = NULL; - return NULL; -} - -inline char *dmixml_GetContent(xmlNode *node) { - // FIXME: Should find better way how to return UTF-8 data - return (((node != NULL) && (node->children != NULL)) ? (char *) node->children->content : NULL); -} - -inline char *dmixml_GetNodeContent(xmlNode *node, const char *key) { - return dmixml_GetContent(dmixml_FindNode(node, key)); -} - -char *dmixml_GetXPathContent(char *buf, size_t buflen, xmlXPathObject *xpo, int idx) { - memset(buf, 0, buflen); - - if( xpo == NULL ) { - return NULL; - } - - switch( xpo->type ) { - case XPATH_STRING: - strncpy(buf, (char *)xpo->stringval, buflen-1); - break; - - case XPATH_NUMBER: - snprintf(buf, buflen-1, "%f", xpo->floatval); - break; - - case XPATH_NODESET: - if( (xpo->nodesetval != NULL) && (xpo->nodesetval->nodeNr >= (idx+1)) ) { - char *str = dmixml_GetContent(xpo->nodesetval->nodeTab[idx]); - if( str != NULL ) { - strncpy(buf, str, buflen-1); - } else { - memset(buf, 0, buflen); - } - } - break; - - default: - fprintf(stderr, "dmixml_GetXPathContent(...):: " - "Do not know how to handle XPath type %i\n", - xpo->type); - return NULL; - } - return buf; -} - diff --git a/unit-tests/dmixml.h b/unit-tests/dmixml.h deleted file mode 100644 index b1d86c6..0000000 --- a/unit-tests/dmixml.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Simplified XML API for dmidecode - * - * Copyright 2009 David Sommerseth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * For the avoidance of doubt the "preferred form" of this code is one which - * is in an open unpatent encumbered format. Where cryptographic key signing - * forms part of the process of creating an executable the information - * including keys needed to generate an equivalently functional executable - * are deemed to be part of the source code. - */ - -#ifndef _XMLHELPER_H -#define _XMLHELPER_H - -#include -#include -#include - -xmlAttr *dmixml_AddAttribute(xmlNode *node, const char *atrname, const char *fmt, ...); -xmlNode *dmixml_AddTextChild(xmlNode *node, const char *tagname, const char *fmt, ...); -xmlNode *dmixml_AddTextContent(xmlNode *node, const char *fmt, ...); - -char *dmixml_GetAttrValue(xmlNode *node, const char *key); -xmlNode *dmixml_FindNode(xmlNode *, const char *key); -inline char *dmixml_GetContent(xmlNode *node); -inline char *dmixml_GetNodeContent(xmlNode *node, const char *key); -char *dmixml_GetXPathContent(char *buf, size_t buflen, xmlXPathObject *xpo, int idx); - -#endif diff --git a/unit-tests/libxml_wrap.h b/unit-tests/libxml_wrap.h deleted file mode 100644 index eaa5e96..0000000 --- a/unit-tests/libxml_wrap.h +++ /dev/null @@ -1,249 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef LIBXML_SCHEMAS_ENABLED -#include -#include -#endif - -/** - * ATTRIBUTE_UNUSED: - * - * Macro used to signal to GCC unused function parameters - * Repeated here since the definition is not available when - * compiled outside the libxml2 build tree. - */ -#ifdef __GNUC__ -#ifdef ATTRIBUTE_UNUSED -#undef ATTRIBUTE_UNUSED -#endif -#ifndef ATTRIBUTE_UNUSED -#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -#endif /* ATTRIBUTE_UNUSED */ -#else -#define ATTRIBUTE_UNUSED -#endif - -#define PyxmlNode_Get(v) (((v) == Py_None) ? NULL : \ - (((PyxmlNode_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlNodePtr obj; -} PyxmlNode_Object; - -#define PyxmlXPathContext_Get(v) (((v) == Py_None) ? NULL : \ - (((PyxmlXPathContext_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlXPathContextPtr obj; -} PyxmlXPathContext_Object; - -#define PyxmlXPathParserContext_Get(v) (((v) == Py_None) ? NULL : \ - (((PyxmlXPathParserContext_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlXPathParserContextPtr obj; -} PyxmlXPathParserContext_Object; - -#define PyparserCtxt_Get(v) (((v) == Py_None) ? NULL : \ - (((PyparserCtxt_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlParserCtxtPtr obj; -} PyparserCtxt_Object; - -#define PyValidCtxt_Get(v) (((v) == Py_None) ? NULL : \ - (((PyValidCtxt_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlValidCtxtPtr obj; -} PyValidCtxt_Object; - -#define Pycatalog_Get(v) (((v) == Py_None) ? NULL : \ - (((Pycatalog_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlCatalogPtr obj; -} Pycatalog_Object; - -#ifdef LIBXML_REGEXP_ENABLED -#define PyxmlReg_Get(v) (((v) == Py_None) ? NULL : \ - (((PyxmlReg_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlRegexpPtr obj; -} PyxmlReg_Object; -#endif /* LIBXML_REGEXP_ENABLED */ - -#ifdef LIBXML_READER_ENABLED -#define PyxmlTextReader_Get(v) (((v) == Py_None) ? NULL : \ - (((PyxmlTextReader_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlTextReaderPtr obj; -} PyxmlTextReader_Object; - -#define PyxmlTextReaderLocator_Get(v) (((v) == Py_None) ? NULL : \ - (((PyxmlTextReaderLocator_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlTextReaderLocatorPtr obj; -} PyxmlTextReaderLocator_Object; -#endif - -#define PyURI_Get(v) (((v) == Py_None) ? NULL : \ - (((PyURI_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlErrorPtr obj; -} PyError_Object; - -#define PyError_Get(v) (((v) == Py_None) ? NULL : \ - (((PyError_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlOutputBufferPtr obj; -} PyoutputBuffer_Object; - -#define PyoutputBuffer_Get(v) (((v) == Py_None) ? NULL : \ - (((PyoutputBuffer_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlParserInputBufferPtr obj; -} PyinputBuffer_Object; - -#define PyinputBuffer_Get(v) (((v) == Py_None) ? NULL : \ - (((PyinputBuffer_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlURIPtr obj; -} PyURI_Object; - -/* FILE * have their own internal representation */ -#define PyFile_Get(v) (((v) == Py_None) ? NULL : \ - (PyFile_Check(v) ? (PyFile_AsFile(v)) : stdout)) - -#ifdef LIBXML_SCHEMAS_ENABLED -typedef struct { - PyObject_HEAD - xmlRelaxNGPtr obj; -} PyrelaxNgSchema_Object; - -#define PyrelaxNgSchema_Get(v) (((v) == Py_None) ? NULL : \ - (((PyrelaxNgSchema_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlRelaxNGParserCtxtPtr obj; -} PyrelaxNgParserCtxt_Object; - -#define PyrelaxNgParserCtxt_Get(v) (((v) == Py_None) ? NULL : \ - (((PyrelaxNgParserCtxt_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlRelaxNGValidCtxtPtr obj; -} PyrelaxNgValidCtxt_Object; - -#define PyrelaxNgValidCtxt_Get(v) (((v) == Py_None) ? NULL : \ - (((PyrelaxNgValidCtxt_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlSchemaPtr obj; -} PySchema_Object; - -#define PySchema_Get(v) (((v) == Py_None) ? NULL : \ - (((PySchema_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlSchemaParserCtxtPtr obj; -} PySchemaParserCtxt_Object; - -#define PySchemaParserCtxt_Get(v) (((v) == Py_None) ? NULL : \ - (((PySchemaParserCtxt_Object *)(v))->obj)) - -typedef struct { - PyObject_HEAD - xmlSchemaValidCtxtPtr obj; -} PySchemaValidCtxt_Object; - -#define PySchemaValidCtxt_Get(v) (((v) == Py_None) ? NULL : \ - (((PySchemaValidCtxt_Object *)(v))->obj)) - -#endif /* LIBXML_SCHEMAS_ENABLED */ - -PyObject * libxml_intWrap(int val); -PyObject * libxml_longWrap(long val); -PyObject * libxml_xmlCharPtrWrap(xmlChar *str); -PyObject * libxml_constxmlCharPtrWrap(const xmlChar *str); -PyObject * libxml_charPtrWrap(char *str); -PyObject * libxml_constcharPtrWrap(const char *str); -PyObject * libxml_charPtrConstWrap(const char *str); -PyObject * libxml_xmlCharPtrConstWrap(const xmlChar *str); -PyObject * libxml_xmlDocPtrWrap(xmlDocPtr doc); -PyObject * libxml_xmlNodePtrWrap(xmlNodePtr node); -PyObject * libxml_xmlAttrPtrWrap(xmlAttrPtr attr); -PyObject * libxml_xmlNsPtrWrap(xmlNsPtr ns); -PyObject * libxml_xmlAttributePtrWrap(xmlAttributePtr ns); -PyObject * libxml_xmlElementPtrWrap(xmlElementPtr ns); -PyObject * libxml_doubleWrap(double val); -PyObject * libxml_xmlXPathContextPtrWrap(xmlXPathContextPtr ctxt); -PyObject * libxml_xmlParserCtxtPtrWrap(xmlParserCtxtPtr ctxt); -PyObject * libxml_xmlXPathParserContextPtrWrap(xmlXPathParserContextPtr ctxt); -PyObject * libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj); -PyObject * libxml_xmlValidCtxtPtrWrap(xmlValidCtxtPtr valid); -PyObject * libxml_xmlCatalogPtrWrap(xmlCatalogPtr obj); -PyObject * libxml_xmlURIPtrWrap(xmlURIPtr uri); -PyObject * libxml_xmlOutputBufferPtrWrap(xmlOutputBufferPtr buffer); -PyObject * libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer); -#ifdef LIBXML_REGEXP_ENABLED -PyObject * libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp); -#endif /* LIBXML_REGEXP_ENABLED */ -#ifdef LIBXML_READER_ENABLED -PyObject * libxml_xmlTextReaderPtrWrap(xmlTextReaderPtr reader); -PyObject * libxml_xmlTextReaderLocatorPtrWrap(xmlTextReaderLocatorPtr locator); -#endif - -xmlXPathObjectPtr libxml_xmlXPathObjectPtrConvert(PyObject * obj); -#ifdef LIBXML_SCHEMAS_ENABLED -PyObject * libxml_xmlRelaxNGPtrWrap(xmlRelaxNGPtr ctxt); -PyObject * libxml_xmlRelaxNGParserCtxtPtrWrap(xmlRelaxNGParserCtxtPtr ctxt); -PyObject * libxml_xmlRelaxNGValidCtxtPtrWrap(xmlRelaxNGValidCtxtPtr valid); -PyObject * libxml_xmlSchemaPtrWrap(xmlSchemaPtr ctxt); -PyObject * libxml_xmlSchemaParserCtxtPtrWrap(xmlSchemaParserCtxtPtr ctxt); -PyObject * libxml_xmlSchemaValidCtxtPtrWrap(xmlSchemaValidCtxtPtr valid); -#endif /* LIBXML_SCHEMAS_ENABLED */ -PyObject * libxml_xmlErrorPtrWrap(xmlErrorPtr error); -PyObject * libxml_xmlSchemaSetValidErrors(PyObject * self, PyObject * args); diff --git a/unit-tests/private/DellPrecisionWorkStation-490.dmp b/unit-tests/private/DellPrecisionWorkStation-490.dmp new file mode 100644 index 0000000..17e0d6c Binary files /dev/null and b/unit-tests/private/DellPrecisionWorkStation-490.dmp differ diff --git a/unit-tests/private/IBM-x3950-M2.0.dmidump b/unit-tests/private/IBM-x3950-M2.0.dmidump new file mode 100644 index 0000000..5421caa Binary files /dev/null and b/unit-tests/private/IBM-x3950-M2.0.dmidump differ diff --git a/unit-tests/private/IBM-x3950-M2.1.dmidump b/unit-tests/private/IBM-x3950-M2.1.dmidump new file mode 100644 index 0000000..aec4766 Binary files /dev/null and b/unit-tests/private/IBM-x3950-M2.1.dmidump differ diff --git a/unit-tests/private/LenovoThinkPad-T61p.dmp b/unit-tests/private/LenovoThinkPad-T61p.dmp new file mode 100644 index 0000000..5815fc0 Binary files /dev/null and b/unit-tests/private/LenovoThinkPad-T61p.dmp differ diff --git a/unit-tests/private/Parallels-Virtual-Platform.0.dmidump b/unit-tests/private/Parallels-Virtual-Platform.0.dmidump new file mode 100644 index 0000000..0a845b4 Binary files /dev/null and b/unit-tests/private/Parallels-Virtual-Platform.0.dmidump differ diff --git a/unit-tests/private/PowerEdge-1800.0.dmidump b/unit-tests/private/PowerEdge-1800.0.dmidump new file mode 100644 index 0000000..c22a86e Binary files /dev/null and b/unit-tests/private/PowerEdge-1800.0.dmidump differ diff --git a/unit-tests/private/ProLiant-BL460c-G1.0.dmidump b/unit-tests/private/ProLiant-BL460c-G1.0.dmidump new file mode 100644 index 0000000..76e659d Binary files /dev/null and b/unit-tests/private/ProLiant-BL460c-G1.0.dmidump differ diff --git a/unit-tests/private/ProLiant-DL385-G1.0.dmidump b/unit-tests/private/ProLiant-DL385-G1.0.dmidump new file mode 100644 index 0000000..bdf2741 Binary files /dev/null and b/unit-tests/private/ProLiant-DL385-G1.0.dmidump differ diff --git a/unit-tests/private/ProLiant-DL385-G1.1.dmidump b/unit-tests/private/ProLiant-DL385-G1.1.dmidump new file mode 100644 index 0000000..9fd4395 Binary files /dev/null and b/unit-tests/private/ProLiant-DL385-G1.1.dmidump differ diff --git a/unit-tests/private/ProLiant-DL385-G1.2.dmidump b/unit-tests/private/ProLiant-DL385-G1.2.dmidump new file mode 100644 index 0000000..e8c22bf Binary files /dev/null and b/unit-tests/private/ProLiant-DL385-G1.2.dmidump differ diff --git a/unit-tests/private/ProLiant-DL385-G2.0.dmidump b/unit-tests/private/ProLiant-DL385-G2.0.dmidump new file mode 100644 index 0000000..9a4be19 Binary files /dev/null and b/unit-tests/private/ProLiant-DL385-G2.0.dmidump differ diff --git a/unit-tests/private/ProLiant-DL580-G5.0.dmidump b/unit-tests/private/ProLiant-DL580-G5.0.dmidump new file mode 100644 index 0000000..e177c09 Binary files /dev/null and b/unit-tests/private/ProLiant-DL580-G5.0.dmidump differ diff --git a/unit-tests/private/ProLiant-DL585-G1.0.dmidump b/unit-tests/private/ProLiant-DL585-G1.0.dmidump new file mode 100644 index 0000000..8c8d5ae Binary files /dev/null and b/unit-tests/private/ProLiant-DL585-G1.0.dmidump differ diff --git a/unit-tests/private/ProLiant-DL585-G1.1.dmidump b/unit-tests/private/ProLiant-DL585-G1.1.dmidump new file mode 100644 index 0000000..2a0c915 Binary files /dev/null and b/unit-tests/private/ProLiant-DL585-G1.1.dmidump differ diff --git a/unit-tests/private/ProLiant-DL585-G1.2.dmidump b/unit-tests/private/ProLiant-DL585-G1.2.dmidump new file mode 100644 index 0000000..ca5892c Binary files /dev/null and b/unit-tests/private/ProLiant-DL585-G1.2.dmidump differ diff --git a/unit-tests/private/ProLiant-DL585-G2.0.dmidump b/unit-tests/private/ProLiant-DL585-G2.0.dmidump new file mode 100644 index 0000000..757f0bb Binary files /dev/null and b/unit-tests/private/ProLiant-DL585-G2.0.dmidump differ diff --git a/unit-tests/private/ProLiant-DL585-G2.1.dmidump b/unit-tests/private/ProLiant-DL585-G2.1.dmidump new file mode 100644 index 0000000..8dee028 Binary files /dev/null and b/unit-tests/private/ProLiant-DL585-G2.1.dmidump differ diff --git a/unit-tests/private/VMware-Virtual-Platform.0.dmidump b/unit-tests/private/VMware-Virtual-Platform.0.dmidump new file mode 100644 index 0000000..0c3aa62 Binary files /dev/null and b/unit-tests/private/VMware-Virtual-Platform.0.dmidump differ diff --git a/unit-tests/private/kvm-QEMU.0.dmidump b/unit-tests/private/kvm-QEMU.0.dmidump new file mode 100644 index 0000000..244a3c5 Binary files /dev/null and b/unit-tests/private/kvm-QEMU.0.dmidump differ diff --git a/unit-tests/unit b/unit-tests/unit index ac3edab..3b06c04 100755 --- a/unit-tests/unit +++ b/unit-tests/unit @@ -2,267 +2,370 @@ #.awk '$0 ~ /case [0-9]+: .. 3/ { sys.stdout.write($2 }' src/dmidecode.c|tr ':\n' ', ' from pprint import pprint -import os, sys, random, tempfile, time -import commands - +import os, sys, subprocess, random, tempfile, time +if sys.version_info[0] < 3: + import commands as subprocess +from getopt import getopt + +# Setup temporary sys.path() with our build dir +(sysname, nodename, release, version, machine) = os.uname() +pyver = sys.version[:3] +sys.path.insert(0,'../build/lib.%s-%s-%s' % (sysname.lower(), machine, pyver)) + +root_user = (os.getuid() == 0 and True or False) + +ERROR = False +HELP = False +VERBOSITY = 0 +COLOR = False DUMPS_D = "private" -def ascii(s, i): return "\033[%d;1m%s\033[0m"%(30+i, str(s)) -def black(s): return "\033[30;1m%s\033[0m"%(str(s)) -def red(s): return "\033[31;1m%s\033[0m"%(str(s)) -def green(s): return "\033[32;1m%s\033[0m"%(str(s)) -def yellow(s): return "\033[33;1m%s\033[0m"%(str(s)) -def blue(s): return "\033[34;1m%s\033[0m"%(str(s)) -def magenta(s): return "\033[35;1m%s\033[0m"%(str(s)) -def cyan(s): return "\033[36;1m%s\033[0m"%(str(s)) -def white(s): return "\033[37;1m%s\033[0m"%(str(s)) +try: + opts, args = getopt( + sys.argv[1:], + "hcv", + ["help", "color", "verbose"] + ) + for o, a in opts: + if o in ("-v", "--verbose"): + VERBOSITY += 1 + elif o in ("-c", "--color"): + COLOR = True + elif o in ("-h", "--help"): + HELP = True +except getopt.GetoptError as err: + # print help information and exit: + HELP = True + ERROR = True + +if HELP: + sys.stdout.write(""" +Usage: %s [] + + OPTIONS + + [-h|--help] #. Take a wild guess. + [-c|--color] #. Add pretty ANSI colors. + [-v|--verbose] #. The more you add, the louder it gets. + + NOTES + + Due to developer laziness, a single verbosity flag does nothing, so if + you actually want to get some verbosity, add two verbosity flags (-vv) + +""" % os.path.basename(sys.argv[0])) + sys.exit(ERROR and 1 or 0) + +def ascii(s, i): + return (COLOR and "\033[%d;1m%s\033[0m" or "%d%s") % (30+i, str(s)) +def black(s): + return (COLOR and "\033[30;1m%s\033[0m" or "%s")%(str(s)) +def red(s): + return (COLOR and "\033[31;1m%s\033[0m" or "%s")%(str(s)) +def green(s): + return (COLOR and "\033[32;1m%s\033[0m" or "%s")%(str(s)) +def yellow(s): + return (COLOR and "\033[33;1m%s\033[0m" or "%s")%(str(s)) +def blue(s): + return (COLOR and "\033[34;1m%s\033[0m" or "%s")%(str(s)) +def magenta(s): + return (COLOR and "\033[35;1m%s\033[0m" or "%s")%(str(s)) +def cyan(s): + return (COLOR and "\033[36;1m%s\033[0m" or "%s")%(str(s)) +def white(s): + return (COLOR and "\033[37;1m%s\033[0m" or "%s")%(str(s)) DISPATCH = { - 1 : red, - 2 : green, - 3 : yellow, - 4 : blue, - 5 : magenta, - 6 : cyan, - 7 : white, + 1 : red, + 2 : green, + 3 : yellow, + 4 : blue, + 5 : magenta, + 6 : cyan, + 7 : white, } LINE = "%s\n"%(magenta("="*80)) score = { - "total" : 0, - "skipped" : 0, - "passed" : 0, - "failed" : 0, + "total" : 0, + "skipped" : 0, + "passed" : 0, + "warned" : 0, + "failed" : 0, } def passed(msg=None, indent=1): - global score - score["total"] += 1 - score["passed"] += 1 - sys.stdout.write("%s\n"%green("PASS")) - if msg: sys.stdout.write("%s %s %s\n"%(" "*indent, green("P"), msg)) + global score + score["total"] += 1 + score["passed"] += 1 + vwrite("%s\n"%green("PASS"), 1) + if msg: vwrite("%s %s %s\n"%(" "*indent, green("P"), msg), 1) + def skipped(msg=None, indent=1): - global score - score["total"] += 1 - score["skipped"] += 1 - sys.stdout.write("%s\n"%yellow("SKIP")) - if msg: sys.stdout.write("%s %s %s\n"%(" "*indent, yellow("S"), msg)) + global score + score["total"] += 1 + score["skipped"] += 1 + vwrite("%s\n"%yellow("SKIP"), 1) + if msg: vwrite("%s %s %s\n"%(" "*indent, yellow("S"), msg), 1) + +def warned(msg=None, indent=1): + global score + score["total"] += 1 + score["warned"] += 1 + vwrite("%s\n"%yellow("WARN"), 1) + if msg: vwrite("%s %s %s\n"%(" "*indent, yellow("S"), msg), 1) + def failed(msg=None, indent=1): - global score - score["total"] += 1 - score["failed"] += 1 - sys.stdout.write("%s\n"%red("FAIL")) - if msg: sys.stdout.write("%s %s %s\n"%(" "*indent, red("F"), msg)) -def test(r, msg=None, indent=1): - if r: - passed(msg, indent) - return True - else: - failed(msg, indent) - return False - -sys.stdout.write(LINE) -sys.stdout.write(" * Testing for dmidecode (upstream)...") -dmidecode_bin = True in [os.path.exists(os.path.join(_, "dmidecode")) for _ in os.getenv("PATH").split(':')] -test(dmidecode_bin) - -sys.stdout.write(" * Creation of temporary files...") + global score + score["total"] += 1 + score["failed"] += 1 + vwrite("%s\n"%red("FAIL"), 1) + if msg: vwrite("%s %s %s\n"%(" "*indent, red("F"), msg), 1) + +def test(r, msg=None, indent=1, bad=failed): + if r: + passed(msg, indent) + return True + else: + bad(msg, indent) + return False + +def vwrite(msg, vLevel=0): + if vLevel < VERBOSITY: + sys.stdout.write(msg) + sys.stdout.flush() + +################################################################################ + +#. Let's ignore warnings from the module for the test units... +err = open('/dev/null', 'a+', 1) +os.dup2(err.fileno(), sys.stderr.fileno()) + +vwrite(LINE, 1) +vwrite(" * Testing for command line version of dmidecode ...", 1) +dmidecode_bin = True in [ + os.path.exists( + os.path.join(_, "dmidecode") + ) for _ in os.getenv("PATH").split(':') +] +test(dmidecode_bin, bad=warned) +if root_user: + vwrite(" * Running test as root user, all tests will be executed\n", 1) +else: + vwrite(" * %s\n"%red("Running test as normal user, some tests will be skipped"), 1) + +vwrite(" * Creation of temporary files...", 1) try: - FH, DUMP = tempfile.mkstemp() - os.unlink(DUMP) - os.close(FH) - passed() + FH, DUMP = tempfile.mkstemp() + os.unlink(DUMP) + os.close(FH) + passed() except: - failed() + failed() -sys.stdout.write(LINE) +vwrite(LINE, 1) try: - sys.stdout.write(" * Importing module...") - import libxml2 -# from dmidecodemod import * - import dmidecode - passed() - - sys.stdout.write(" * Version: %s\n"%blue(dmidecode.version)) - sys.stdout.write(" * DMI Version String: %s\n"%blue(dmidecode.dmi)) - - sys.stdout.write(" * Testing that default device is /dev/mem...") - test(dmidecode.get_dev() == "/dev/mem") - - sys.stdout.write(" * Testing that write-lock will not break on dump()...") - test(not dmidecode.dump()) - - sys.stdout.write(" * Testing ability to change device to %s..."%DUMP) - test(dmidecode.set_dev(DUMP)) + vwrite(" * Importing module...", 1) + import libxml2 + import dmidecode + if not root_user: + vwrite("\n%s"%cyan("Not running as root, a warning above can be expected..."), 1) + passed() + + vwrite(" * Version: %s\n"%blue(dmidecode.version), 1) + vwrite(" * DMI Version String: %s\n"%blue(dmidecode.dmi), 1) + + vwrite(" * Testing that default device is /dev/mem...", 1) + test(dmidecode.get_dev() == "/dev/mem") + + if root_user: + vwrite(" * Testing that write-lock will not break on dump()...", 1) + test(not dmidecode.dump()) + + vwrite(" * Testing ability to change device to %s..."%DUMP, 1) + test(dmidecode.set_dev(DUMP)) + + vwrite(" * Testing that device has changed to %s..."%DUMP, 1) + test(dmidecode.get_dev() == DUMP) + + if root_user and dmidecode.dmi is not None: + vwrite(" * Testing that write on new file is ok...", 1) + test(dmidecode.dump()) + + vwrite(" * Testing that file was actually written...", 1) + time.sleep(0.1) + if test(os.path.exists(DUMP)): + os.unlink(DUMP) + else: + if dmidecode.dmi is None: + vwrite( + " * %s\n" % yellow( + "Skipped testing dump() function, dmidecode does not have access to DMI data" + ), 1) + else: + vwrite( + " * %s\n" % red( + "Skip testing API function, missing root privileges: dmidecode.dump()" + ), 1) + + types = list(range(0, 42))+list(range(126, 128)) + bad_types = [-1, -1000, 256] + sections = [ + "bios", + "system", + "baseboard", + "chassis", + "processor", + "memory", + "cache", + "connector", + "slot" + ] + devices = [] + if os.path.exists(DUMPS_D): + devices.extend([os.path.join(DUMPS_D, _) for _ in os.listdir(DUMPS_D)]) + else: + vwrite(" * If you have memory dumps to test, create a directory called `%s' and drop them in there.\n" % DUMPS_D, 1) + + if root_user and dmidecode.dmi is not None: + devices.append("/dev/mem") + else: + if dmidecode.dmi is not None: + vwrite(" * %s\n"%red("Running test as normal user, will not try to read /dev/mem"), 1) - sys.stdout.write(" * Testing that device has changed to %s..."%DUMP) - test(dmidecode.get_dev() == DUMP) - - sys.stdout.write(" * Testing that write on new file is ok...") - test(dmidecode.dump()) - - sys.stdout.write(" * Testing that file was actually written...") - time.sleep(0.1) - if test(os.path.exists(DUMP)): - os.unlink(DUMP) - - types = range(0, 42)+range(126, 128) - bad_types = [-1, -1000, 256] - sections = ["bios", "system", "baseboard", "chassis", "processor", "memory", "cache", "connector", "slot"] - devices = [] - if os.path.exists(DUMPS_D): - devices.extend([os.path.join(DUMPS_D, _) for _ in os.listdir(DUMPS_D)]) - else: - sys.stdout.write(" * If you have memory dumps to test, create a directory called `%s' and drop them in there.\n"%(DUMPS_D)) - devices.append("/dev/mem") - random.shuffle(types) - random.shuffle(devices) - random.shuffle(sections) - - for dev in devices: - sys.stdout.write(LINE) - sys.stdout.write(" * Testing %s..."%yellow(dev)); sys.stdout.flush() try: - fH = open(dev, 'r') - fH.close() - passed() - sys.stdout.write(" * Testing set_dev/get_dev on %s..."%(yellow(dev))); sys.stdout.flush() - if test(dmidecode.set_dev(dev) and dmidecode.get_dev() == dev): - i = 0 - for section in sections: - i += 1 - sys.stdout.write(" * Testing %s (%d/%d)..."%(cyan(section), i, len(sections))); sys.stdout.flush() - try: - output = getattr(dmidecode, section)() - test(output is not False) - if output: - sys.stdout.write(" * %s\n"%black(output.keys())) - except LookupError, e: - failed(e, 2) - - for i in bad_types: - sys.stdout.write(" * Testing bad type %s..."%red(i)); sys.stdout.flush() - try: - output = dmidecode.type(i) - test(output is False) - except SystemError: - failed() - - for i in types: - sys.stdout.write(" * Testing type %s..."%red(i)); sys.stdout.flush() - try: - output = dmidecode.type(i) - if dmidecode_bin: - _output = commands.getoutput("dmidecode -t %d"%i).strip().split('\n') - test(len(_output) == 1 and len(output) == 0 or True) - else: - test(output is not False) - if output: - sys.stdout.write(" * %s\n"%output.keys()) - except IOError, e: - failed(e, 2) - except LookupError, e: - failed(e, 2) - - dmixml = dmidecode.dmidecodeXML() + pymap = '../src/pymap.xml' + vwrite(" * Loading %s for XML->Python dictonary mapping..." % pymap, 1) + dmidecode.pythonmap(pymap) + passed() + except: + failed() + + random.shuffle(types) + random.shuffle(devices) + random.shuffle(sections) + + for dev in devices: + vwrite(LINE, 1) + vwrite(" * Testing %s..."%yellow(dev), 1) try: - sys.stdout.write(" * XML: Swapping result type dmidecodeXML::SetResultType('-')..."); - sys.stdout.flush() - test(not dmixml.SetResultType('-')) - except TypeError: - sys.stdout.write("Not working => ") - passed() - except: - sys.stdout.write("Accepted => ") - failed() - - try: - sys.stdout.write(" * XML: Swapping result type - dmidecodeXML::SetResultType(dmidecode.DMIXML_DOC)..."); - sys.stdout.flush() - test(dmixml.SetResultType(dmidecode.DMIXML_DOC)) - sys.stdout.write(" * XML: Swapping result type - dmidecodeXML::SetResultType(dmidecode.DMIXML_NODE)..."); - sys.stdout.flush() - test(dmixml.SetResultType(dmidecode.DMIXML_NODE)) - except: - failed() - - for i in bad_types: - sys.stdout.write(" * XML: Testing bad type - dmidecodeXML::QueryTypeId(%s)..." - % red(i)) - sys.stdout.flush() - try: - output_node = dmixml.QueryTypeId(i) - test(not isinstance(output_node, libxml2.xmlNode)) - except SystemError: - sys.stdout.write("Accepted => ") - failed() - except TypeError: - sys.stdout.write("Not working => ") + fH = open(dev, 'r') + fH.close() passed() - except ValueError: - sys.stdout.write("Not working => ") - passed() - - for i in types: - sys.stdout.write(" * XML: Testing dmidecodeXML::QueryTypeId(%s)..." - % red(i)) - sys.stdout.flush() - try: - output_node = dmixml.QueryTypeId(i) - test(isinstance(output_node, libxml2.xmlNode)) - except Exception, e: - failed(e, 2) - except: - failed() - - dmixml.SetResultType(dmidecode.DMIXML_DOC) - i = 0 - for section in sections: - i += 1 - sys.stdout.write(" * XML: Testing dmidecodeXML::QuerySection('%s') (%d/%d)..." - % (cyan(section), i, len(sections))) - sys.stdout.flush() - try: - output_doc = dmixml.QuerySection(section) - test(isinstance(output_doc, libxml2.xmlDoc)) - except Exception, e: - failed(e, 2) - except: - failed() - - except IOError: - skipped() - -except ImportError, err: - failed() - print err - - -""" -import libxml2 -from POCDemo import POCDemo - -test = POCDemo() -print "Please note the dmixml_demo/@entrypoint attribute in the root node" -print -print "-------- xmlDoc ---------------" -xmldoc = test.GetXMLdoc() -xmldoc.saveFormatFileEnc("-", "UTF-8", 1) - -print -print "-------- xmlNode ---------------" -xmldoc2 = libxml2.newDoc("1.0") -xmlnode = test.GetXMLnode() -xmldoc2.setRootElement(xmlnode) -xmldoc2.saveFormatFileEnc("-", "UTF-8", 1) -""" - - - -sys.stdout.write(LINE) -sys.stdout.write("Devices : %s\n"%cyan(len(devices))) -sys.stdout.write("Total : %s\n"%blue(score["total"])) -sys.stdout.write("Skipped : %s\n"%yellow(score["skipped"])) -sys.stdout.write("Passed : %s\n"%green(score["passed"])) -sys.stdout.write("Failed : %s\n"%red(score["failed"])) + vwrite(" * Testing set_dev/get_dev on %s..."%(yellow(dev)), 1) + if test(dmidecode.set_dev(dev) and dmidecode.get_dev() == dev): + i = 0 + for section in sections: + i += 1 + vwrite(" * Testing %s (%d/%d)..."%(cyan(section), i, len(sections)), 1) + try: + output = getattr(dmidecode, section)() + test(output is not False) + if output: + vwrite(" * %s\n"%black(output.keys()), 1) + except LookupError as e: + failed(e, 1) + + for i in bad_types: + vwrite(" * Testing bad type %s..."%red(i), 1) + try: + output = dmidecode.type(i) + test(output is False) + except SystemError: + failed() + + for i in types: + vwrite(" * Testing type %s..."%red(i), 1) + try: + output = dmidecode.type(i) + if dmidecode_bin: + _output = subprocess.getoutput("dmidecode -t %d"%i).strip().split('\n') + test(len(_output) == 1 and len(output) == 0 or True) + else: + test(output is not False) + if output: + vwrite(" * %s\n"%output.keys(), 1) + except IOError as e: + failed(e, 1) + except LookupError as e: + failed(e, 1) + + + dmixml = dmidecode.dmidecodeXML() + try: + vwrite(" * XML: Swapping result type dmidecodeXML::SetResultType('-') - invalid type... ", 1) + test(not dmixml.SetResultType('-')) + except TypeError: + vwrite("Not working => ", 1) + passed() + except: + vwrite("Accepted => ", 1) + failed() + + try: + vwrite(" * XML: Swapping result type - dmidecodeXML::SetResultType(dmidecode.DMIXML_DOC) - valid type...", 1) + test(dmixml.SetResultType(dmidecode.DMIXML_DOC)) + vwrite(" * XML: Swapping result type - dmidecodeXML::SetResultType(dmidecode.DMIXML_NODE) - valid type...", 1) + test(dmixml.SetResultType(dmidecode.DMIXML_NODE)) + except: + failed() + + for i in bad_types: + vwrite(" * XML: Testing bad type - dmidecodeXML::QueryTypeId(%s)..." % red(i), 1) + try: + output_node = dmixml.QueryTypeId(i) + test(not isinstance(output_node, libxml2.xmlNode)) + except SystemError: + vwrite("Accepted => ", 1) + failed() + except TypeError: + vwrite("Not working => ", 1) + passed() + except ValueError: + vwrite("Not working => ", 1) + passed() + + for i in types: + vwrite(" * XML: Testing dmidecodeXML::QueryTypeId(%s)..." % red(i), 1) + try: + output_node = dmixml.QueryTypeId(i) + test(isinstance(output_node, libxml2.xmlNode)) + except Exception as e: + failed(e, 1) + except: + failed() + + dmixml.SetResultType(dmidecode.DMIXML_DOC) + i = 0 + for section in sections: + i += 1 + vwrite(" * %s (%d/%d)..." % ( + "XML: Testing dmidecodeXML::QuerySection('%s')" % cyan( + section + ), i, len(sections) + ), 1) + try: + output_doc = dmixml.QuerySection(section) + test(isinstance(output_doc, libxml2.xmlDoc)) + except Exception as e: + failed(e, 1) + except: + failed() + + except IOError: + skipped() + +except ImportError as err: + failed() + print(err) + +vwrite(LINE, 1) +vwrite("Devices : %s\n"%cyan(len(devices)), 1) +vwrite("Total : %s\n"%blue(score["total"]), 1) +vwrite("Skipped : %s\n"%yellow(score["skipped"]), 1) +vwrite("Warned : %s\n"%yellow(score["warned"]), 1) +vwrite("Passed : %s\n"%green(score["passed"]), 1) +vwrite("Failed : %s\n"%red(score["failed"]), 1) + +sys.exit(score["failed"] != 0 and 1 or 0) diff --git a/utils/set_version b/utils/set_version index c42f6d6..bbca211 100755 --- a/utils/set_version +++ b/utils/set_version @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash if [ $# != 1 ]; then echo "Usage: $0 " @@ -13,7 +13,28 @@ fi NEW_VERSION=$1 OLD_VERSION=$(cd src;python -c "from setup_common import *; print get_version();") +rm -f src/setup_common.py[co] +# Prepare ChangeLog entry for the python-dmidecode.spec file +TSTAMP="$(date +%a\ %b\ %d\ %Y)" +FNAME="$(git config user.name)" +EMAIL="$(git config user.email)" +CHLOG="$TSTAMP $FNAME <$EMAIL> - ${NEW_VERSION}-1" + +# Prepare regexp script to modify python-dmidecode.spec +{ +cat < .chversion + +# Get confirmation of version change cat </dev/null - echo " ** Updating redhat.spec" - printf ",s/^Version: .*/Version: ${NEW_VERSION}/\nw\n" | ed contrib/python-dmidecode.spec 2>/dev/null - + echo " ** Updating contrib/python-dmidecode.spec" + cat .chversion | ed contrib/python-dmidecode.spec 2> /dev/null + if [ $? = 0 ]; then + rm -f .chversion + fi echo - echo " ** git add src/version.h redhat.spec" + echo " ** git add src/version.h contrib/python-dmidecode.spec" git add src/version.h contrib/python-dmidecode.spec + echo "-----------------------------------------------------------------------------------" git diff --cached + echo "-----------------------------------------------------------------------------------" echo - echo " REMEMBER to commit this change when you have validated the result" + echo " ** **" + echo " ** REMEMBER to COMMIT this change when you have validated the result **" + echo " ** **" echo ;; *)