From: Thomas Huth Date: Fri, 30 Aug 2024 13:38:23 +0000 (+0200) Subject: tests/functional: Convert the acpi-bits test into a standalone test X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=05caa0624256da44974cd68e8f55dbbde3dfede7;p=qemu.git tests/functional: Convert the acpi-bits test into a standalone test Mostly a straight-forward conversion. Looks like we can simply drop the avocado datadrainer stuff when not using the avocado framework anymore. Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-ID: <20240830133841.142644-30-thuth@redhat.com> Signed-off-by: Thomas Huth --- diff --git a/MAINTAINERS b/MAINTAINERS index 70dd2430db..f234464d11 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2074,8 +2074,8 @@ ACPI/AVOCADO/BIOSBITS M: Ani Sinha M: Michael S. Tsirkin S: Supported -F: tests/avocado/acpi-bits/* -F: tests/avocado/acpi-bits.py +F: tests/functional/acpi-bits/* +F: tests/functional/test_acpi_bits.py F: docs/devel/acpi-bits.rst ACPI/HEST/GHES diff --git a/docs/devel/acpi-bits.rst b/docs/devel/acpi-bits.rst index 1ec394f5fb..78aeb6aa3c 100644 --- a/docs/devel/acpi-bits.rst +++ b/docs/devel/acpi-bits.rst @@ -1,6 +1,6 @@ -============================================================================= -ACPI/SMBIOS avocado tests using biosbits -============================================================================= +================================== +ACPI/SMBIOS testing using biosbits +================================== ************ Introduction ************ @@ -35,7 +35,7 @@ for developing biosbits and its real life uses can be found in [#a]_ and [#b]_. For QEMU, we maintain a fork of bios bits in gitlab along with all the dependent submodules `here `__. This fork contains numerous fixes, a newer acpica and changes specific to -running this avocado QEMU tests using bits. The author of this document +running these functional QEMU tests using bits. The author of this document is the sole maintainer of the QEMU fork of bios bits repository. For more information, please see author's `FOSDEM talk on this bios-bits based test framework `__. @@ -44,12 +44,12 @@ framework diff --git a/tests/avocado/acpi-bits.py b/tests/avocado/acpi-bits.py deleted file mode 100644 index efe4f52ee0..0000000000 --- a/tests/avocado/acpi-bits.py +++ /dev/null @@ -1,409 +0,0 @@ -#!/usr/bin/env python3 -# group: rw quick -# Exercise QEMU generated ACPI/SMBIOS tables using biosbits, -# https://biosbits.org/ -# -# 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, see . -# -# -# Author: -# Ani Sinha - -# pylint: disable=invalid-name -# pylint: disable=consider-using-f-string - -""" -This is QEMU ACPI/SMBIOS avocado tests using biosbits. -Biosbits is available originally at https://biosbits.org/. -This test uses a fork of the upstream bits and has numerous fixes -including an upgraded acpica. The fork is located here: -https://gitlab.com/qemu-project/biosbits-bits . -""" - -import logging -import os -import platform -import re -import shutil -import subprocess -import tarfile -import tempfile -import time -import zipfile -from typing import ( - List, - Optional, - Sequence, -) -from qemu.machine import QEMUMachine -from avocado import skipIf -from avocado.utils import datadrainer as drainer -from avocado_qemu import QemuBaseTest - -deps = ["xorriso", "mformat"] # dependent tools needed in the test setup/box. -supported_platforms = ['x86_64'] # supported test platforms. - -# default timeout of 120 secs is sometimes not enough for bits test. -BITS_TIMEOUT = 200 - -def which(tool): - """ looks up the full path for @tool, returns None if not found - or if @tool does not have executable permissions. - """ - paths=os.getenv('PATH') - for p in paths.split(os.path.pathsep): - p = os.path.join(p, tool) - if os.path.exists(p) and os.access(p, os.X_OK): - return p - return None - -def missing_deps(): - """ returns True if any of the test dependent tools are absent. - """ - for dep in deps: - if which(dep) is None: - return True - return False - -def supported_platform(): - """ checks if the test is running on a supported platform. - """ - return platform.machine() in supported_platforms - -class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods - """ - A QEMU VM, with isa-debugcon enabled and bits iso passed - using -cdrom to QEMU commandline. - - """ - def __init__(self, - binary: str, - args: Sequence[str] = (), - wrapper: Sequence[str] = (), - name: Optional[str] = None, - base_temp_dir: str = "/var/tmp", - debugcon_log: str = "debugcon-log.txt", - debugcon_addr: str = "0x403", - qmp_timer: Optional[float] = None): - # pylint: disable=too-many-arguments - - if name is None: - name = "qemu-bits-%d" % os.getpid() - super().__init__(binary, args, wrapper=wrapper, name=name, - base_temp_dir=base_temp_dir, - qmp_timer=qmp_timer) - self.debugcon_log = debugcon_log - self.debugcon_addr = debugcon_addr - self.base_temp_dir = base_temp_dir - - @property - def _base_args(self) -> List[str]: - args = super()._base_args - args.extend([ - '-chardev', - 'file,path=%s,id=debugcon' %os.path.join(self.base_temp_dir, - self.debugcon_log), - '-device', - 'isa-debugcon,iobase=%s,chardev=debugcon' %self.debugcon_addr, - ]) - return args - - def base_args(self): - """return the base argument to QEMU binary""" - return self._base_args - -@skipIf(not supported_platform() or missing_deps(), - 'unsupported platform or dependencies (%s) not installed' \ - % ','.join(deps)) -class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes - """ - ACPI and SMBIOS tests using biosbits. - - :avocado: tags=arch:x86_64 - :avocado: tags=acpi - - """ - # in slower systems the test can take as long as 3 minutes to complete. - timeout = BITS_TIMEOUT - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._vm = None - self._workDir = None - self._baseDir = None - - # following are some standard configuration constants - self._bitsInternalVer = 2020 # gitlab CI does shallow clones of depth 20 - self._bitsCommitHash = 'c7920d2b' # commit hash must match - # the artifact tag below - self._bitsTag = "qemu-bits-10262023" # this is the latest bits - # release as of today. - self._bitsArtSHA1Hash = 'b22cdfcfc7453875297d06d626f5474ee36a343f' - self._bitsArtURL = ("https://gitlab.com/qemu-project/" - "biosbits-bits/-/jobs/artifacts/%s/" - "download?job=qemu-bits-build" %self._bitsTag) - self._debugcon_addr = '0x403' - self._debugcon_log = 'debugcon-log.txt' - logging.basicConfig(level=logging.INFO) - self.logger = logging.getLogger('acpi-bits') - - def _print_log(self, log): - self.logger.info('\nlogs from biosbits follows:') - self.logger.info('==========================================\n') - self.logger.info(log) - self.logger.info('==========================================\n') - - def copy_bits_config(self): - """ copies the bios bits config file into bits. - """ - config_file = 'bits-cfg.txt' - bits_config_dir = os.path.join(self._baseDir, 'acpi-bits', - 'bits-config') - target_config_dir = os.path.join(self._workDir, - 'bits-%d' %self._bitsInternalVer, - 'boot') - self.assertTrue(os.path.exists(bits_config_dir)) - self.assertTrue(os.path.exists(target_config_dir)) - self.assertTrue(os.access(os.path.join(bits_config_dir, - config_file), os.R_OK)) - shutil.copy2(os.path.join(bits_config_dir, config_file), - target_config_dir) - self.logger.info('copied config file %s to %s', - config_file, target_config_dir) - - def copy_test_scripts(self): - """copies the python test scripts into bits. """ - - bits_test_dir = os.path.join(self._baseDir, 'acpi-bits', - 'bits-tests') - target_test_dir = os.path.join(self._workDir, - 'bits-%d' %self._bitsInternalVer, - 'boot', 'python') - - self.assertTrue(os.path.exists(bits_test_dir)) - self.assertTrue(os.path.exists(target_test_dir)) - - for filename in os.listdir(bits_test_dir): - if os.path.isfile(os.path.join(bits_test_dir, filename)) and \ - filename.endswith('.py2'): - # all test scripts are named with extension .py2 so that - # avocado does not try to load them. These scripts are - # written for python 2.7 not python 3 and hence if avocado - # loaded them, it would complain about python 3 specific - # syntaxes. - newfilename = os.path.splitext(filename)[0] + '.py' - shutil.copy2(os.path.join(bits_test_dir, filename), - os.path.join(target_test_dir, newfilename)) - self.logger.info('copied test file %s to %s', - filename, target_test_dir) - - # now remove the pyc test file if it exists, otherwise the - # changes in the python test script won't be executed. - testfile_pyc = os.path.splitext(filename)[0] + '.pyc' - if os.access(os.path.join(target_test_dir, testfile_pyc), - os.F_OK): - os.remove(os.path.join(target_test_dir, testfile_pyc)) - self.logger.info('removed compiled file %s', - os.path.join(target_test_dir, - testfile_pyc)) - - def fix_mkrescue(self, mkrescue): - """ grub-mkrescue is a bash script with two variables, 'prefix' and - 'libdir'. They must be pointed to the right location so that the - iso can be generated appropriately. We point the two variables to - the directory where we have extracted our pre-built bits grub - tarball. - """ - grub_x86_64_mods = os.path.join(self._workDir, 'grub-inst-x86_64-efi') - grub_i386_mods = os.path.join(self._workDir, 'grub-inst') - - self.assertTrue(os.path.exists(grub_x86_64_mods)) - self.assertTrue(os.path.exists(grub_i386_mods)) - - new_script = "" - with open(mkrescue, 'r', encoding='utf-8') as filehandle: - orig_script = filehandle.read() - new_script = re.sub('(^prefix=)(.*)', - r'\1"%s"' %grub_x86_64_mods, - orig_script, flags=re.M) - new_script = re.sub('(^libdir=)(.*)', r'\1"%s/lib"' %grub_i386_mods, - new_script, flags=re.M) - - with open(mkrescue, 'w', encoding='utf-8') as filehandle: - filehandle.write(new_script) - - def generate_bits_iso(self): - """ Uses grub-mkrescue to generate a fresh bits iso with the python - test scripts - """ - bits_dir = os.path.join(self._workDir, - 'bits-%d' %self._bitsInternalVer) - iso_file = os.path.join(self._workDir, - 'bits-%d.iso' %self._bitsInternalVer) - mkrescue_script = os.path.join(self._workDir, - 'grub-inst-x86_64-efi', 'bin', - 'grub-mkrescue') - - self.assertTrue(os.access(mkrescue_script, - os.R_OK | os.W_OK | os.X_OK)) - - self.fix_mkrescue(mkrescue_script) - - self.logger.info('using grub-mkrescue for generating biosbits iso ...') - - try: - if os.getenv('V') or os.getenv('BITS_DEBUG'): - subprocess.check_call([mkrescue_script, '-o', iso_file, - bits_dir], stderr=subprocess.STDOUT) - else: - subprocess.check_call([mkrescue_script, '-o', - iso_file, bits_dir], - stderr=subprocess.DEVNULL, - stdout=subprocess.DEVNULL) - except Exception as e: # pylint: disable=broad-except - self.skipTest("Error while generating the bits iso. " - "Pass V=1 in the environment to get more details. " - + str(e)) - - self.assertTrue(os.access(iso_file, os.R_OK)) - - self.logger.info('iso file %s successfully generated.', iso_file) - - def setUp(self): # pylint: disable=arguments-differ - super().setUp('qemu-system-') - - self._baseDir = os.getenv('AVOCADO_TEST_BASEDIR') - - # workdir could also be avocado's own workdir in self.workdir. - # At present, I prefer to maintain my own temporary working - # directory. It gives us more control over the generated bits - # log files and also for debugging, we may chose not to remove - # this working directory so that the logs and iso can be - # inspected manually and archived if needed. - self._workDir = tempfile.mkdtemp(prefix='acpi-bits-', - suffix='.tmp') - self.logger.info('working dir: %s', self._workDir) - - prebuiltDir = os.path.join(self._workDir, 'prebuilt') - if not os.path.isdir(prebuiltDir): - os.mkdir(prebuiltDir, mode=0o775) - - bits_zip_file = os.path.join(prebuiltDir, 'bits-%d-%s.zip' - %(self._bitsInternalVer, - self._bitsCommitHash)) - grub_tar_file = os.path.join(prebuiltDir, - 'bits-%d-%s-grub.tar.gz' - %(self._bitsInternalVer, - self._bitsCommitHash)) - - bitsLocalArtLoc = self.fetch_asset(self._bitsArtURL, - asset_hash=self._bitsArtSHA1Hash) - self.logger.info("downloaded bits artifacts to %s", bitsLocalArtLoc) - - # extract the bits artifact in the temp working directory - with zipfile.ZipFile(bitsLocalArtLoc, 'r') as zref: - zref.extractall(prebuiltDir) - - # extract the bits software in the temp working directory - with zipfile.ZipFile(bits_zip_file, 'r') as zref: - zref.extractall(self._workDir) - - with tarfile.open(grub_tar_file, 'r', encoding='utf-8') as tarball: - tarball.extractall(self._workDir) - - self.copy_test_scripts() - self.copy_bits_config() - self.generate_bits_iso() - - def parse_log(self): - """parse the log generated by running bits tests and - check for failures. - """ - debugconf = os.path.join(self._workDir, self._debugcon_log) - log = "" - with open(debugconf, 'r', encoding='utf-8') as filehandle: - log = filehandle.read() - - matchiter = re.finditer(r'(.*Summary: )(\d+ passed), (\d+ failed).*', - log) - for match in matchiter: - # verify that no test cases failed. - try: - self.assertEqual(match.group(3).split()[0], '0', - 'Some bits tests seems to have failed. ' \ - 'Please check the test logs for more info.') - except AssertionError as e: - self._print_log(log) - raise e - else: - if os.getenv('V') or os.getenv('BITS_DEBUG'): - self._print_log(log) - - def tearDown(self): - """ - Lets do some cleanups. - """ - if self._vm: - self.assertFalse(not self._vm.is_running) - if not os.getenv('BITS_DEBUG') and self._workDir: - self.logger.info('removing the work directory %s', self._workDir) - shutil.rmtree(self._workDir) - else: - self.logger.info('not removing the work directory %s ' \ - 'as BITS_DEBUG is ' \ - 'passed in the environment', self._workDir) - super().tearDown() - - def test_acpi_smbios_bits(self): - """The main test case implementation.""" - - iso_file = os.path.join(self._workDir, - 'bits-%d.iso' %self._bitsInternalVer) - - self.assertTrue(os.access(iso_file, os.R_OK)) - - self._vm = QEMUBitsMachine(binary=self.qemu_bin, - base_temp_dir=self._workDir, - debugcon_log=self._debugcon_log, - debugcon_addr=self._debugcon_addr) - - self._vm.add_args('-cdrom', '%s' %iso_file) - # the vm needs to be run under icount so that TCG emulation is - # consistent in terms of timing. smilatency tests have consistent - # timing requirements. - self._vm.add_args('-icount', 'auto') - # currently there is no support in bits for recognizing 64-bit SMBIOS - # entry points. QEMU defaults to 64-bit entry points since the - # upstream commit bf376f3020 ("hw/i386/pc: Default to use SMBIOS 3.0 - # for newer machine models"). Therefore, enforce 32-bit entry point. - self._vm.add_args('-machine', 'smbios-entry-point-type=32') - - # enable console logging - self._vm.set_console() - self._vm.launch() - - self.logger.debug("Console output from bits VM follows ...") - c_drainer = drainer.LineLogger(self._vm.console_socket.fileno(), - logger=self.logger.getChild("console"), - stop_check=(lambda : - not self._vm.is_running())) - c_drainer.start() - - # biosbits has been configured to run all the specified test suites - # in batch mode and then automatically initiate a vm shutdown. - # Set timeout to BITS_TIMEOUT for SHUTDOWN event from bits VM at par - # with the avocado test timeout. - self._vm.event_wait('SHUTDOWN', timeout=BITS_TIMEOUT) - self._vm.wait(timeout=None) - self.parse_log() diff --git a/tests/avocado/acpi-bits/bits-config/bits-cfg.txt b/tests/avocado/acpi-bits/bits-config/bits-cfg.txt deleted file mode 100644 index 8010804453..0000000000 --- a/tests/avocado/acpi-bits/bits-config/bits-cfg.txt +++ /dev/null @@ -1,18 +0,0 @@ -# BITS configuration file -[bits] - -# To run BITS in batch mode, set batch to a list of one or more of the -# following keywords; BITS will then run all of the requested operations, then -# save the log file to disk. -# -# test: Run the full BITS testsuite. -# acpi: Dump all ACPI structures. -# smbios: Dump all SMBIOS structures. -# -# Leave batch set to an empty string to disable batch mode. -# batch = - -# Uncomment the following to run all available batch operations -# please take a look at boot/python/init.py in bits zip file -# to see how these options are parsed and used. -batch = test acpi smbios diff --git a/tests/avocado/acpi-bits/bits-tests/smbios.py2 b/tests/avocado/acpi-bits/bits-tests/smbios.py2 deleted file mode 100644 index 5868a7137a..0000000000 --- a/tests/avocado/acpi-bits/bits-tests/smbios.py2 +++ /dev/null @@ -1,2434 +0,0 @@ -# Copyright (c) 2015, Intel Corporation -# All rights reserved. -# -# SPDX-License-Identifier: BSD-3-Clause -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# * Neither the name of Intel Corporation nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. - -# This script runs only from the biosbits VM. - -"""SMBIOS/DMI module.""" - -import bits -import bitfields -import ctypes -import redirect -import struct -import uuid -import unpack -import ttypager -import sys - -class SMBIOS(unpack.Struct): - def __new__(cls): - if sys.platform == "BITS-EFI": - import efi - sm_ptr = efi.system_table.ConfigurationTableDict.get(efi.SMBIOS_TABLE_GUID) - else: - address = 0xF0000 - mem = bits.memory(0xF0000, 0x10000) - for offset in range(0, len(mem), 16): - signature = (ctypes.c_char * 4).from_address(address + offset).value - if signature == "_SM_": - entry_point_length = ctypes.c_ubyte.from_address(address + offset + 5).value - csum = sum(map(ord, mem[offset:offset + entry_point_length])) & 0xff - if csum == 0: - sm_ptr = address + offset - break - else: - return None - - if not sm_ptr: - return None - - sm = super(SMBIOS, cls).__new__(cls) - sm._header_memory = bits.memory(sm_ptr, 0x1f) - return sm - - def __init__(self): - super(SMBIOS, self).__init__() - u = unpack.Unpackable(self._header_memory) - self.add_field('header', Header(u)) - self._structure_memory = bits.memory(self.header.structure_table_address, self.header.structure_table_length) - u = unpack.Unpackable(self._structure_memory) - self.add_field('structures', unpack.unpack_all(u, _smbios_structures, self), unpack.format_each("\n\n{!r}")) - - def structure_type(self, num): - '''Dumps structure of given Type if present''' - try: - types_present = [self.structures[x].smbios_structure_type for x in range(len(self.structures))] - matrix = dict() - for index in range(len(types_present)): - if types_present.count(types_present[index]) == 1: - matrix[types_present[index]] = self.structures[index] - else: # if multiple structures of the same type, return a list of structures for the type number - if matrix.has_key(types_present[index]): - matrix[types_present[index]].append(self.structures[index]) - else: - matrix[types_present[index]] = [self.structures[index]] - return matrix[num] - except: - print "Failure: Type {} - not found".format(num) - -class Header(unpack.Struct): - def __new__(cls, u): - return super(Header, cls).__new__(cls) - - def __init__(self, u): - super(Header, self).__init__() - self.raw_data = u.unpack_rest() - u = unpack.Unpackable(self.raw_data) - self.add_field('anchor_string', u.unpack_one("4s")) - self.add_field('checksum', u.unpack_one("B")) - self.add_field('length', u.unpack_one("B")) - self.add_field('major_version', u.unpack_one("B")) - self.add_field('minor_version', u.unpack_one("B")) - self.add_field('max_structure_size', u.unpack_one(" len(self.strings): - return "(error: string index out of range)" - return self.strings[i - 1] - -class BIOSInformation(SmbiosBaseStructure): - smbios_structure_type = 0 - - def __init__(self, u, sm): - super(BIOSInformation, self).__init__(u, sm) - u = self.u - try: - self.add_field('vendor', u.unpack_one("B"), self.fmtstr) - self.add_field('version', u.unpack_one("B"), self.fmtstr) - self.add_field('starting_address_segment', u.unpack_one("= (2,"4"): - characteristic_bytes = 2 - else: - characteristic_bytes = self.length - 0x12 - self.add_field('characteristics_extensions', [u.unpack_one("B") for b in range(characteristic_bytes)]) - if (sm.header.major_version, minor_version_str) >= (2,"4"): - self.add_field('major_release', u.unpack_one("B")) - self.add_field('minor_release', u.unpack_one("B")) - self.add_field('ec_major_release', u.unpack_one("B")) - self.add_field('ec_minor_release', u.unpack_one("B")) - except: - self.decode_failure = True - print "Error parsing BIOSInformation" - import traceback - traceback.print_exc() - self.fini() - -class SystemInformation(SmbiosBaseStructure): - smbios_structure_type = 1 - - def __init__(self, u, sm): - super(SystemInformation, self).__init__(u, sm) - u = self.u - try: - self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) - self.add_field('product_name', u.unpack_one("B"), self.fmtstr) - self.add_field('version', u.unpack_one("B"), self.fmtstr) - self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) - if self.length > 0x8: - self.add_field('uuid', uuid.UUID(bytes_le=u.unpack_one("16s"))) - wakeup_types = { - 0: 'Reserved', - 1: 'Other', - 2: 'Unknown', - 3: 'APM Timer', - 4: 'Modem Ring', - 5: 'LAN Remote', - 6: 'Power Switch', - 7: 'PCI PME#', - 8: 'AC Power Restored' - } - self.add_field('wakeup_type', u.unpack_one("B"), unpack.format_table("{}", wakeup_types)) - if self.length > 0x19: - self.add_field('sku_number', u.unpack_one("B"), self.fmtstr) - self.add_field('family', u.unpack_one("B"), self.fmtstr) - except: - self.decode_failure = True - print "Error parsing SystemInformation" - import traceback - traceback.print_exc() - self.fini() - -_board_types = { - 1: 'Unknown', - 2: 'Other', - 3: 'Server Blade', - 4: 'Connectivity Switch', - 5: 'System Management Module', - 6: 'Processor Module', - 7: 'I/O Module', - 8: 'Memory Module', - 9: 'Daughter Board', - 0xA: 'Motherboard', - 0xB: 'Processor/Memory Module', - 0xC: 'Processor/IO Module', - 0xD: 'Interconnect Board' -} - -class BaseboardInformation(SmbiosBaseStructure): - smbios_structure_type = 2 - - def __init__(self, u, sm): - super(BaseboardInformation, self).__init__(u, sm) - u = self.u - try: - self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) - self.add_field('product', u.unpack_one("B"), self.fmtstr) - self.add_field('version', u.unpack_one("B"), self.fmtstr) - self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) - - if self.length > 0x8: - self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr) - - if self.length > 0x9: - self.add_field('feature_flags', u.unpack_one("B")) - self.add_field('hosting_board', bool(bitfields.getbits(self.feature_flags, 0)), "feature_flags[0]={}") - self.add_field('requires_daughter_card', bool(bitfields.getbits(self.feature_flags, 1)), "feature_flags[1]={}") - self.add_field('removable', bool(bitfields.getbits(self.feature_flags, 2)), "feature_flags[2]={}") - self.add_field('replaceable', bool(bitfields.getbits(self.feature_flags, 3)), "feature_flags[3]={}") - self.add_field('hot_swappable', bool(bitfields.getbits(self.feature_flags, 4)), "feature_flags[4]={}") - - if self.length > 0xA: - self.add_field('location', u.unpack_one("B"), self.fmtstr) - - if self.length > 0xB: - self.add_field('chassis_handle', u.unpack_one(" 0xD: - self.add_field('board_type', u.unpack_one("B"), unpack.format_table("{}", _board_types)) - - if self.length > 0xE: - self.add_field('handle_count', u.unpack_one("B")) - if self.handle_count > 0: - self.add_field('contained_object_handles', tuple(u.unpack_one(" 9: - chassis_states = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Safe', - 0x04: 'Warning', - 0x05: 'Critical', - 0x06: 'Non-recoverable', - } - self.add_field('bootup_state', u.unpack_one("B"), unpack.format_table("{}", chassis_states)) - self.add_field('power_supply_state', u.unpack_one("B"), unpack.format_table("{}", chassis_states)) - self.add_field('thermal_state', u.unpack_one("B"), unpack.format_table("{}", chassis_states)) - security_states = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'None', - 0x04: 'External interface locked out', - 0x05: 'External interface enabled', - } - self.add_field('security_status', u.unpack_one("B"), unpack.format_table("{}", security_states)) - if self.length > 0xd: - self.add_field('oem_defined', u.unpack_one(" 0x11: - self.add_field('height', u.unpack_one("B")) - self.add_field('num_power_cords', u.unpack_one("B")) - self.add_field('contained_element_count', u.unpack_one("B")) - self.add_field('contained_element_length', u.unpack_one("B")) - if getattr(self, 'contained_element_count', 0): - self.add_field('contained_elements', tuple(SystemEnclosureContainedElement(u, self.contained_element_length) for i in range(self.contained_element_count))) - if self.length > (0x15 + (getattr(self, 'contained_element_count', 0) * getattr(self, 'contained_element_length', 0))): - self.add_field('sku_number', u.unpack_one("B"), self.fmtstr) - except: - self.decode_failure = True - print "Error parsing SystemEnclosure" - import traceback - traceback.print_exc() - self.fini() - -class SystemEnclosureContainedElement(unpack.Struct): - def __init__(self, u, length): - super(SystemEnclosureContainedElement, self).__init__() - self.start_offset = u.offset - self.raw_data = u.unpack_raw(length) - self.u = unpack.Unpackable(self.raw_data) - u = self.u - self.add_field('contained_element_type', u.unpack_one("B")) - type_selections = { - 0: 'SMBIOS baseboard type enumeration', - 1: 'SMBIOS structure type enumeration', - } - self.add_field('type_select', bitfields.getbits(self.contained_element_type, 7), unpack.format_table("contained_element_type[7]={}", type_selections)) - self.add_field('type', bitfields.getbits(self.contained_element_type, 6, 0)) - if self.type_select == 0: - self.add_field('smbios_board_type', self.type, unpack.format_table("{}", _board_types)) - else: - self.add_field('smbios_structure_type', self.type) - self.add_field('minimum', u.unpack_one("B")) - self.add_field('maximum', u.unpack_one("B")) - if not u.at_end(): - self.add_field('data', u.unpack_rest()) - del self.u - -class ProcessorInformation(SmbiosBaseStructure): - smbios_structure_type = 4 - - def __init__(self, u, sm): - super(ProcessorInformation, self).__init__(u, sm) - u = self.u - try: - self.add_field('socket_designation', u.unpack_one("B"), self.fmtstr) - processor_types = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Central Processor', - 0x04: 'Math Processor', - 0x05: 'DSP Processor', - 0x06: 'Video Processor', - } - self.add_field('processor_type', u.unpack_one("B"), unpack.format_table("{}", processor_types)) - self.add_field('processor_family', u.unpack_one("B")) - self.add_field('processor_manufacturer', u.unpack_one("B"), self.fmtstr) - self.add_field('processor_id', u.unpack_one(" 0x1A: - self.add_field('l1_cache_handle', u.unpack_one(" 0x20: - self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) - self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr) - self.add_field('part_number', u.unpack_one("B"), self.fmtstr) - if self.length > 0x24: - self.add_field('core_count', u.unpack_one("B")) - self.add_field('core_enabled', u.unpack_one("B")) - self.add_field('thread_count', u.unpack_one("B")) - self.add_field('processor_characteristics', u.unpack_one(" 0x28: - self.add_field('processor_family_2', u.unpack_one(" 0x2A: - self.add_field('core_count2', u.unpack_one(" 0x0F: - self.add_field('cache_speed', u.unpack_one("B")) - if self.length > 0x10: - _error_correction = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'None', - 0x04: 'Parity', - 0x05: 'Single-bit ECC', - 0x06: 'Multi-bit ECC' - } - self.add_field('error_correction', u.unpack_one("B"), unpack.format_table("{}", _error_correction)) - if self.length > 0x10: - _system_cache_type = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Instruction', - 0x04: 'Data', - 0x05: 'Unified' - } - self.add_field('system_cache_type', u.unpack_one("B"), unpack.format_table("{}", _system_cache_type)) - if self.length > 0x12: - _associativity = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Direct Mapped', - 0x04: '2-way Set-Associative', - 0x05: '4-way Set-Associative', - 0x06: 'Fully Associative', - 0x07: '8-way Set-Associative', - 0x08: '16-way Set-Associative', - 0x09: '12-way Set-Associative', - 0x0A: '24-way Set-Associative', - 0x0B: '32-way Set-Associative', - 0x0C: '48-way Set-Associative', - 0x0D: '64-way Set-Associative', - 0x0E: '20-way Set-Associative' - } - self.add_field('associativity', u.unpack_one("B"), unpack.format_table("{}", _associativity)) - - except: - self.decode_failure = True - print "Error parsing CacheInformation" - import traceback - traceback.print_exc() - self.fini() - -class PortConnectorInfo(SmbiosBaseStructure): - smbios_structure_type = 8 - - def __init__(self, u, sm): - super(PortConnectorInfo, self).__init__(u, sm) - u = self.u - try: - self.add_field('internal_reference_designator', u.unpack_one("B"), self.fmtstr) - connector_types = { - 0x00: 'None', - 0x01: 'Centronics', - 0x02: 'Mini Centronics', - 0x03: 'Proprietary', - 0x04: 'DB-25 pin male', - 0x05: 'DB-25 pin female', - 0x06: 'DB-15 pin male', - 0x07: 'DB-15 pin female', - 0x08: 'DB-9 pin male', - 0x09: 'DB-9 pin female', - 0x0A: 'RJ-11', - 0x0B: 'RJ-45', - 0x0C: '50-pin MiniSCSI', - 0x0D: 'Mini-DIN', - 0x0E: 'Micro-DIN', - 0x0F: 'PS/2', - 0x10: 'Infrared', - 0x11: 'HP-HIL', - 0x12: 'Access Bus (USB)', - 0x13: 'SSA SCSI', - 0x14: 'Circular DIN-8 male', - 0x15: 'Circular DIN-8 female', - 0x16: 'On Board IDE', - 0x17: 'On Board Floppy', - 0x18: '9-pin Dual Inline (pin 10 cut)', - 0x19: '25-pin Dual Inline (pin 26 cut)', - 0x1A: '50-pin Dual Inline', - 0x1B: '68-pin Dual Inline', - 0x1C: 'On Board Sound Input from CD-ROM', - 0x1D: 'Mini-Centronics Type-14', - 0x1E: 'Mini-Centronics Type-26', - 0x1F: 'Mini-jack (headphones)', - 0x20: 'BNC', - 0x21: '1394', - 0x22: 'SAS/SATA Plug Receptacle', - 0xA0: 'PC-98', - 0xA1: 'PC-98Hireso', - 0xA2: 'PC-H98', - 0xA3: 'PC-98Note', - 0xA4: 'PC-98Full', - 0xFF: 'Other', - } - self.add_field('internal_connector_type', u.unpack_one("B"), unpack.format_table("{}", connector_types)) - self.add_field('external_reference_designator', u.unpack_one("B"), self.fmtstr) - self.add_field('external_connector_type', u.unpack_one("B"), unpack.format_table("{}", connector_types)) - port_types = { - 0x00: 'None', - 0x01: 'Parallel Port XT/AT Compatible', - 0x02: 'Parallel Port PS/2', - 0x03: 'Parallel Port ECP', - 0x04: 'Parallel Port EPP', - 0x05: 'Parallel Port ECP/EPP', - 0x06: 'Serial Port XT/AT Compatible', - 0x07: 'Serial Port 16450 Compatible', - 0x08: 'Serial Port 16550 Compatible', - 0x09: 'Serial Port 16550A Compatible', - 0x0A: 'SCSI Port', - 0x0B: 'MIDI Port', - 0x0C: 'Joy Stick Port', - 0x0D: 'Keyboard Port', - 0x0E: 'Mouse Port', - 0x0F: 'SSA SCSI', - 0x10: 'USB', - 0x11: 'FireWire (IEEE P1394)', - 0x12: 'PCMCIA Type I2', - 0x13: 'PCMCIA Type II', - 0x14: 'PCMCIA Type III', - 0x15: 'Cardbus', - 0x16: 'Access Bus Port', - 0x17: 'SCSI II', - 0x18: 'SCSI Wide', - 0x19: 'PC-98', - 0x1A: 'PC-98-Hireso', - 0x1B: 'PC-H98', - 0x1C: 'Video Port', - 0x1D: 'Audio Port', - 0x1E: 'Modem Port', - 0x1F: 'Network Port', - 0x20: 'SATA', - 0x21: 'SAS', - 0xA0: '8251 Compatible', - 0xA1: '8251 FIFO Compatible', - 0xFF: 'Other', - } - self.add_field('port_type', u.unpack_one("B"), unpack.format_table("{}", port_types)) - except: - self.decodeFailure = True - print "Error parsing PortConnectorInfo" - import traceback - traceback.print_exc() - self.fini() - -class SystemSlots(SmbiosBaseStructure): - smbios_structure_type = 9 - - def __init__(self, u, sm): - super(SystemSlots, self).__init__(u, sm) - u = self.u - try: - self.add_field('designation', u.unpack_one("B"), self.fmtstr) - _slot_types = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'ISA', - 0x04: 'MCA', - 0x05: 'EISA', - 0x06: 'PCI', - 0x07: 'PC Card (PCMCIA)', - 0x08: 'VL-VESA', - 0x09: 'Proprietary', - 0x0A: 'Processor Card Slot', - 0x0B: 'Proprietary Memory Card Slot', - 0x0C: 'I/O Riser Card Slot', - 0x0D: 'NuBus', - 0x0E: 'PCI 66MHz Capable', - 0x0F: 'AGP', - 0x10: 'AGP 2X', - 0x11: 'AGP 4X', - 0x12: 'PCI-X', - 0x13: 'AGP 8X', - 0xA0: 'PC-98/C20', - 0xA1: 'PC-98/C24', - 0xA2: 'PC-98/E', - 0xA3: 'PC-98/Local Bus', - 0xA4: 'PC-98/Card', - 0xA5: 'PCI Express', - 0xA6: 'PCI Express x1', - 0xA7: 'PCI Express x2', - 0xA8: 'PCI Express x4', - 0xA9: 'PCI Express x8', - 0xAA: 'PCI Express x16', - 0xAB: 'PCI Express Gen 2', - 0xAC: 'PCI Express Gen 2 x1', - 0xAD: 'PCI Express Gen 2 x2', - 0xAE: 'PCI Express Gen 2 x4', - 0xAF: 'PCI Express Gen 2 x8', - 0xB0: 'PCI Express Gen 2 x16', - 0xB1: 'PCI Express Gen 3', - 0xB2: 'PCI Express Gen 3 x1', - 0xB3: 'PCI Express Gen 3 x2', - 0xB4: 'PCI Express Gen 3 x4', - 0xB5: 'PCI Express Gen 3 x8', - 0xB6: 'PCI Express Gen 3 x16', - } - self.add_field('slot_type', u.unpack_one("B"), unpack.format_table("{}", _slot_types)) - _slot_data_bus_widths = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: '8 bit', - 0x04: '16 bit', - 0x05: '32 bit', - 0x06: '64 bit', - 0x07: '128 bit', - 0x08: '1x or x1', - 0x09: '2x or x2', - 0x0A: '4x or x4', - 0x0B: '8x or x8', - 0x0C: '12x or x12', - 0x0D: '16x or x16', - 0x0E: '32x or x32', - } - self.add_field('slot_data_bus_width', u.unpack_one('B'), unpack.format_table("{}", _slot_data_bus_widths)) - _current_usages = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Available', - 0x04: 'In use', - } - self.add_field('current_usage', u.unpack_one('B'), unpack.format_table("{}", _current_usages)) - _slot_lengths = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Short Length', - 0x04: 'Long Length', - } - self.add_field('slot_length', u.unpack_one('B'), unpack.format_table("{}", _slot_lengths)) - self.add_field('slot_id', u.unpack_one(' 0x0C: - self.add_field('characteristics2', u.unpack_one('B')) - self.add_field('supports_PME', bool(bitfields.getbits(self.characteristics2, 0)), "characteristics2[0]={}") - self.add_field('supports_hot_plug', bool(bitfields.getbits(self.characteristics2, 1)), "characteristics2[1]={}") - self.add_field('supports_smbus', bool(bitfields.getbits(self.characteristics2, 2)), "characteristics2[2]={}") - if self.length > 0x0D: - self.add_field('segment_group_number', u.unpack_one(' 0x05: - self.add_field('flags', u.unpack_one('B')) - self.add_field('abbreviated_format', bool(bitfields.getbits(self.flags, 0)), "flags[0]={}") - if self.length > 0x6: - u.skip(15) - self.add_field('current_language', u.unpack_one('B'), self.fmtstr) - except: - self.decodeFailure = True - print "Error parsing BIOSLanguageInformation" - import traceback - traceback.print_exc() - self.fini() - -class GroupAssociations(SmbiosBaseStructure): - smbios_structure_type = 14 - - def __init__(self, u, sm): - super(GroupAssociations, self).__init__(u, sm) - u = self.u - try: - self.add_field('group_name', u.unpack_one("B"), self.fmtstr) - self.add_field('item_type', u.unpack_one('B')) - self.add_field('item_handle', u.unpack_one(' 0x14: - _log_header_formats = { - 0: 'No header', - 1: 'Type 1 log header', - xrange(2, 0x7f): 'Available for future assignment', - xrange(0x80, 0xff): 'BIOS vendor or OEM-specific format' - } - self.add_field('log_header_format', u.unpack_one("B"), unpack.format_table("{}", _log_header_formats)) - if self.length > 0x15: - self.add_field('num_supported_log_type_descriptors', u.unpack_one('B')) - if self.length > 0x16: - self.add_field('length_log_type_descriptor', u.unpack_one('B')) - if self.length != (0x17 + (self.num_supported_log_type_descriptors * self.length_log_type_descriptor)): - print "Error: structure length ({}) != 0x17 + (num_supported_log_type_descriptors ({}) * length_log_type_descriptor({}))".format(self.length, self.num_supported_log_type_descriptors, self.length_log_type_descriptor) - print "structure length = {}".format(self.length) - print "num_supported_log_type_descriptors = {}".format(self.num_supported_log_type_descriptors) - print "length_log_type_descriptor = {}".format(self.length_log_type_descriptor) - self.decodeFailure = True - self.add_field('descriptors', tuple(EventLogDescriptor.unpack(u) for i in range(self.num_supported_log_type_descriptors)), unpack.format_each("\n{!r}")) - except: - self.decodeFailure = True - print "Error parsing SystemEventLog" - import traceback - traceback.print_exc() - self.fini() - -class EventLogDescriptor(unpack.Struct): - @staticmethod - def _unpack(u): - _event_log_type_descriptors = { - 0x00: 'Reserved', - 0x01: 'Single-bit ECC memory error', - 0x02: 'Multi-bit ECC memory error', - 0x03: 'Parity memory error', - 0x04: 'Bus time-out', - 0x05: 'I/O Channel Check', - 0x06: 'Software NMI', - 0x07: 'POST Memory Resize', - 0x08: 'POST Error', - 0x09: 'PCI Parity Error', - 0x0A: 'PCI System Error', - 0x0B: 'CPU Failure', - 0x0C: 'EISA FailSafe Timer time-out', - 0x0D: 'Correctable memory log disabled', - 0x0E: 'Logging disabled for a specific Event Type - too many errors of the same type received in a short amount of time', - 0x0F: 'Reserved', - 0x10: 'System Limit Exceeded', - 0x11: 'Asynchronous hardware timer expired and issued a system reset', - 0x12: 'System configuration information', - 0x13: 'Hard-disk information', - 0x14: 'System reconfigured', - 0x15: 'Uncorrectable CPU-complex error', - 0x16: 'Log Area Reset/Cleared', - 0x17: 'System boot', - xrange(0x18, 0x7F): 'Unused, available for assignment', - xrange(0x80, 0xFE): 'Available for system- and OEM-specific assignments', - 0xFF: 'End of log' - } - yield 'log_type', u.unpack_one('B'), unpack.format_table("{}", _event_log_type_descriptors) - _event_log_format = { - 0x00: 'None', - 0x01: 'Handle', - 0x02: 'Multiple-Event', - 0x03: 'Multiple-Event Handle', - 0x04: 'POST Results Bitmap', - 0x05: 'System Management Type', - 0x06: 'Multiple-Event System Management Type', - xrange(0x80, 0xFF): 'OEM assigned' - } - yield 'variable_data_format_type', u.unpack_one('B'), unpack.format_table("{}", _event_log_format) - -class PhysicalMemoryArray(SmbiosBaseStructure): - smbios_structure_type = 16 - - def __init__(self, u, sm): - super(PhysicalMemoryArray, self).__init__(u, sm) - u = self.u - try: - if self.length > 0x4: - _location_field = { - 0x01: "Other", - 0x02: "Unknown", - 0x03: "System board or motherboard", - 0x04: "ISA add-on card", - 0x05: "EISA add-on card", - 0x06: "PCI add-on card", - 0x07: "MCA add-on card", - 0x08: "PCMCIA add-on card", - 0x09: "Proprietary add-on card", - 0x0A: "NuBus", - 0xA0: "PC-98/C20 add-on card", - 0xA1: "PC-98/C24 add-on card", - 0xA2: "PC-98/E add-on card", - 0xA3: "PC-98/Local bus add-on card" - } - self.add_field('location', u.unpack_one("B"), unpack.format_table("{}", _location_field)) - if self.length > 0x05: - _use = { - 0x01: "Other", - 0x02: "Unknown", - 0x03: "System memory", - 0x04: "Video memory", - 0x05: "Flash memory", - 0x06: "Non-volatile RAM", - 0x07: "Cache memory" - } - self.add_field('use', u.unpack_one('B'), unpack.format_table("{}", _use)) - if self.length > 0x06: - _error_correction = { - 0x01: "Other", - 0x02: "Unknown", - 0x03: "None", - 0x04: "Parity", - 0x05: "Single-bit ECC", - 0x06: "Multi-bit ECC", - 0x07: "CRC" - } - self.add_field('memory_error_correction', u.unpack_one('B'), unpack.format_table("{}", _error_correction)) - if self.length > 0x07: - self.add_field('maximum_capacity', u.unpack_one(' 0x0B: - self.add_field('memory_error_information_handle', u.unpack_one(' 0x0D: - self.add_field('num_memory_devices', u.unpack_one(' 0x0F: - self.add_field('extended_maximum_capacity', u.unpack_one(' 0x4: - self.add_field('physical_memory_array_handle', u.unpack_one(" 0x6: - self.add_field('memory_error_information_handle', u.unpack_one(" 0x8: - self.add_field('total_width', u.unpack_one(" 0xA: - self.add_field('data_width', u.unpack_one(" 0xC: - self.add_field('size', u.unpack_one(" 0xE: - _form_factors = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'SIMM', - 0x04: 'SIP', - 0x05: 'Chip', - 0x06: 'DIP', - 0x07: 'ZIP', - 0x08: 'Proprietary Card', - 0x09: 'DIMM', - 0x0A: 'TSOP', - 0x0B: 'Row of chips', - 0x0C: 'RIMM', - 0x0D: 'SODIMM', - 0x0E: 'SRIMM', - 0x0F: 'FB-DIMM' - } - self.add_field('form_factor', u.unpack_one("B"), unpack.format_table("{}", _form_factors)) - if self.length > 0xF: - self.add_field('device_set', u.unpack_one("B")) - if self.length > 0x10: - self.add_field('device_locator', u.unpack_one("B"), self.fmtstr) - if self.length > 0x11: - self.add_field('bank_locator', u.unpack_one("B"), self.fmtstr) - if self.length > 0x12: - _memory_types = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'DRAM', - 0x04: 'EDRAM', - 0x05: 'VRAM', - 0x06: 'SRAM', - 0x07: 'RAM', - 0x08: 'ROM', - 0x09: 'FLASH', - 0x0A: 'EEPROM', - 0x0B: 'FEPROM', - 0x0C: 'EPROM', - 0x0D: 'CDRAM', - 0x0E: '3DRAM', - 0x0F: 'SDRAM', - 0x10: 'SGRAM', - 0x11: 'RDRAM', - 0x12: 'DDR', - 0x13: 'DDR2', - 0x14: 'DDR2 FB-DIMM', - xrange(0x15, 0x17): 'Reserved', - 0x18: 'DDR3', - 0x19: 'FBD2' - } - self.add_field('memory_type', u.unpack_one("B"), unpack.format_table("{}", _memory_types)) - if self.length > 0x13: - self.add_field('type_detail', u.unpack_one(' 0x15: - self.add_field('speed', u.unpack_one(" 0x17: - self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) - if self.length > 0x18: - self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) - if self.length > 0x19: - self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr) - if self.length > 0x1A: - self.add_field('part_number', u.unpack_one("B"), self.fmtstr) - if self.length > 0x1B: - self.add_field('attributes', u.unpack_one("B")) - self.add_field('rank', bitfields.getbits(self.attributes, 3, 0), "attributes[3:0]={}") - if self.length > 0x1C: - if self.size == 0x7FFF: - self.add_field('extended_size', u.unpack_one(' 0x20: - self.add_field('configured_memory_clock_speed', u.unpack_one(" 0x22: - self.add_field('minimum_voltage', u.unpack_one(" 0x24: - self.add_field('maximum_voltage', u.unpack_one(" 0x26: - self.add_field('configured_voltage', u.unpack_one(" 0x4: - _error_types = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'OK', - 0x04: 'Bad read', - 0x05: 'Parity error', - 0x06: 'Single-bit error', - 0x07: 'Double-bit error', - 0x08: 'Multi-bit error', - 0x09: 'Nibble error', - 0x0A: 'Checksum error', - 0x0B: 'CRC error', - 0x0C: 'Corrected single-bit error', - 0x0D: 'Corrected error', - 0x0E: 'Uncorrectable error' - } - self.add_field('error_type', u.unpack_one("B"), unpack.format_table("{}", _error_types)) - if self.length > 0x5: - _error_granularity_field = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Device level', - 0x04: 'Memory partition level' - } - self.add_field('error_granularity', u.unpack_one("B"), unpack.format_table("{}", _error_granularity_field)) - if self.length > 0x6: - _error_operation_field = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Read', - 0x04: 'Write', - 0x05: 'Partial write' - } - self.add_field('error_operation', u.unpack_one("B"), unpack.format_table("{}", _error_operation_field)) - if self.length > 0x7: - self.add_field('vendor_syndrome', u.unpack_one(" 0xB: - self.add_field('memory_array_error_address', u.unpack_one(" 0xF: - self.add_field('device_error_address', u.unpack_one(" 0x13: - self.add_field('error_resolution', u.unpack_one(" 0x4: - self.add_field('starting_address', u.unpack_one(" 0x8: - self.add_field('ending_address', u.unpack_one(" 0xC: - self.add_field('memory_array_handle', u.unpack_one(" 0xE: - self.add_field('partition_width', u.unpack_one("B")) - if self.length > 0xF: - # valid if starting_address = FFFF FFFF - if self.starting_address == 0xFFFFFFFF: - self.add_field('extended_starting_address', u.unpack_one(" 0x17: - self.add_field('extended_ending_address', u.unpack_one(" 0x4: - self.add_field('starting_address', u.unpack_one(" 0x8: - self.add_field('ending_address', u.unpack_one(" 0xC: - self.add_field('memory_device_handle', u.unpack_one(" 0xE: - self.add_field('memory_array_mapped_address_handle', u.unpack_one(" 0x10: - self.add_field('partition_row_position', u.unpack_one("B")) - if self.length > 0x11: - self.add_field('interleave_position', u.unpack_one("B")) - if self.length > 0x12: - self.add_field('interleave_data_depth', u.unpack_one("B")) - if self.length > 0x13: - # valid if starting_address = FFFF FFFF - if self.starting_address == 0xFFFFFFFF: - self.add_field('extended_starting_address', u.unpack_one(" 0x1B: - self.add_field('extended_ending_address', u.unpack_one(" 0x4: - _pointing_device_types = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Mouse', - 0x04: 'Track Ball', - 0x05: 'Track Point', - 0x06: 'Glide Point', - 0x07: 'Touch Pad', - 0x08: 'Touch Screen', - 0x09: 'Optical Sensor' - } - self.add_field('pointing_device_type', u.unpack_one("B"), unpack.format_table("{}", _pointing_device_types)) - if self.length > 0x5: - _interfaces = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Serial', - 0x04: 'PS/2', - 0x05: 'Infared', - 0x06: 'HP-HIL', - 0x07: 'Bus mouse', - 0x08: 'ADB (Apple Desktop Bus)', - 0x09: 'Bus mouse DB-9', - 0x0A: 'Bus mouse micro-DIN', - 0x0B: 'USB' - } - self.add_field('interface', u.unpack_one("B"), unpack.format_table("{}", _interfaces)) - if self.length > 0x6: - self.add_field('num_buttons', u.unpack_one("B")) - except: - self.decodeFailure = True - print "Error parsing BuiltInPointingDevice" - import traceback - traceback.print_exc() - self.fini() - -class PortableBattery(SmbiosBaseStructure): - smbios_structure_type = 22 - - def __init__(self, u, sm): - super(PortableBattery, self).__init__(u, sm) - u = self.u - try: - if self.length > 0x4: - self.add_field('location', u.unpack_one("B"), self.fmtstr) - if self.length > 0x5: - self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) - if self.length > 0x6: - self.add_field('manufacturer_date', u.unpack_one("B"), self.fmtstr) - if self.length > 0x7: - self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) - if self.length > 0x8: - self.add_field('device_name', u.unpack_one("B"), self.fmtstr) - if self.length > 0x9: - _device_chemistry = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Lead Acid', - 0x04: 'Nickel Cadmium', - 0x05: 'Nickel metal hydride', - 0x06: 'Lithium-ion', - 0x07: 'Zinc air', - 0x08: 'Lithium Polymer' - } - self.add_field('device_chemistry', u.unpack_one("B"), unpack.format_table("{}", _device_chemistry)) - if self.length > 0xA: - self.add_field('design_capacity', u.unpack_one(" 0xC: - self.add_field('design_voltage', u.unpack_one(" 0xE: - self.add_field('sbds_version_number', u.unpack_one("B"), self.fmtstr) - if self.length > 0xF: - self.add_field('max_error_battery_data', u.unpack_one("B"), self.fmtstr) - if self.length > 0x10: - if self.serial_number == 0: - self.add_field('sbds_serial_number', u.unpack_one(" 0x12: - if self.manufacturer_date == 0: - self.add_field('sbds_manufacture_date', u.unpack_one(" 0x14: - if self.device_chemistry == 0x02: - self.add_field('sbds_device_chemistry', u.unpack_one("B"), self.fmtstr) - else: - u.skip(1) - if self.length > 0x15: - self.add_field('design_capacity_multiplier', u.unpack_one("B")) - if self.length > 0x16: - self.add_field('oem_specific', u.unpack_one(" 0x4: - self.add_field('capabilities', u.unpack_one("B")) - self.add_field('contains_watchdog_timer', bool(bitfields.getbits(self.capabilities, 5)), "capabilities[5]={}") - _boot_option = { - 0b00: 'Reserved, do not use', - 0b01: 'Operating System', - 0b10: 'System utilities', - 0b11: 'Do not reboot' - } - self.add_field('boot_option_on_limit', bitfields.getbits(self.capabilities, 4, 3), unpack.format_table("capabilities[4:3]={}", _boot_option)) - self.add_field('boot_option_after_watchdog_reset', bitfields.getbits(self.capabilities, 2, 1), unpack.format_table("capabilities[2:1]={}", _boot_option)) - self.add_field('system_reset_enabled_by_user', bool(bitfields.getbits(self.capabilities, 0)), "capabilities[0]={}") - if self.length > 0x5: - self.add_field('reset_count', u.unpack_one(" 0x5: - self.add_field('reset_limit', u.unpack_one(" 0x9: - self.add_field('timer_interval', u.unpack_one(" 0xB: - self.add_field('timeout', u.unpack_one(" 0x4: - self.add_field('hardware_security_settings', u.unpack_one("B")) - _status = { - 0x00: 'Disabled', - 0x01: 'Enabled', - 0x02: 'Not Implemented', - 0x03: 'Unknown' - } - self.add_field('power_on_password_status', bitfields.getbits(self.hardware_security_settings, 7, 6), unpack.format_table("hardware_security_settings[7:6]={}", _status)) - self.add_field('keyboard_password_status', bitfields.getbits(self.hardware_security_settings, 5, 4), unpack.format_table("hardware_security_settings[5:4]={}", _status)) - self.add_field('admin_password_status', bitfields.getbits(self.hardware_security_settings, 3, 2), unpack.format_table("hardware_security_settings0[3:2]={}", _status)) - self.add_field('front_panel_reset_status', bitfields.getbits(self.hardware_security_settings, 1, 0), unpack.format_table("hardware_security_settings[1:0]={}", _status)) - except: - self.decodeFailure = True - print "Error parsing HardwareSecurity" - import traceback - traceback.print_exc() - self.fini() - -class SystemPowerControls(SmbiosBaseStructure): - smbios_structure_type = 25 - - def __init__(self, u, sm): - super(SystemPowerControls, self).__init__(u, sm) - u = self.u - try: - if self.length > 0x4: - self.add_field('next_scheduled_poweron_month', u.unpack_one("B")) - self.add_field('next_scheduled_poweron_day_of_month', u.unpack_one("B")) - self.add_field('next_scheduled_poweron_hour', u.unpack_one("B")) - self.add_field('next_scheduled_poweron_minute', u.unpack_one("B")) - self.add_field('next_scheduled_poweron_second', u.unpack_one("B")) - except: - self.decodeFailure = True - print "Error parsing SystemPowerControls" - import traceback - traceback.print_exc() - self.fini() - -class VoltageProbe(SmbiosBaseStructure): - smbios_structure_type = 26 - - def __init__(self, u, sm): - super(VoltageProbe, self).__init__(u, sm) - u = self.u - try: - if self.length > 0x4: - self.add_field('description', u.unpack_one("B"), self.fmtstr) - if self.length > 0x5: - self.add_field('location_and_status', u.unpack_one("B")) - _status = { - 0b001: 'Other', - 0b010: 'Unknown', - 0b011: 'OK', - 0b100: 'Non-critical', - 0b101: 'Critical', - 0b110: 'Non-recoverable' - } - _location = { - 0b00001: 'Other', - 0b00010: 'Unknown', - 0b00011: 'Processor', - 0b00100: 'Disk', - 0b00101: 'Peripheral Bay', - 0b00110: 'System Management Module', - 0b00111: 'Motherboard', - 0b01000: 'Memory Module', - 0b01001: 'Processor Module', - 0b01010: 'Power Unit', - 0b01011: 'Add-in Card' - } - self.add_field('status', bitfields.getbits(self.location_and_status, 7, 5), unpack.format_table("location_and_status[7:5]={}", _status)) - self.add_field('location', bitfields.getbits(self.location_and_status, 4, 0), unpack.format_table("location_and_status[4:0]={}", _location)) - if self.length > 0x6: - self.add_field('max_value', u.unpack_one(" 0x8: - self.add_field('min_value', u.unpack_one(" 0xA: - self.add_field('resolution', u.unpack_one(" 0xC: - self.add_field('tolerance', u.unpack_one(" 0xE: - self.add_field('accuracy', u.unpack_one(" 0x10: - self.add_field('oem_defined', u.unpack_one(" 0x14: - self.add_field('nominal_value', u.unpack_one(" 0x4: - self.add_field('temperature_probe_handle', u.unpack_one(" 0x6: - self.add_field('device_type_and_status', u.unpack_one("B")) - _status = { - 0b001: 'Other', - 0b010: 'Unknown', - 0b011: 'OK', - 0b100: 'Non-critical', - 0b101: 'Critical', - 0b110: 'Non-recoverable' - } - _type = { - 0b00001: 'Other', - 0b00010: 'Unknown', - 0b00011: 'Fan', - 0b00100: 'Centrifugal Blower', - 0b00101: 'Chip Fan', - 0b00110: 'Cabinet Fan', - 0b00111: 'Power Supply Fan', - 0b01000: 'Heat Pipe', - 0b01001: 'Integrated Refrigeration', - 0b10000: 'Active Cooling', - 0b10001: 'Passive Cooling' - } - self.add_field('status', bitfields.getbits(self.device_type_and_status, 7, 5), unpack.format_table("device_type_and_status[7:5]={}", _status)) - self.add_field('device_type', bitfields.getbits(self.device_type_and_status, 4, 0), unpack.format_table("device_type_and_status[4:0]={}", _type)) - if self.length > 0x7: - self.add_field('cooling_unit_group', u.unpack_one("B")) - if self.length > 0x8: - self.add_field('OEM_defined', u.unpack_one(" 0xC: - self.add_field('nominal_speed', u.unpack_one(" 0xE: - self.add_field('description', u.unpack_one("B"), self.fmtstr) - except: - self.decodeFailure = True - print "Error parsing CoolingDevice" - import traceback - traceback.print_exc() - self.fini() - -class TemperatureProbe(SmbiosBaseStructure): - smbios_structure_type = 28 - - def __init__(self, u, sm): - super(TemperatureProbe, self).__init__(u, sm) - u = self.u - try: - if self.length > 0x4: - self.add_field('description', u.unpack_one("B"), self.fmtstr) - if self.length > 0x5: - self.add_field('location_and_status', u.unpack_one("B")) - _status = { - 0b001: 'Other', - 0b010: 'Unknown', - 0b011: 'OK', - 0b100: 'Non-critical', - 0b101: 'Critical', - 0b110: 'Non-recoverable' - } - _location = { - 0b00001: 'Other', - 0b00010: 'Unknown', - 0b00011: 'Processor', - 0b00100: 'Disk', - 0b00101: 'Peripheral Bay', - 0b00110: 'System Management Module', - 0b00111: 'Motherboard', - 0b01000: 'Memory Module', - 0b01001: 'Processor Module', - 0b01010: 'Power Unit', - 0b01011: 'Add-in Card', - 0b01100: 'Front Panel Board', - 0b01101: 'Back Panel Board', - 0b01110: 'Power System Board', - 0b01111: 'Drive Back Plane' - } - self.add_field('status', bitfields.getbits(self.location_and_status, 7, 5), unpack.format_table("location_and_status[7:5]={}", _status)) - self.add_field('location', bitfields.getbits(self.location_and_status, 4, 0), unpack.format_table("location_and_status[4:0]={}", _location)) - if self.length > 0x6: - self.add_field('maximum_value', u.unpack_one(" 0x8: - self.add_field('minimum_value', u.unpack_one(" 0xA: - self.add_field('resolution', u.unpack_one(" 0xC: - self.add_field('tolerance', u.unpack_one(" 0xE: - self.add_field('accuracy', u.unpack_one(" 0x10: - self.add_field('OEM_defined', u.unpack_one(" 0x14: - self.add_field('nominal_value', u.unpack_one(" 0x4: - self.add_field('description', u.unpack_one("B"), self.fmtstr) - if self.length > 0x5: - self.add_field('location_and_status', u.unpack_one("B")) - _status = { - 0b001: 'Other', - 0b010: 'Unknown', - 0b011: 'OK', - 0b100: 'Non-critical', - 0b101: 'Critical', - 0b110: 'Non-recoverable' - } - _location = { - 0b00001: 'Other', - 0b00010: 'Unknown', - 0b00011: 'Processor', - 0b00100: 'Disk', - 0b00101: 'Peripheral Bay', - 0b00110: 'System Management Module', - 0b00111: 'Motherboard', - 0b01000: 'Memory Module', - 0b01001: 'Processor Module', - 0b01010: 'Power Unit', - 0b01011: 'Add-in Card', - 0b01100: 'Front Panel Board', - 0b01101: 'Back Panel Board', - 0b01110: 'Power System Board', - 0b01111: 'Drive Back Plane' - } - self.add_field('status', bitfields.getbits(self.location_and_status, 7, 5), unpack.format_table("location_and_status[7:5]={}", _status)) - self.add_field('location', bitfields.getbits(self.location_and_status, 4, 0), unpack.format_table("location_and_status[4:0]={}", _location)) - if self.length > 0x6: - self.add_field('maximum_value', u.unpack_one(" 0x8: - self.add_field('minimum_value', u.unpack_one(" 0xA: - self.add_field('resolution', u.unpack_one(" 0xC: - self.add_field('tolerance', u.unpack_one(" 0xE: - self.add_field('accuracy', u.unpack_one(" 0x10: - self.add_field('OEM_defined', u.unpack_one(" 0x14: - self.add_field('nominal_value', u.unpack_one(" 0x4: - self.add_field('manufacturer_name', u.unpack_one("B"), self.fmtstr) - if self.length > 0x5: - self.add_field('connections', u.unpack_one("B")) - self.add_field('outbound_connection_enabled', bool(bitfields.getbits(self.connections, 1)), "connections[1]={}") - self.add_field('inbound_connection_enabled', bool(bitfields.getbits(self.connections, 0)), "connections[0]={}") - except: - self.decodeFailure = True - print "Error parsing OutOfBandRemoteAccess" - import traceback - traceback.print_exc() - self.fini() - -class BootIntegrityServicesEntryPoint(SmbiosBaseStructure): - smbios_structure_type = 31 - -class SystemBootInformation(SmbiosBaseStructure): - smbios_structure_type = 32 - - def __init__(self, u, sm): - super(SystemBootInformation, self).__init__(u, sm) - u = self.u - try: - if self.length > 0xA: - u.skip(6) - _boot_status = { - 0: 'No errors detected', - 1: 'No bootable media', - 2: '"normal" operating system failed to load', - 3: 'Firmware-detected hardware failure, including "unknown" failure types', - 4: 'Operating system-detected hardware failure', - 5: 'User-requested boot, usually through a keystroke', - 6: 'System security violation', - 7: 'Previously-requested image', - 8: 'System watchdog timer expired, causing the system to reboot', - xrange(9,127): 'Reserved for future assignment', - xrange(128, 191): 'Vendor/OEM-specific implementations', - xrange(192, 255): 'Product-specific implementations' - } - self.add_field('boot_status', u.unpack_one("B"), unpack.format_table("{}", _boot_status)) - except: - self.decodeFailure = True - print "Error parsing SystemBootInformation" - import traceback - traceback.print_exc() - self.fini() - -class MemoryErrorInfo64Bit(SmbiosBaseStructure): - smbios_structure_type = 33 - - def __init__(self, u, sm): - super(MemoryErrorInfo64Bit, self).__init__(u, sm) - u = self.u - try: - if self.length > 0x4: - _error_types = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'OK', - 0x04: 'Bad read', - 0x05: 'Parity error', - 0x06: 'Single-bit error', - 0x07: 'Double-bit error', - 0x08: 'Multi-bit error', - 0x09: 'Nibble error', - 0x0A: 'Checksum error', - 0x0B: 'CRC error', - 0x0C: 'Corrected single-bit error', - 0x0D: 'Corrected error', - 0x0E: 'Uncorrectable error' - } - self.add_field('error_type', u.unpack_one("B"), unpack.format_table("{}", _error_types)) - if self.length > 0x5: - _error_granularity_field = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Device level', - 0x04: 'Memory partition level' - } - self.add_field('error_granularity', u.unpack_one("B"), unpack.format_table("{}", _error_granularity_field)) - if self.length > 0x6: - _error_operation_field = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Read', - 0x04: 'Write', - 0x05: 'Partial write' - } - self.add_field('error_operation', u.unpack_one("B"), unpack.format_table("{}", _error_operation_field)) - if self.length > 0x7: - self.add_field('vendor_syndrome', u.unpack_one(" 0xB: - self.add_field('memory_array_error_address', u.unpack_one(" 0xF: - self.add_field('device_error_address', u.unpack_one(" 0x13: - self.add_field('error_resolution', u.unpack_one(" 0x4: - self.add_field('description', u.unpack_one("B"), self.fmtstr) - if self.length > 0x5: - _type = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'National Semiconductor LM75', - 0x04: 'National Semiconductor LM78', - 0x05: 'National Semiconductor LM79', - 0x06: 'National Semiconductor LM80', - 0x07: 'National Semiconductor LM81', - 0x08: 'Analog Devices ADM9240', - 0x09: 'Dallas Semiconductor DS1780', - 0x0A: 'Maxim 1617', - 0x0B: 'Genesys GL518SM', - 0x0C: 'Winbond W83781D', - 0x0D: 'Holtek HT82H791' - } - self.add_field('device_type', u.unpack_one("B"), unpack.format_table("{}", _type)) - if self.length > 0x6: - self.add_field('address', u.unpack_one(" 0xA: - _address_type = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'I/O Port', - 0x04: 'Memory', - 0x05: 'SM Bus' - } - self.add_field('address_type', u.unpack_one("B"), unpack.format_table("{}", _address_type)) - except: - self.decodeFailure = True - print "Error parsing ManagementDevice" - import traceback - traceback.print_exc() - self.fini() - -class ManagementDeviceComponent(SmbiosBaseStructure): - smbios_structure_type = 35 - - def __init__(self, u, sm): - super(ManagementDeviceComponent, self).__init__(u, sm) - u = self.u - try: - if self.length > 0x4: - self.add_field('description', u.unpack_one("B"), self.fmtstr) - if self.length > 0x5: - self.add_field('management_device_handle', u.unpack_one(" 0x7: - self.add_field('component_handle', u.unpack_one(" 0x9: - self.add_field('threshold_handle', u.unpack_one(" 0x4: - self.add_field('lower_threshold_noncritical', u.unpack_one(" 0x6: - self.add_field('upper_threshold_noncritical', u.unpack_one(" 0x8: - self.add_field('lower_threshold_critical', u.unpack_one(" 0xA: - self.add_field('upper_threshold_critical', u.unpack_one(" 0xC: - self.add_field('lower_threshold_nonrecoverable', u.unpack_one(" 0xE: - self.add_field('upper_threshold_nonrecoverable', u.unpack_one(" 0x4: - _channel_type = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'RamBus', - 0x04: 'SyncLink' - } - self.add_field('channel_type', u.unpack_one("B"), unpack.format_table("{}", _channel_type)) - if self.length > 0x6: - self.add_field('max_channel_load', u.unpack_one("B")) - if self.length > 0x8: - self.add_field('memory_device_count', u.unpack_one("B")) - if self.length > 0xA: - self.add_field('memory_device_load', u.unpack_one("B")) - if self.length > 0xC: - self.add_field('memory_device_handle', u.unpack_one(" 0x4: - self.add_field('power_unit_group', u.unpack_one("B")) - if self.length > 0x5: - self.add_field('location', u.unpack_one("B"), self.fmtstr) - if self.length > 0x6: - self.add_field('device_name', u.unpack_one("B"), self.fmtstr) - if self.length > 0x7: - self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) - if self.length > 0x8: - self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) - if self.length > 0x9: - self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr) - if self.length > 0xA: - self.add_field('model_part_number', u.unpack_one("B"), self.fmtstr) - if self.length > 0xB: - self.add_field('revision_level', u.unpack_one("B"), self.fmtstr) - if self.length > 0xC: - self.add_field('max_power_capacity', u.unpack_one(" 0xE: - self.add_field('power_supply_characteristics', u.unpack_one(" 0x10: - self.add_field('input_voltage_probe_handle', u.unpack_one(" 0x12: - self.add_field('cooling_device_handle', u.unpack_one(" 0x14: - self.add_field('input_current_probe_handle', u.unpack_one(" 0x4: - self.add_field('num_additional_information_entries', u.unpack_one("B")) - if self.length > 0x5: - self.add_field('additional_information_entry_length', u.unpack_one("B")) - self.add_field('referenced_handle', u.unpack_one(" 0x4: - self.add_field('reference_designation', u.unpack_one("B"), self.fmtstr) - if self.length > 0x5: - self.add_field('device_type', u.unpack_one("B")) - self.add_field('device_enabled', bool(bitfields.getbits(self.device_type, 7)), "device_type[7]={}") - _device_types = { - 0x01: 'Other', - 0x02: 'Unknown', - 0x03: 'Video', - 0x04: 'SCSI Controller', - 0x05: 'Ethernet', - 0x06: 'Token Ring', - 0x07: 'Sound', - 0x08: 'PATA Controller', - 0x09: 'SATA Controller', - 0x0A: 'SAS Controller' - } - self.add_field('type_of_device', bitfields.getbits(self.device_type, 6, 0), unpack.format_table("device_type[6:0]={}", _device_types)) - if self.length > 0x6: - self.add_field('device_type_instance', u.unpack_one("B")) - if self.length > 0x7: - self.add_field('segment_group_number', u.unpack_one(" 0x9: - self.add_field('bus_number', u.unpack_one("B"), self.fmtstr) - if self.length > 0xA: - self.add_field('device_and_function_number', u.unpack_one("B")) - self.add_field('device_number', bitfields.getbits(self.device_type, 7, 3), "device_and_function_number[7:3]={}") - self.add_field('function_number', bitfields.getbits(self.device_type, 2, 0), "device_and_function_number[2:0]={}") - except: - self.decodeFailure = True - print "Error parsing OnboardDevicesExtendedInformation" - import traceback - traceback.print_exc() - self.fini() - -class ManagementControllerHostInterface(SmbiosBaseStructure): - smbios_structure_type = 42 - - def __init__(self, u, sm): - super(ManagementControllerHostInterface, self).__init__(u, sm) - u = self.u - try: - if self.length > 0x4: - _interface_types = { - 0x00: 'Reserved', - 0x01: 'Reserved', - 0x02: 'KCS: Keyboard Controller Style', - 0x03: '8250 UART Register Compatible', - 0x04: '16450 UART Register Compatible', - 0x05: '16550/16550A UART Register Compatible', - 0x06: '16650/16650A UART Register Compatible', - 0x07: '16750/16750A UART Register Compatible', - 0x08: '16850/16850A UART Register Compatible', - 0xF0: 'OEM' - } - self.add_field('interface_type', u.unpack_one("B"), unpack.format_table("{}", _interface_types)) - if self.length > 0x5: - self.add_field('mc_host_interface_data', u.unpack_rest(), self.fmtstr) - except: - self.decodeFailure = True - print "Error parsing ManagementControllerHostInterface" - import traceback - traceback.print_exc() - self.fini() - -class Inactive(SmbiosBaseStructure): - smbios_structure_type = 126 - - def __init__(self, u, sm): - super(Inactive, self).__init__(u, sm) - self.fini() - -class EndOfTable(SmbiosBaseStructure): - smbios_structure_type = 127 - - def __init__(self, u, sm): - super(EndOfTable, self).__init__(u, sm) - self.fini() - -class SmbiosStructureUnknown(SmbiosBaseStructure): - smbios_structure_type = None - - def __init__(self, u, sm): - super(SmbiosStructureUnknown, self).__init__(u, sm) - self.fini() - -_smbios_structures = [ - BIOSInformation, - SystemInformation, - BaseboardInformation, - SystemEnclosure, - ProcessorInformation, - MemoryControllerInformation, - MemoryModuleInformation, - CacheInformation, - PortConnectorInfo, - SystemSlots, - OnBoardDevicesInformation, - OEMStrings, - SystemConfigOptions, - BIOSLanguageInformation, - GroupAssociations, - SystemEventLog, - PhysicalMemoryArray, - MemoryDevice, - MemoryErrorInfo32Bit, - MemoryArrayMappedAddress, - MemoryDeviceMappedAddress, - BuiltInPointingDevice, - PortableBattery, - SystemReset, - HardwareSecurity, - SystemPowerControls, - VoltageProbe, - CoolingDevice, - TemperatureProbe, - ElectricalCurrentProbe, - OutOfBandRemoteAccess, - BootIntegrityServicesEntryPoint, - SystemBootInformation, - MemoryErrorInfo64Bit, - ManagementDevice, - ManagementDeviceComponent, - ManagementDeviceThresholdData, - MemoryChannel, - IPMIDeviceInformation, - SystemPowerSupply, - AdditionalInformation, - OnboardDevicesExtendedInformation, - ManagementControllerHostInterface, - Inactive, - EndOfTable, - SmbiosStructureUnknown, # Must always come last -] - -def log_smbios_info(): - with redirect.logonly(): - try: - sm = SMBIOS() - print - if sm is None: - print "No SMBIOS structures found" - return - output = {} - known_types = (0, 1) - for sm_struct in sm.structures: - if sm_struct.type in known_types: - output.setdefault(sm_struct.type, []).append(sm_struct) - if len(output) == len(known_types): - break - - print "SMBIOS information:" - for key in sorted(known_types): - for s in output.get(key, ["No structure of type {} found".format(key)]): - print ttypager._wrap("{}: {}".format(key, s)) - except: - print "Error parsing SMBIOS information:" - import traceback - traceback.print_exc() - -def dump_raw(): - try: - sm = SMBIOS() - if sm: - s = "SMBIOS -- Raw bytes and structure decode.\n\n" - - s += str(sm.header) + '\n' - s += bits.dumpmem(sm._header_memory) + '\n' - - s += "Raw bytes for the SMBIOS structures\n" - s += bits.dumpmem(sm._structure_memory) + '\n' - - for sm_struct in sm.structures: - s += str(sm_struct) + '\n' - s += bits.dumpmem(sm_struct.raw_data) - - s += "Strings:\n" - for n in range(1, len(getattr(sm_struct, "strings", [])) + 1): - s += str(sm_struct.fmtstr(n)) + '\n' - s += bits.dumpmem(sm_struct.raw_strings) + '\n' - else: - s = "No SMBIOS structures found" - ttypager.ttypager_wrap(s, indent=False) - except: - print "Error parsing SMBIOS information:" - import traceback - traceback.print_exc() - -def dump(): - try: - sm = SMBIOS() - if sm: - s = str(sm) - else: - s = "No SMBIOS structures found" - ttypager.ttypager_wrap(s, indent=False) - except: - print "Error parsing SMBIOS information:" - import traceback - traceback.print_exc() - -def annex_a_conformance(): - try: - sm = SMBIOS() - - # check: 1. The table anchor string "_SM_" is present in the address range 0xF0000 to 0xFFFFF on a 16-byte bound - - def table_entry_point_verification(): - ''' Verify table entry-point''' - if (sm.header.length < 0x1F): - print "Failure: Table entry-point - The entry-point Length must be at least 0x1F" - if sm.header.checksum != 0: - print "Failure: Table entry-point - The entry-point checksum must evaluate to 0" - if ((sm.header.major_version < 2) and (sm.header.minor_version < 4)): - print "Failure: Table entry-point - SMBIOS version must be at least 2.4" - if (sm.header.intermediate_anchor_string == '_DMI_'): - print "Failure: Table entry-point - The Intermediate Anchor String must be '_DMI_'" - if (sm.header.intermediate_checksum != 0): - print "Failure: Table entry-point - The Intermediate checksum must evaluate to 0" - - #check: 3. The structure-table is traversable and conforms to the entry-point specifications: - - def req_structures(): - '''Checks for required structures and corresponding data''' - types_present = [sm.structures[x].smbios_structure_type for x in range(len(sm.structures))] - required = [0, 1, 4, 7, 9, 16, 17, 19, 31, 32] - for s in required: - if s not in set(types_present): - print "Failure: Type {} required but not found".format(s) - - else: - if s == 0: - if types_present.count(s) > 1: - print "Failure: Type {} - One and only one structure of this type must be present.".format(s) - if sm.structure_type(s).length < 0x18: - print "Failure: Type {} - The structure Length field must be at least 0x18".format(s) - if sm.structure_type(s).version is None: - print "Failure: Type {} - BIOS Version string must be present and non-null.".format(s) - if sm.structure_type(s).release_date is None: - print "Failure: Type {} - BIOS Release Date string must be present, non-null, and include a 4-digit year".format(s) - if bitfields.getbits(sm.structure_type(s).characteristics, 3, 0) != 0 or bitfields.getbits(sm.structure_type(s).characteristics, 31, 4) == 0: - print "Failure: Type {} - BIOS Characteristics: bits 3:0 must all be 0, and at least one of bits 31:4 must be set to 1.".format(s) - elif s == 1: - if types_present.count(s) > 1: - print "Failure: Type {} - One and only one structure of this type must be present.".format(s) - if sm.structure_type(s).length < 0x1B: - print "Failure: Type {} - The structure Length field must be at least 0x1B".format(s) - if sm.structure_type(s).manufacturer == None: - print "Failure: Type {} - Manufacturer string must be present and non-null.".format(s) - if sm.structure_type(s).product_name == None: - print "Failure: Type {} - Product Name string must be present and non-null".format(s) - if sm.structure_type(s).uuid == '00000000 00000000' and sm.structure_type(s).uuid == 'FFFFFFFF FFFFFFFF': - print "Failure: Type {} - UUID field must be neither 00000000 00000000 nor FFFFFFFF FFFFFFFF.".format(s) - if sm.structure_type(s).wakeup_type == 00 and sm.structure_type(s).wakeup_type == 0x02: - print "Failure: Type {} - Wake-up Type field must be neither 00h (Reserved) nor 02h (Unknown).".format(s) - # continue for remaining required types - - # check remaining conformance guidelines - - table_entry_point_verification() - req_structures() - except: - print "Error checking ANNEX A conformance guidelines" - import traceback - traceback.print_exc() diff --git a/tests/avocado/acpi-bits/bits-tests/smilatency.py2 b/tests/avocado/acpi-bits/bits-tests/smilatency.py2 deleted file mode 100644 index 405af67e19..0000000000 --- a/tests/avocado/acpi-bits/bits-tests/smilatency.py2 +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (c) 2015, Intel Corporation -# All rights reserved. -# -# SPDX-License-Identifier: BSD-3-Clause - -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# * Neither the name of Intel Corporation nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. - -# This script runs only from the biosbits VM. - -"""SMI latency test.""" - -import bits -from collections import namedtuple -import testsuite -import time -import usb - -def register_tests(): - pass -# testsuite.add_test("SMI latency test", smi_latency); -# testsuite.add_test("SMI latency test with USB disabled via BIOS handoff", test_with_usb_disabled, runall=False); - -def smi_latency(): - MSR_SMI_COUNT = 0x34 - - print "Warning: touching the keyboard can affect the results of this test." - - tsc_per_sec = bits.tsc_per_sec() - tsc_per_usec = tsc_per_sec / (1000 * 1000) - bins = [long(tsc_per_usec * 10**i) for i in range(9)] - bin_descs = [ - "0 < t <= 1us", - "1us < t <= 10us", - "10us < t <= 100us", - "100us < t <= 1ms", - "1ms < t <= 10ms", - "10ms < t <= 100ms", - "100ms < t <= 1s ", - "1s < t <= 10s ", - "10s < t <= 100s ", - "100s < t ", - ] - - print "Starting test. Wait here, I will be back in 15 seconds." - (max_latency, smi_count_delta, bins) = bits.smi_latency(long(15 * tsc_per_sec), bins) - BinType = namedtuple('BinType', ("max", "total", "count", "times")) - bins = [BinType(*b) for b in bins] - - testsuite.test("SMI latency < 150us to minimize risk of OS timeouts", max_latency / tsc_per_usec <= 150) - if not testsuite.show_detail(): - return - - for bin, desc in zip(bins, bin_descs): - if bin.count == 0: - continue - testsuite.print_detail("{}; average = {}; count = {}".format(desc, bits.format_tsc(bin.total/bin.count), bin.count)) - deltas = (bits.format_tsc(t2 - t1) for t1,t2 in zip(bin.times, bin.times[1:])) - testsuite.print_detail(" Times between first few observations: {}".format(" ".join("{:>6}".format(delta) for delta in deltas))) - - if smi_count_delta is not None: - testsuite.print_detail("{} SMI detected using MSR_SMI_COUNT (MSR {:#x})".format(smi_count_delta, MSR_SMI_COUNT)) - - testsuite.print_detail("Summary of impact: observed maximum latency = {}".format(bits.format_tsc(max_latency))) - -def test_with_usb_disabled(): - if usb.handoff_to_os(): - smi_latency() - -def average_io_smi(port, value, count): - def f(): - tsc_start = bits.rdtsc() - bits.outb(port, value) - return bits.rdtsc() - tsc_start - counts = [f() for i in range(count)] - return sum(counts)/len(counts) - -def time_io_smi(port=0xb2, value=0, count=1000): - count_for_estimate = 10 - start = time.time() - average_io_smi(port, value, count_for_estimate) - avg10 = time.time() - start - estimate = avg10 * count/count_for_estimate - if estimate > 1: - print "Running test, estimated time: {}s".format(int(estimate)) - average = average_io_smi(port, value, count) - print "Average of {} SMIs (via outb, port={:#x}, value={:#x}): {}".format(count, port, value, bits.format_tsc(average)) diff --git a/tests/avocado/acpi-bits/bits-tests/testacpi.py2 b/tests/avocado/acpi-bits/bits-tests/testacpi.py2 deleted file mode 100644 index 7bf9075c1b..0000000000 --- a/tests/avocado/acpi-bits/bits-tests/testacpi.py2 +++ /dev/null @@ -1,287 +0,0 @@ -# Copyright (c) 2015, Intel Corporation -# All rights reserved. -# -# SPDX-License-Identifier: BSD-3-Clause -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# * Neither the name of Intel Corporation nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. - -# This script runs only from the biosbits VM. - -"""Tests for ACPI""" - -import acpi -import bits -import bits.mwait -import struct -import testutil -import testsuite -import time - -def register_tests(): - testsuite.add_test("ACPI _MAT (Multiple APIC Table Entry) under Processor objects", test_mat, submenu="ACPI Tests") -# testsuite.add_test("ACPI _PSS (Pstate) table conformance tests", test_pss, submenu="ACPI Tests") -# testsuite.add_test("ACPI _PSS (Pstate) runtime tests", test_pstates, submenu="ACPI Tests") - testsuite.add_test("ACPI DSDT (Differentiated System Description Table)", test_dsdt, submenu="ACPI Tests") - testsuite.add_test("ACPI FACP (Fixed ACPI Description Table)", test_facp, submenu="ACPI Tests") - testsuite.add_test("ACPI HPET (High Precision Event Timer Table)", test_hpet, submenu="ACPI Tests") - testsuite.add_test("ACPI MADT (Multiple APIC Description Table)", test_apic, submenu="ACPI Tests") - testsuite.add_test("ACPI MPST (Memory Power State Table)", test_mpst, submenu="ACPI Tests") - testsuite.add_test("ACPI RSDP (Root System Description Pointer Structure)", test_rsdp, submenu="ACPI Tests") - testsuite.add_test("ACPI XSDT (Extended System Description Table)", test_xsdt, submenu="ACPI Tests") - -def test_mat(): - cpupaths = acpi.get_cpupaths() - apic = acpi.parse_apic() - procid_apicid = apic.procid_apicid - uid_x2apicid = apic.uid_x2apicid - for cpupath in cpupaths: - # Find the ProcId defined by the processor object - processor = acpi.evaluate(cpupath) - # Find the UID defined by the processor object's _UID method - uid = acpi.evaluate(cpupath + "._UID") - mat_buffer = acpi.evaluate(cpupath + "._MAT") - if mat_buffer is None: - continue - # Process each _MAT subtable - mat = acpi._MAT(mat_buffer) - for index, subtable in enumerate(mat): - if subtable.subtype == acpi.MADT_TYPE_LOCAL_APIC: - if subtable.flags.bits.enabled: - testsuite.test("{} Processor declaration ProcId = _MAT ProcId".format(cpupath), processor.ProcId == subtable.proc_id) - testsuite.print_detail("{} ProcId ({:#02x}) != _MAT ProcId ({:#02x})".format(cpupath, processor.ProcId, subtable.proc_id)) - testsuite.print_detail("Processor Declaration: {}".format(processor)) - testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) - if testsuite.test("{} with local APIC in _MAT has local APIC in MADT".format(cpupath), processor.ProcId in procid_apicid): - testsuite.test("{} ApicId derived using Processor declaration ProcId = _MAT ApicId".format(cpupath), procid_apicid[processor.ProcId] == subtable.apic_id) - testsuite.print_detail("{} ApicId derived from MADT ({:#02x}) != _MAT ApicId ({:#02x})".format(cpupath, procid_apicid[processor.ProcId], subtable.apic_id)) - testsuite.print_detail("Processor Declaration: {}".format(processor)) - testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) - if subtable.subtype == acpi.MADT_TYPE_LOCAL_X2APIC: - if subtable.flags.bits.enabled: - if testsuite.test("{} with x2Apic in _MAT has _UID".format(cpupath), uid is not None): - testsuite.test("{}._UID = _MAT UID".format(cpupath), uid == subtable.uid) - testsuite.print_detail("{}._UID ({:#x}) != _MAT UID ({:#x})".format(cpupath, uid, subtable.uid)) - testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) - if testsuite.test("{} with _MAT x2Apic has x2Apic in MADT".format(cpupath), subtable.uid in uid_x2apicid): - testsuite.test("{} x2ApicId derived from MADT using UID = _MAT x2ApicId".format(cpupath), uid_x2apicid[subtable.uid] == subtable.x2apicid) - testsuite.print_detail("{} x2ApicId derived from MADT ({:#02x}) != _MAT x2ApicId ({:#02x})".format(cpupath, uid_x2apicid[subtable.uid], subtable.x2apicid)) - testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) - -def test_pss(): - uniques = acpi.parse_cpu_method("_PSS") - # We special-case None here to avoid a double-failure for CPUs without a _PSS - testsuite.test("_PSS must be identical for all CPUs", len(uniques) <= 1 or (len(uniques) == 2 and None in uniques)) - for pss, cpupaths in uniques.iteritems(): - if not testsuite.test("_PSS must exist", pss is not None): - testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) - testsuite.print_detail('No _PSS exists') - continue - - if not testsuite.test("_PSS must not be empty", pss.pstates): - testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) - testsuite.print_detail('_PSS is empty') - continue - - testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) - for index, pstate in enumerate(pss.pstates): - testsuite.print_detail("P[{}]: {}".format(index, pstate)) - - testsuite.test("_PSS must contain at most 16 Pstates", len(pss.pstates) <= 16) - testsuite.test("_PSS must have no duplicate Pstates", len(pss.pstates) == len(set(pss.pstates))) - - frequencies = [p.core_frequency for p in pss.pstates] - testsuite.test("_PSS must list Pstates in descending order of frequency", frequencies == sorted(frequencies, reverse=True)) - - testsuite.test("_PSS must have Pstates with no duplicate frequencies", len(frequencies) == len(set(frequencies))) - - dissipations = [p.power for p in pss.pstates] - testsuite.test("_PSS must list Pstates in descending order of power dissipation", dissipations == sorted(dissipations, reverse=True)) - -def test_pstates(): - """Execute and verify frequency for each Pstate in the _PSS""" - IA32_PERF_CTL = 0x199 - with bits.mwait.use_hint(), bits.preserve_msr(IA32_PERF_CTL): - cpupath_procid = acpi.find_procid() - cpupath_uid = acpi.find_uid() - apic = acpi.parse_apic() - procid_apicid = apic.procid_apicid - uid_x2apicid = apic.uid_x2apicid - def cpupath_apicid(cpupath): - if procid_apicid is not None: - procid = cpupath_procid.get(cpupath, None) - if procid is not None: - apicid = procid_apicid.get(procid, None) - if apicid is not None: - return apicid - if uid_x2apicid is not None: - uid = cpupath_uid.get(cpupath, None) - if uid is not None: - apicid = uid_x2apicid.get(uid, None) - if apicid is not None: - return apicid - return bits.cpus()[0] - - bclk = testutil.adjust_to_nearest(bits.bclk(), 100.0/12) * 1000000 - - uniques = acpi.parse_cpu_method("_PSS") - for pss, cpupaths in uniques.iteritems(): - if not testsuite.test("_PSS must exist", pss is not None): - testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) - testsuite.print_detail('No _PSS exists') - continue - - for n, pstate in enumerate(pss.pstates): - for cpupath in cpupaths: - apicid = cpupath_apicid(cpupath) - if apicid is None: - print 'Failed to find apicid for cpupath {}'.format(cpupath) - continue - bits.wrmsr(apicid, IA32_PERF_CTL, pstate.control) - - # Detecting Turbo frequency requires at least 2 pstates - # since turbo frequency = max non-turbo frequency + 1 - turbo = False - if len(pss.pstates) >= 2: - turbo = (n == 0 and pstate.core_frequency == (pss.pstates[1].core_frequency + 1)) - if turbo: - # Needs to busywait, not sleep - start = time.time() - while (time.time() - start < 2): - pass - - for duration in (0.1, 1.0): - frequency_data = bits.cpu_frequency(duration) - # Abort the test if no cpu frequency is not available - if frequency_data is None: - continue - aperf = frequency_data[1] - aperf = testutil.adjust_to_nearest(aperf, bclk/2) - aperf = int(aperf / 1000000) - if turbo: - if aperf >= pstate.core_frequency: - break - else: - if aperf == pstate.core_frequency: - break - - if turbo: - testsuite.test("P{}: Turbo measured frequency {} >= expected {} MHz".format(n, aperf, pstate.core_frequency), aperf >= pstate.core_frequency) - else: - testsuite.test("P{}: measured frequency {} MHz == expected {} MHz".format(n, aperf, pstate.core_frequency), aperf == pstate.core_frequency) - -def test_psd_thread_scope(): - uniques = acpi.parse_cpu_method("_PSD") - if not testsuite.test("_PSD (P-State Dependency) must exist for each processor", None not in uniques): - testsuite.print_detail(acpi.factor_commonprefix(uniques[None])) - testsuite.print_detail('No _PSD exists') - return - unique_num_dependencies = {} - unique_num_entries = {} - unique_revision = {} - unique_domain = {} - unique_coordination_type = {} - unique_num_processors = {} - for value, cpupaths in uniques.iteritems(): - unique_num_dependencies.setdefault(len(value.dependencies), []).extend(cpupaths) - unique_num_entries.setdefault(value.dependencies[0].num_entries, []).extend(cpupaths) - unique_revision.setdefault(value.dependencies[0].revision, []).extend(cpupaths) - unique_domain.setdefault(value.dependencies[0].domain, []).extend(cpupaths) - unique_coordination_type.setdefault(value.dependencies[0].coordination_type, []).extend(cpupaths) - unique_num_processors.setdefault(value.dependencies[0].num_processors, []).extend(cpupaths) - def detail(d, fmt): - for value, cpupaths in sorted(d.iteritems(), key=(lambda (k,v): v)): - testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) - testsuite.print_detail(fmt.format(value)) - - testsuite.test('Dependency count for each processor must be 1', unique_num_dependencies.keys() == [1]) - detail(unique_num_dependencies, 'Dependency count for each processor = {} (Expected 1)') - testsuite.test('_PSD.num_entries must be 5', unique_num_entries.keys() == [5]) - detail(unique_num_entries, 'num_entries = {} (Expected 5)') - testsuite.test('_PSD.revision must be 0', unique_revision.keys() == [0]) - detail(unique_revision, 'revision = {}') - testsuite.test('_PSD.coordination_type must be 0xFE (HW_ALL)', unique_coordination_type.keys() == [0xfe]) - detail(unique_coordination_type, 'coordination_type = {:#x} (Expected 0xFE HW_ALL)') - testsuite.test('_PSD.domain must be unique (thread-scoped) for each processor', len(unique_domain) == len(acpi.get_cpupaths())) - detail(unique_domain, 'domain = {:#x} (Expected a unique value for each processor)') - testsuite.test('_PSD.num_processors must be 1', unique_num_processors.keys() == [1]) - detail(unique_num_processors, 'num_processors = {} (Expected 1)') - -def test_table_checksum(data): - csum = sum(ord(c) for c in data) % 0x100 - testsuite.test('ACPI table cumulative checksum must equal 0', csum == 0) - testsuite.print_detail("Cumulative checksum = {} (Expected 0)".format(csum)) - -def test_apic(): - data = acpi.get_table("APIC") - if data is None: - return - test_table_checksum(data) - apic = acpi.parse_apic() - -def test_dsdt(): - data = acpi.get_table("DSDT") - if data is None: - return - test_table_checksum(data) - -def test_facp(): - data = acpi.get_table("FACP") - if data is None: - return - test_table_checksum(data) - facp = acpi.parse_facp() - -def test_hpet(): - data = acpi.get_table("HPET") - if data is None: - return - test_table_checksum(data) - hpet = acpi.parse_hpet() - -def test_mpst(): - data = acpi.get_table("MPST") - if data is None: - return - test_table_checksum(data) - mpst = acpi.MPST(data) - -def test_rsdp(): - data = acpi.get_table("RSD PTR ") - if data is None: - return - - # Checksum the first 20 bytes per ACPI 1.0 - csum = sum(ord(c) for c in data[:20]) % 0x100 - testsuite.test('ACPI 1.0 table first 20 bytes cumulative checksum must equal 0', csum == 0) - testsuite.print_detail("Cumulative checksum = {} (Expected 0)".format(csum)) - - test_table_checksum(data) - rsdp = acpi.parse_rsdp() - -def test_xsdt(): - data = acpi.get_table("XSDT") - if data is None: - return - test_table_checksum(data) - xsdt = acpi.parse_xsdt() diff --git a/tests/avocado/acpi-bits/bits-tests/testcpuid.py2 b/tests/avocado/acpi-bits/bits-tests/testcpuid.py2 deleted file mode 100644 index 7adefbe355..0000000000 --- a/tests/avocado/acpi-bits/bits-tests/testcpuid.py2 +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (c) 2012, Intel Corporation -# All rights reserved. -# -# SPDX-License-Identifier: BSD-3-Clause -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# * Neither the name of Intel Corporation nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. - -# This script runs only from the biosbits VM. - -"""Tests and helpers for CPUID.""" - -import bits -import testsuite -import testutil - -def cpuid_helper(function, index=None, shift=0, mask=~0, eax_mask=~0, ebx_mask=~0, ecx_mask=~0, edx_mask=~0): - if index is None: - index = 0 - indexdesc = "" - else: - indexdesc = " index {0:#x}".format(index) - - def find_mask(m): - if m == ~0: - return mask - return m - masks = map(find_mask, [eax_mask, ebx_mask, ecx_mask, edx_mask]) - - uniques = {} - for cpu in bits.cpus(): - regs = bits.cpuid_result(*[(r >> shift) & m for r, m in zip(bits.cpuid(cpu, function, index), masks)]) - uniques.setdefault(regs, []).append(cpu) - - desc = ["CPUID function {:#x}{}".format(function, indexdesc)] - - if shift != 0: - desc.append("Register values have been shifted by {}".format(shift)) - if mask != ~0 or eax_mask != ~0 or ebx_mask != ~0 or ecx_mask != ~0 or edx_mask != ~0: - desc.append("Register values have been masked:") - shifted_masks = bits.cpuid_result(*[m << shift for m in masks]) - desc.append("Masks: eax={eax:#010x} ebx={ebx:#010x} ecx={ecx:#010x} edx={edx:#010x}".format(**shifted_masks._asdict())) - - if len(uniques) > 1: - regvalues = zip(*uniques.iterkeys()) - common_masks = bits.cpuid_result(*map(testutil.find_common_mask, regvalues)) - common_values = bits.cpuid_result(*[v[0] & m for v, m in zip(regvalues, common_masks)]) - desc.append('Register values are not unique across all logical processors') - desc.append("Common bits: eax={eax:#010x} ebx={ebx:#010x} ecx={ecx:#010x} edx={edx:#010x}".format(**common_values._asdict())) - desc.append("Mask of common bits: {eax:#010x} {ebx:#010x} {ecx:#010x} {edx:#010x}".format(**common_masks._asdict())) - - for regs in sorted(uniques.iterkeys()): - cpus = uniques[regs] - desc.append("Register value: eax={eax:#010x} ebx={ebx:#010x} ecx={ecx:#010x} edx={edx:#010x}".format(**regs._asdict())) - desc.append("On {0} CPUs: {1}".format(len(cpus), testutil.apicid_list(cpus))) - - return uniques, desc - -def test_cpuid_consistency(text, function, index=None, shift=0, mask=~0, eax_mask=~0, ebx_mask=~0, ecx_mask=~0, edx_mask=~0): - uniques, desc = cpuid_helper(function, index, shift, mask, eax_mask, ebx_mask, ecx_mask, edx_mask) - desc[0] += " Consistency Check" - if text: - desc.insert(0, text) - status = testsuite.test(desc[0], len(uniques) == 1) - for line in desc[1:]: - testsuite.print_detail(line) - return status diff --git a/tests/functional/acpi-bits/bits-config/bits-cfg.txt b/tests/functional/acpi-bits/bits-config/bits-cfg.txt new file mode 100644 index 0000000000..8010804453 --- /dev/null +++ b/tests/functional/acpi-bits/bits-config/bits-cfg.txt @@ -0,0 +1,18 @@ +# BITS configuration file +[bits] + +# To run BITS in batch mode, set batch to a list of one or more of the +# following keywords; BITS will then run all of the requested operations, then +# save the log file to disk. +# +# test: Run the full BITS testsuite. +# acpi: Dump all ACPI structures. +# smbios: Dump all SMBIOS structures. +# +# Leave batch set to an empty string to disable batch mode. +# batch = + +# Uncomment the following to run all available batch operations +# please take a look at boot/python/init.py in bits zip file +# to see how these options are parsed and used. +batch = test acpi smbios diff --git a/tests/functional/acpi-bits/bits-tests/smbios.py2 b/tests/functional/acpi-bits/bits-tests/smbios.py2 new file mode 100644 index 0000000000..5868a7137a --- /dev/null +++ b/tests/functional/acpi-bits/bits-tests/smbios.py2 @@ -0,0 +1,2434 @@ +# Copyright (c) 2015, Intel Corporation +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. + +# This script runs only from the biosbits VM. + +"""SMBIOS/DMI module.""" + +import bits +import bitfields +import ctypes +import redirect +import struct +import uuid +import unpack +import ttypager +import sys + +class SMBIOS(unpack.Struct): + def __new__(cls): + if sys.platform == "BITS-EFI": + import efi + sm_ptr = efi.system_table.ConfigurationTableDict.get(efi.SMBIOS_TABLE_GUID) + else: + address = 0xF0000 + mem = bits.memory(0xF0000, 0x10000) + for offset in range(0, len(mem), 16): + signature = (ctypes.c_char * 4).from_address(address + offset).value + if signature == "_SM_": + entry_point_length = ctypes.c_ubyte.from_address(address + offset + 5).value + csum = sum(map(ord, mem[offset:offset + entry_point_length])) & 0xff + if csum == 0: + sm_ptr = address + offset + break + else: + return None + + if not sm_ptr: + return None + + sm = super(SMBIOS, cls).__new__(cls) + sm._header_memory = bits.memory(sm_ptr, 0x1f) + return sm + + def __init__(self): + super(SMBIOS, self).__init__() + u = unpack.Unpackable(self._header_memory) + self.add_field('header', Header(u)) + self._structure_memory = bits.memory(self.header.structure_table_address, self.header.structure_table_length) + u = unpack.Unpackable(self._structure_memory) + self.add_field('structures', unpack.unpack_all(u, _smbios_structures, self), unpack.format_each("\n\n{!r}")) + + def structure_type(self, num): + '''Dumps structure of given Type if present''' + try: + types_present = [self.structures[x].smbios_structure_type for x in range(len(self.structures))] + matrix = dict() + for index in range(len(types_present)): + if types_present.count(types_present[index]) == 1: + matrix[types_present[index]] = self.structures[index] + else: # if multiple structures of the same type, return a list of structures for the type number + if matrix.has_key(types_present[index]): + matrix[types_present[index]].append(self.structures[index]) + else: + matrix[types_present[index]] = [self.structures[index]] + return matrix[num] + except: + print "Failure: Type {} - not found".format(num) + +class Header(unpack.Struct): + def __new__(cls, u): + return super(Header, cls).__new__(cls) + + def __init__(self, u): + super(Header, self).__init__() + self.raw_data = u.unpack_rest() + u = unpack.Unpackable(self.raw_data) + self.add_field('anchor_string', u.unpack_one("4s")) + self.add_field('checksum', u.unpack_one("B")) + self.add_field('length', u.unpack_one("B")) + self.add_field('major_version', u.unpack_one("B")) + self.add_field('minor_version', u.unpack_one("B")) + self.add_field('max_structure_size', u.unpack_one(" len(self.strings): + return "(error: string index out of range)" + return self.strings[i - 1] + +class BIOSInformation(SmbiosBaseStructure): + smbios_structure_type = 0 + + def __init__(self, u, sm): + super(BIOSInformation, self).__init__(u, sm) + u = self.u + try: + self.add_field('vendor', u.unpack_one("B"), self.fmtstr) + self.add_field('version', u.unpack_one("B"), self.fmtstr) + self.add_field('starting_address_segment', u.unpack_one("= (2,"4"): + characteristic_bytes = 2 + else: + characteristic_bytes = self.length - 0x12 + self.add_field('characteristics_extensions', [u.unpack_one("B") for b in range(characteristic_bytes)]) + if (sm.header.major_version, minor_version_str) >= (2,"4"): + self.add_field('major_release', u.unpack_one("B")) + self.add_field('minor_release', u.unpack_one("B")) + self.add_field('ec_major_release', u.unpack_one("B")) + self.add_field('ec_minor_release', u.unpack_one("B")) + except: + self.decode_failure = True + print "Error parsing BIOSInformation" + import traceback + traceback.print_exc() + self.fini() + +class SystemInformation(SmbiosBaseStructure): + smbios_structure_type = 1 + + def __init__(self, u, sm): + super(SystemInformation, self).__init__(u, sm) + u = self.u + try: + self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) + self.add_field('product_name', u.unpack_one("B"), self.fmtstr) + self.add_field('version', u.unpack_one("B"), self.fmtstr) + self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0x8: + self.add_field('uuid', uuid.UUID(bytes_le=u.unpack_one("16s"))) + wakeup_types = { + 0: 'Reserved', + 1: 'Other', + 2: 'Unknown', + 3: 'APM Timer', + 4: 'Modem Ring', + 5: 'LAN Remote', + 6: 'Power Switch', + 7: 'PCI PME#', + 8: 'AC Power Restored' + } + self.add_field('wakeup_type', u.unpack_one("B"), unpack.format_table("{}", wakeup_types)) + if self.length > 0x19: + self.add_field('sku_number', u.unpack_one("B"), self.fmtstr) + self.add_field('family', u.unpack_one("B"), self.fmtstr) + except: + self.decode_failure = True + print "Error parsing SystemInformation" + import traceback + traceback.print_exc() + self.fini() + +_board_types = { + 1: 'Unknown', + 2: 'Other', + 3: 'Server Blade', + 4: 'Connectivity Switch', + 5: 'System Management Module', + 6: 'Processor Module', + 7: 'I/O Module', + 8: 'Memory Module', + 9: 'Daughter Board', + 0xA: 'Motherboard', + 0xB: 'Processor/Memory Module', + 0xC: 'Processor/IO Module', + 0xD: 'Interconnect Board' +} + +class BaseboardInformation(SmbiosBaseStructure): + smbios_structure_type = 2 + + def __init__(self, u, sm): + super(BaseboardInformation, self).__init__(u, sm) + u = self.u + try: + self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) + self.add_field('product', u.unpack_one("B"), self.fmtstr) + self.add_field('version', u.unpack_one("B"), self.fmtstr) + self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) + + if self.length > 0x8: + self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr) + + if self.length > 0x9: + self.add_field('feature_flags', u.unpack_one("B")) + self.add_field('hosting_board', bool(bitfields.getbits(self.feature_flags, 0)), "feature_flags[0]={}") + self.add_field('requires_daughter_card', bool(bitfields.getbits(self.feature_flags, 1)), "feature_flags[1]={}") + self.add_field('removable', bool(bitfields.getbits(self.feature_flags, 2)), "feature_flags[2]={}") + self.add_field('replaceable', bool(bitfields.getbits(self.feature_flags, 3)), "feature_flags[3]={}") + self.add_field('hot_swappable', bool(bitfields.getbits(self.feature_flags, 4)), "feature_flags[4]={}") + + if self.length > 0xA: + self.add_field('location', u.unpack_one("B"), self.fmtstr) + + if self.length > 0xB: + self.add_field('chassis_handle', u.unpack_one(" 0xD: + self.add_field('board_type', u.unpack_one("B"), unpack.format_table("{}", _board_types)) + + if self.length > 0xE: + self.add_field('handle_count', u.unpack_one("B")) + if self.handle_count > 0: + self.add_field('contained_object_handles', tuple(u.unpack_one(" 9: + chassis_states = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Safe', + 0x04: 'Warning', + 0x05: 'Critical', + 0x06: 'Non-recoverable', + } + self.add_field('bootup_state', u.unpack_one("B"), unpack.format_table("{}", chassis_states)) + self.add_field('power_supply_state', u.unpack_one("B"), unpack.format_table("{}", chassis_states)) + self.add_field('thermal_state', u.unpack_one("B"), unpack.format_table("{}", chassis_states)) + security_states = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'None', + 0x04: 'External interface locked out', + 0x05: 'External interface enabled', + } + self.add_field('security_status', u.unpack_one("B"), unpack.format_table("{}", security_states)) + if self.length > 0xd: + self.add_field('oem_defined', u.unpack_one(" 0x11: + self.add_field('height', u.unpack_one("B")) + self.add_field('num_power_cords', u.unpack_one("B")) + self.add_field('contained_element_count', u.unpack_one("B")) + self.add_field('contained_element_length', u.unpack_one("B")) + if getattr(self, 'contained_element_count', 0): + self.add_field('contained_elements', tuple(SystemEnclosureContainedElement(u, self.contained_element_length) for i in range(self.contained_element_count))) + if self.length > (0x15 + (getattr(self, 'contained_element_count', 0) * getattr(self, 'contained_element_length', 0))): + self.add_field('sku_number', u.unpack_one("B"), self.fmtstr) + except: + self.decode_failure = True + print "Error parsing SystemEnclosure" + import traceback + traceback.print_exc() + self.fini() + +class SystemEnclosureContainedElement(unpack.Struct): + def __init__(self, u, length): + super(SystemEnclosureContainedElement, self).__init__() + self.start_offset = u.offset + self.raw_data = u.unpack_raw(length) + self.u = unpack.Unpackable(self.raw_data) + u = self.u + self.add_field('contained_element_type', u.unpack_one("B")) + type_selections = { + 0: 'SMBIOS baseboard type enumeration', + 1: 'SMBIOS structure type enumeration', + } + self.add_field('type_select', bitfields.getbits(self.contained_element_type, 7), unpack.format_table("contained_element_type[7]={}", type_selections)) + self.add_field('type', bitfields.getbits(self.contained_element_type, 6, 0)) + if self.type_select == 0: + self.add_field('smbios_board_type', self.type, unpack.format_table("{}", _board_types)) + else: + self.add_field('smbios_structure_type', self.type) + self.add_field('minimum', u.unpack_one("B")) + self.add_field('maximum', u.unpack_one("B")) + if not u.at_end(): + self.add_field('data', u.unpack_rest()) + del self.u + +class ProcessorInformation(SmbiosBaseStructure): + smbios_structure_type = 4 + + def __init__(self, u, sm): + super(ProcessorInformation, self).__init__(u, sm) + u = self.u + try: + self.add_field('socket_designation', u.unpack_one("B"), self.fmtstr) + processor_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Central Processor', + 0x04: 'Math Processor', + 0x05: 'DSP Processor', + 0x06: 'Video Processor', + } + self.add_field('processor_type', u.unpack_one("B"), unpack.format_table("{}", processor_types)) + self.add_field('processor_family', u.unpack_one("B")) + self.add_field('processor_manufacturer', u.unpack_one("B"), self.fmtstr) + self.add_field('processor_id', u.unpack_one(" 0x1A: + self.add_field('l1_cache_handle', u.unpack_one(" 0x20: + self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) + self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr) + self.add_field('part_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0x24: + self.add_field('core_count', u.unpack_one("B")) + self.add_field('core_enabled', u.unpack_one("B")) + self.add_field('thread_count', u.unpack_one("B")) + self.add_field('processor_characteristics', u.unpack_one(" 0x28: + self.add_field('processor_family_2', u.unpack_one(" 0x2A: + self.add_field('core_count2', u.unpack_one(" 0x0F: + self.add_field('cache_speed', u.unpack_one("B")) + if self.length > 0x10: + _error_correction = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'None', + 0x04: 'Parity', + 0x05: 'Single-bit ECC', + 0x06: 'Multi-bit ECC' + } + self.add_field('error_correction', u.unpack_one("B"), unpack.format_table("{}", _error_correction)) + if self.length > 0x10: + _system_cache_type = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Instruction', + 0x04: 'Data', + 0x05: 'Unified' + } + self.add_field('system_cache_type', u.unpack_one("B"), unpack.format_table("{}", _system_cache_type)) + if self.length > 0x12: + _associativity = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Direct Mapped', + 0x04: '2-way Set-Associative', + 0x05: '4-way Set-Associative', + 0x06: 'Fully Associative', + 0x07: '8-way Set-Associative', + 0x08: '16-way Set-Associative', + 0x09: '12-way Set-Associative', + 0x0A: '24-way Set-Associative', + 0x0B: '32-way Set-Associative', + 0x0C: '48-way Set-Associative', + 0x0D: '64-way Set-Associative', + 0x0E: '20-way Set-Associative' + } + self.add_field('associativity', u.unpack_one("B"), unpack.format_table("{}", _associativity)) + + except: + self.decode_failure = True + print "Error parsing CacheInformation" + import traceback + traceback.print_exc() + self.fini() + +class PortConnectorInfo(SmbiosBaseStructure): + smbios_structure_type = 8 + + def __init__(self, u, sm): + super(PortConnectorInfo, self).__init__(u, sm) + u = self.u + try: + self.add_field('internal_reference_designator', u.unpack_one("B"), self.fmtstr) + connector_types = { + 0x00: 'None', + 0x01: 'Centronics', + 0x02: 'Mini Centronics', + 0x03: 'Proprietary', + 0x04: 'DB-25 pin male', + 0x05: 'DB-25 pin female', + 0x06: 'DB-15 pin male', + 0x07: 'DB-15 pin female', + 0x08: 'DB-9 pin male', + 0x09: 'DB-9 pin female', + 0x0A: 'RJ-11', + 0x0B: 'RJ-45', + 0x0C: '50-pin MiniSCSI', + 0x0D: 'Mini-DIN', + 0x0E: 'Micro-DIN', + 0x0F: 'PS/2', + 0x10: 'Infrared', + 0x11: 'HP-HIL', + 0x12: 'Access Bus (USB)', + 0x13: 'SSA SCSI', + 0x14: 'Circular DIN-8 male', + 0x15: 'Circular DIN-8 female', + 0x16: 'On Board IDE', + 0x17: 'On Board Floppy', + 0x18: '9-pin Dual Inline (pin 10 cut)', + 0x19: '25-pin Dual Inline (pin 26 cut)', + 0x1A: '50-pin Dual Inline', + 0x1B: '68-pin Dual Inline', + 0x1C: 'On Board Sound Input from CD-ROM', + 0x1D: 'Mini-Centronics Type-14', + 0x1E: 'Mini-Centronics Type-26', + 0x1F: 'Mini-jack (headphones)', + 0x20: 'BNC', + 0x21: '1394', + 0x22: 'SAS/SATA Plug Receptacle', + 0xA0: 'PC-98', + 0xA1: 'PC-98Hireso', + 0xA2: 'PC-H98', + 0xA3: 'PC-98Note', + 0xA4: 'PC-98Full', + 0xFF: 'Other', + } + self.add_field('internal_connector_type', u.unpack_one("B"), unpack.format_table("{}", connector_types)) + self.add_field('external_reference_designator', u.unpack_one("B"), self.fmtstr) + self.add_field('external_connector_type', u.unpack_one("B"), unpack.format_table("{}", connector_types)) + port_types = { + 0x00: 'None', + 0x01: 'Parallel Port XT/AT Compatible', + 0x02: 'Parallel Port PS/2', + 0x03: 'Parallel Port ECP', + 0x04: 'Parallel Port EPP', + 0x05: 'Parallel Port ECP/EPP', + 0x06: 'Serial Port XT/AT Compatible', + 0x07: 'Serial Port 16450 Compatible', + 0x08: 'Serial Port 16550 Compatible', + 0x09: 'Serial Port 16550A Compatible', + 0x0A: 'SCSI Port', + 0x0B: 'MIDI Port', + 0x0C: 'Joy Stick Port', + 0x0D: 'Keyboard Port', + 0x0E: 'Mouse Port', + 0x0F: 'SSA SCSI', + 0x10: 'USB', + 0x11: 'FireWire (IEEE P1394)', + 0x12: 'PCMCIA Type I2', + 0x13: 'PCMCIA Type II', + 0x14: 'PCMCIA Type III', + 0x15: 'Cardbus', + 0x16: 'Access Bus Port', + 0x17: 'SCSI II', + 0x18: 'SCSI Wide', + 0x19: 'PC-98', + 0x1A: 'PC-98-Hireso', + 0x1B: 'PC-H98', + 0x1C: 'Video Port', + 0x1D: 'Audio Port', + 0x1E: 'Modem Port', + 0x1F: 'Network Port', + 0x20: 'SATA', + 0x21: 'SAS', + 0xA0: '8251 Compatible', + 0xA1: '8251 FIFO Compatible', + 0xFF: 'Other', + } + self.add_field('port_type', u.unpack_one("B"), unpack.format_table("{}", port_types)) + except: + self.decodeFailure = True + print "Error parsing PortConnectorInfo" + import traceback + traceback.print_exc() + self.fini() + +class SystemSlots(SmbiosBaseStructure): + smbios_structure_type = 9 + + def __init__(self, u, sm): + super(SystemSlots, self).__init__(u, sm) + u = self.u + try: + self.add_field('designation', u.unpack_one("B"), self.fmtstr) + _slot_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'ISA', + 0x04: 'MCA', + 0x05: 'EISA', + 0x06: 'PCI', + 0x07: 'PC Card (PCMCIA)', + 0x08: 'VL-VESA', + 0x09: 'Proprietary', + 0x0A: 'Processor Card Slot', + 0x0B: 'Proprietary Memory Card Slot', + 0x0C: 'I/O Riser Card Slot', + 0x0D: 'NuBus', + 0x0E: 'PCI 66MHz Capable', + 0x0F: 'AGP', + 0x10: 'AGP 2X', + 0x11: 'AGP 4X', + 0x12: 'PCI-X', + 0x13: 'AGP 8X', + 0xA0: 'PC-98/C20', + 0xA1: 'PC-98/C24', + 0xA2: 'PC-98/E', + 0xA3: 'PC-98/Local Bus', + 0xA4: 'PC-98/Card', + 0xA5: 'PCI Express', + 0xA6: 'PCI Express x1', + 0xA7: 'PCI Express x2', + 0xA8: 'PCI Express x4', + 0xA9: 'PCI Express x8', + 0xAA: 'PCI Express x16', + 0xAB: 'PCI Express Gen 2', + 0xAC: 'PCI Express Gen 2 x1', + 0xAD: 'PCI Express Gen 2 x2', + 0xAE: 'PCI Express Gen 2 x4', + 0xAF: 'PCI Express Gen 2 x8', + 0xB0: 'PCI Express Gen 2 x16', + 0xB1: 'PCI Express Gen 3', + 0xB2: 'PCI Express Gen 3 x1', + 0xB3: 'PCI Express Gen 3 x2', + 0xB4: 'PCI Express Gen 3 x4', + 0xB5: 'PCI Express Gen 3 x8', + 0xB6: 'PCI Express Gen 3 x16', + } + self.add_field('slot_type', u.unpack_one("B"), unpack.format_table("{}", _slot_types)) + _slot_data_bus_widths = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: '8 bit', + 0x04: '16 bit', + 0x05: '32 bit', + 0x06: '64 bit', + 0x07: '128 bit', + 0x08: '1x or x1', + 0x09: '2x or x2', + 0x0A: '4x or x4', + 0x0B: '8x or x8', + 0x0C: '12x or x12', + 0x0D: '16x or x16', + 0x0E: '32x or x32', + } + self.add_field('slot_data_bus_width', u.unpack_one('B'), unpack.format_table("{}", _slot_data_bus_widths)) + _current_usages = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Available', + 0x04: 'In use', + } + self.add_field('current_usage', u.unpack_one('B'), unpack.format_table("{}", _current_usages)) + _slot_lengths = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Short Length', + 0x04: 'Long Length', + } + self.add_field('slot_length', u.unpack_one('B'), unpack.format_table("{}", _slot_lengths)) + self.add_field('slot_id', u.unpack_one(' 0x0C: + self.add_field('characteristics2', u.unpack_one('B')) + self.add_field('supports_PME', bool(bitfields.getbits(self.characteristics2, 0)), "characteristics2[0]={}") + self.add_field('supports_hot_plug', bool(bitfields.getbits(self.characteristics2, 1)), "characteristics2[1]={}") + self.add_field('supports_smbus', bool(bitfields.getbits(self.characteristics2, 2)), "characteristics2[2]={}") + if self.length > 0x0D: + self.add_field('segment_group_number', u.unpack_one(' 0x05: + self.add_field('flags', u.unpack_one('B')) + self.add_field('abbreviated_format', bool(bitfields.getbits(self.flags, 0)), "flags[0]={}") + if self.length > 0x6: + u.skip(15) + self.add_field('current_language', u.unpack_one('B'), self.fmtstr) + except: + self.decodeFailure = True + print "Error parsing BIOSLanguageInformation" + import traceback + traceback.print_exc() + self.fini() + +class GroupAssociations(SmbiosBaseStructure): + smbios_structure_type = 14 + + def __init__(self, u, sm): + super(GroupAssociations, self).__init__(u, sm) + u = self.u + try: + self.add_field('group_name', u.unpack_one("B"), self.fmtstr) + self.add_field('item_type', u.unpack_one('B')) + self.add_field('item_handle', u.unpack_one(' 0x14: + _log_header_formats = { + 0: 'No header', + 1: 'Type 1 log header', + xrange(2, 0x7f): 'Available for future assignment', + xrange(0x80, 0xff): 'BIOS vendor or OEM-specific format' + } + self.add_field('log_header_format', u.unpack_one("B"), unpack.format_table("{}", _log_header_formats)) + if self.length > 0x15: + self.add_field('num_supported_log_type_descriptors', u.unpack_one('B')) + if self.length > 0x16: + self.add_field('length_log_type_descriptor', u.unpack_one('B')) + if self.length != (0x17 + (self.num_supported_log_type_descriptors * self.length_log_type_descriptor)): + print "Error: structure length ({}) != 0x17 + (num_supported_log_type_descriptors ({}) * length_log_type_descriptor({}))".format(self.length, self.num_supported_log_type_descriptors, self.length_log_type_descriptor) + print "structure length = {}".format(self.length) + print "num_supported_log_type_descriptors = {}".format(self.num_supported_log_type_descriptors) + print "length_log_type_descriptor = {}".format(self.length_log_type_descriptor) + self.decodeFailure = True + self.add_field('descriptors', tuple(EventLogDescriptor.unpack(u) for i in range(self.num_supported_log_type_descriptors)), unpack.format_each("\n{!r}")) + except: + self.decodeFailure = True + print "Error parsing SystemEventLog" + import traceback + traceback.print_exc() + self.fini() + +class EventLogDescriptor(unpack.Struct): + @staticmethod + def _unpack(u): + _event_log_type_descriptors = { + 0x00: 'Reserved', + 0x01: 'Single-bit ECC memory error', + 0x02: 'Multi-bit ECC memory error', + 0x03: 'Parity memory error', + 0x04: 'Bus time-out', + 0x05: 'I/O Channel Check', + 0x06: 'Software NMI', + 0x07: 'POST Memory Resize', + 0x08: 'POST Error', + 0x09: 'PCI Parity Error', + 0x0A: 'PCI System Error', + 0x0B: 'CPU Failure', + 0x0C: 'EISA FailSafe Timer time-out', + 0x0D: 'Correctable memory log disabled', + 0x0E: 'Logging disabled for a specific Event Type - too many errors of the same type received in a short amount of time', + 0x0F: 'Reserved', + 0x10: 'System Limit Exceeded', + 0x11: 'Asynchronous hardware timer expired and issued a system reset', + 0x12: 'System configuration information', + 0x13: 'Hard-disk information', + 0x14: 'System reconfigured', + 0x15: 'Uncorrectable CPU-complex error', + 0x16: 'Log Area Reset/Cleared', + 0x17: 'System boot', + xrange(0x18, 0x7F): 'Unused, available for assignment', + xrange(0x80, 0xFE): 'Available for system- and OEM-specific assignments', + 0xFF: 'End of log' + } + yield 'log_type', u.unpack_one('B'), unpack.format_table("{}", _event_log_type_descriptors) + _event_log_format = { + 0x00: 'None', + 0x01: 'Handle', + 0x02: 'Multiple-Event', + 0x03: 'Multiple-Event Handle', + 0x04: 'POST Results Bitmap', + 0x05: 'System Management Type', + 0x06: 'Multiple-Event System Management Type', + xrange(0x80, 0xFF): 'OEM assigned' + } + yield 'variable_data_format_type', u.unpack_one('B'), unpack.format_table("{}", _event_log_format) + +class PhysicalMemoryArray(SmbiosBaseStructure): + smbios_structure_type = 16 + + def __init__(self, u, sm): + super(PhysicalMemoryArray, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + _location_field = { + 0x01: "Other", + 0x02: "Unknown", + 0x03: "System board or motherboard", + 0x04: "ISA add-on card", + 0x05: "EISA add-on card", + 0x06: "PCI add-on card", + 0x07: "MCA add-on card", + 0x08: "PCMCIA add-on card", + 0x09: "Proprietary add-on card", + 0x0A: "NuBus", + 0xA0: "PC-98/C20 add-on card", + 0xA1: "PC-98/C24 add-on card", + 0xA2: "PC-98/E add-on card", + 0xA3: "PC-98/Local bus add-on card" + } + self.add_field('location', u.unpack_one("B"), unpack.format_table("{}", _location_field)) + if self.length > 0x05: + _use = { + 0x01: "Other", + 0x02: "Unknown", + 0x03: "System memory", + 0x04: "Video memory", + 0x05: "Flash memory", + 0x06: "Non-volatile RAM", + 0x07: "Cache memory" + } + self.add_field('use', u.unpack_one('B'), unpack.format_table("{}", _use)) + if self.length > 0x06: + _error_correction = { + 0x01: "Other", + 0x02: "Unknown", + 0x03: "None", + 0x04: "Parity", + 0x05: "Single-bit ECC", + 0x06: "Multi-bit ECC", + 0x07: "CRC" + } + self.add_field('memory_error_correction', u.unpack_one('B'), unpack.format_table("{}", _error_correction)) + if self.length > 0x07: + self.add_field('maximum_capacity', u.unpack_one(' 0x0B: + self.add_field('memory_error_information_handle', u.unpack_one(' 0x0D: + self.add_field('num_memory_devices', u.unpack_one(' 0x0F: + self.add_field('extended_maximum_capacity', u.unpack_one(' 0x4: + self.add_field('physical_memory_array_handle', u.unpack_one(" 0x6: + self.add_field('memory_error_information_handle', u.unpack_one(" 0x8: + self.add_field('total_width', u.unpack_one(" 0xA: + self.add_field('data_width', u.unpack_one(" 0xC: + self.add_field('size', u.unpack_one(" 0xE: + _form_factors = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'SIMM', + 0x04: 'SIP', + 0x05: 'Chip', + 0x06: 'DIP', + 0x07: 'ZIP', + 0x08: 'Proprietary Card', + 0x09: 'DIMM', + 0x0A: 'TSOP', + 0x0B: 'Row of chips', + 0x0C: 'RIMM', + 0x0D: 'SODIMM', + 0x0E: 'SRIMM', + 0x0F: 'FB-DIMM' + } + self.add_field('form_factor', u.unpack_one("B"), unpack.format_table("{}", _form_factors)) + if self.length > 0xF: + self.add_field('device_set', u.unpack_one("B")) + if self.length > 0x10: + self.add_field('device_locator', u.unpack_one("B"), self.fmtstr) + if self.length > 0x11: + self.add_field('bank_locator', u.unpack_one("B"), self.fmtstr) + if self.length > 0x12: + _memory_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'DRAM', + 0x04: 'EDRAM', + 0x05: 'VRAM', + 0x06: 'SRAM', + 0x07: 'RAM', + 0x08: 'ROM', + 0x09: 'FLASH', + 0x0A: 'EEPROM', + 0x0B: 'FEPROM', + 0x0C: 'EPROM', + 0x0D: 'CDRAM', + 0x0E: '3DRAM', + 0x0F: 'SDRAM', + 0x10: 'SGRAM', + 0x11: 'RDRAM', + 0x12: 'DDR', + 0x13: 'DDR2', + 0x14: 'DDR2 FB-DIMM', + xrange(0x15, 0x17): 'Reserved', + 0x18: 'DDR3', + 0x19: 'FBD2' + } + self.add_field('memory_type', u.unpack_one("B"), unpack.format_table("{}", _memory_types)) + if self.length > 0x13: + self.add_field('type_detail', u.unpack_one(' 0x15: + self.add_field('speed', u.unpack_one(" 0x17: + self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) + if self.length > 0x18: + self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0x19: + self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr) + if self.length > 0x1A: + self.add_field('part_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0x1B: + self.add_field('attributes', u.unpack_one("B")) + self.add_field('rank', bitfields.getbits(self.attributes, 3, 0), "attributes[3:0]={}") + if self.length > 0x1C: + if self.size == 0x7FFF: + self.add_field('extended_size', u.unpack_one(' 0x20: + self.add_field('configured_memory_clock_speed', u.unpack_one(" 0x22: + self.add_field('minimum_voltage', u.unpack_one(" 0x24: + self.add_field('maximum_voltage', u.unpack_one(" 0x26: + self.add_field('configured_voltage', u.unpack_one(" 0x4: + _error_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'OK', + 0x04: 'Bad read', + 0x05: 'Parity error', + 0x06: 'Single-bit error', + 0x07: 'Double-bit error', + 0x08: 'Multi-bit error', + 0x09: 'Nibble error', + 0x0A: 'Checksum error', + 0x0B: 'CRC error', + 0x0C: 'Corrected single-bit error', + 0x0D: 'Corrected error', + 0x0E: 'Uncorrectable error' + } + self.add_field('error_type', u.unpack_one("B"), unpack.format_table("{}", _error_types)) + if self.length > 0x5: + _error_granularity_field = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Device level', + 0x04: 'Memory partition level' + } + self.add_field('error_granularity', u.unpack_one("B"), unpack.format_table("{}", _error_granularity_field)) + if self.length > 0x6: + _error_operation_field = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Read', + 0x04: 'Write', + 0x05: 'Partial write' + } + self.add_field('error_operation', u.unpack_one("B"), unpack.format_table("{}", _error_operation_field)) + if self.length > 0x7: + self.add_field('vendor_syndrome', u.unpack_one(" 0xB: + self.add_field('memory_array_error_address', u.unpack_one(" 0xF: + self.add_field('device_error_address', u.unpack_one(" 0x13: + self.add_field('error_resolution', u.unpack_one(" 0x4: + self.add_field('starting_address', u.unpack_one(" 0x8: + self.add_field('ending_address', u.unpack_one(" 0xC: + self.add_field('memory_array_handle', u.unpack_one(" 0xE: + self.add_field('partition_width', u.unpack_one("B")) + if self.length > 0xF: + # valid if starting_address = FFFF FFFF + if self.starting_address == 0xFFFFFFFF: + self.add_field('extended_starting_address', u.unpack_one(" 0x17: + self.add_field('extended_ending_address', u.unpack_one(" 0x4: + self.add_field('starting_address', u.unpack_one(" 0x8: + self.add_field('ending_address', u.unpack_one(" 0xC: + self.add_field('memory_device_handle', u.unpack_one(" 0xE: + self.add_field('memory_array_mapped_address_handle', u.unpack_one(" 0x10: + self.add_field('partition_row_position', u.unpack_one("B")) + if self.length > 0x11: + self.add_field('interleave_position', u.unpack_one("B")) + if self.length > 0x12: + self.add_field('interleave_data_depth', u.unpack_one("B")) + if self.length > 0x13: + # valid if starting_address = FFFF FFFF + if self.starting_address == 0xFFFFFFFF: + self.add_field('extended_starting_address', u.unpack_one(" 0x1B: + self.add_field('extended_ending_address', u.unpack_one(" 0x4: + _pointing_device_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Mouse', + 0x04: 'Track Ball', + 0x05: 'Track Point', + 0x06: 'Glide Point', + 0x07: 'Touch Pad', + 0x08: 'Touch Screen', + 0x09: 'Optical Sensor' + } + self.add_field('pointing_device_type', u.unpack_one("B"), unpack.format_table("{}", _pointing_device_types)) + if self.length > 0x5: + _interfaces = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Serial', + 0x04: 'PS/2', + 0x05: 'Infared', + 0x06: 'HP-HIL', + 0x07: 'Bus mouse', + 0x08: 'ADB (Apple Desktop Bus)', + 0x09: 'Bus mouse DB-9', + 0x0A: 'Bus mouse micro-DIN', + 0x0B: 'USB' + } + self.add_field('interface', u.unpack_one("B"), unpack.format_table("{}", _interfaces)) + if self.length > 0x6: + self.add_field('num_buttons', u.unpack_one("B")) + except: + self.decodeFailure = True + print "Error parsing BuiltInPointingDevice" + import traceback + traceback.print_exc() + self.fini() + +class PortableBattery(SmbiosBaseStructure): + smbios_structure_type = 22 + + def __init__(self, u, sm): + super(PortableBattery, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + self.add_field('location', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) + if self.length > 0x6: + self.add_field('manufacturer_date', u.unpack_one("B"), self.fmtstr) + if self.length > 0x7: + self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0x8: + self.add_field('device_name', u.unpack_one("B"), self.fmtstr) + if self.length > 0x9: + _device_chemistry = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Lead Acid', + 0x04: 'Nickel Cadmium', + 0x05: 'Nickel metal hydride', + 0x06: 'Lithium-ion', + 0x07: 'Zinc air', + 0x08: 'Lithium Polymer' + } + self.add_field('device_chemistry', u.unpack_one("B"), unpack.format_table("{}", _device_chemistry)) + if self.length > 0xA: + self.add_field('design_capacity', u.unpack_one(" 0xC: + self.add_field('design_voltage', u.unpack_one(" 0xE: + self.add_field('sbds_version_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0xF: + self.add_field('max_error_battery_data', u.unpack_one("B"), self.fmtstr) + if self.length > 0x10: + if self.serial_number == 0: + self.add_field('sbds_serial_number', u.unpack_one(" 0x12: + if self.manufacturer_date == 0: + self.add_field('sbds_manufacture_date', u.unpack_one(" 0x14: + if self.device_chemistry == 0x02: + self.add_field('sbds_device_chemistry', u.unpack_one("B"), self.fmtstr) + else: + u.skip(1) + if self.length > 0x15: + self.add_field('design_capacity_multiplier', u.unpack_one("B")) + if self.length > 0x16: + self.add_field('oem_specific', u.unpack_one(" 0x4: + self.add_field('capabilities', u.unpack_one("B")) + self.add_field('contains_watchdog_timer', bool(bitfields.getbits(self.capabilities, 5)), "capabilities[5]={}") + _boot_option = { + 0b00: 'Reserved, do not use', + 0b01: 'Operating System', + 0b10: 'System utilities', + 0b11: 'Do not reboot' + } + self.add_field('boot_option_on_limit', bitfields.getbits(self.capabilities, 4, 3), unpack.format_table("capabilities[4:3]={}", _boot_option)) + self.add_field('boot_option_after_watchdog_reset', bitfields.getbits(self.capabilities, 2, 1), unpack.format_table("capabilities[2:1]={}", _boot_option)) + self.add_field('system_reset_enabled_by_user', bool(bitfields.getbits(self.capabilities, 0)), "capabilities[0]={}") + if self.length > 0x5: + self.add_field('reset_count', u.unpack_one(" 0x5: + self.add_field('reset_limit', u.unpack_one(" 0x9: + self.add_field('timer_interval', u.unpack_one(" 0xB: + self.add_field('timeout', u.unpack_one(" 0x4: + self.add_field('hardware_security_settings', u.unpack_one("B")) + _status = { + 0x00: 'Disabled', + 0x01: 'Enabled', + 0x02: 'Not Implemented', + 0x03: 'Unknown' + } + self.add_field('power_on_password_status', bitfields.getbits(self.hardware_security_settings, 7, 6), unpack.format_table("hardware_security_settings[7:6]={}", _status)) + self.add_field('keyboard_password_status', bitfields.getbits(self.hardware_security_settings, 5, 4), unpack.format_table("hardware_security_settings[5:4]={}", _status)) + self.add_field('admin_password_status', bitfields.getbits(self.hardware_security_settings, 3, 2), unpack.format_table("hardware_security_settings0[3:2]={}", _status)) + self.add_field('front_panel_reset_status', bitfields.getbits(self.hardware_security_settings, 1, 0), unpack.format_table("hardware_security_settings[1:0]={}", _status)) + except: + self.decodeFailure = True + print "Error parsing HardwareSecurity" + import traceback + traceback.print_exc() + self.fini() + +class SystemPowerControls(SmbiosBaseStructure): + smbios_structure_type = 25 + + def __init__(self, u, sm): + super(SystemPowerControls, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + self.add_field('next_scheduled_poweron_month', u.unpack_one("B")) + self.add_field('next_scheduled_poweron_day_of_month', u.unpack_one("B")) + self.add_field('next_scheduled_poweron_hour', u.unpack_one("B")) + self.add_field('next_scheduled_poweron_minute', u.unpack_one("B")) + self.add_field('next_scheduled_poweron_second', u.unpack_one("B")) + except: + self.decodeFailure = True + print "Error parsing SystemPowerControls" + import traceback + traceback.print_exc() + self.fini() + +class VoltageProbe(SmbiosBaseStructure): + smbios_structure_type = 26 + + def __init__(self, u, sm): + super(VoltageProbe, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + self.add_field('description', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('location_and_status', u.unpack_one("B")) + _status = { + 0b001: 'Other', + 0b010: 'Unknown', + 0b011: 'OK', + 0b100: 'Non-critical', + 0b101: 'Critical', + 0b110: 'Non-recoverable' + } + _location = { + 0b00001: 'Other', + 0b00010: 'Unknown', + 0b00011: 'Processor', + 0b00100: 'Disk', + 0b00101: 'Peripheral Bay', + 0b00110: 'System Management Module', + 0b00111: 'Motherboard', + 0b01000: 'Memory Module', + 0b01001: 'Processor Module', + 0b01010: 'Power Unit', + 0b01011: 'Add-in Card' + } + self.add_field('status', bitfields.getbits(self.location_and_status, 7, 5), unpack.format_table("location_and_status[7:5]={}", _status)) + self.add_field('location', bitfields.getbits(self.location_and_status, 4, 0), unpack.format_table("location_and_status[4:0]={}", _location)) + if self.length > 0x6: + self.add_field('max_value', u.unpack_one(" 0x8: + self.add_field('min_value', u.unpack_one(" 0xA: + self.add_field('resolution', u.unpack_one(" 0xC: + self.add_field('tolerance', u.unpack_one(" 0xE: + self.add_field('accuracy', u.unpack_one(" 0x10: + self.add_field('oem_defined', u.unpack_one(" 0x14: + self.add_field('nominal_value', u.unpack_one(" 0x4: + self.add_field('temperature_probe_handle', u.unpack_one(" 0x6: + self.add_field('device_type_and_status', u.unpack_one("B")) + _status = { + 0b001: 'Other', + 0b010: 'Unknown', + 0b011: 'OK', + 0b100: 'Non-critical', + 0b101: 'Critical', + 0b110: 'Non-recoverable' + } + _type = { + 0b00001: 'Other', + 0b00010: 'Unknown', + 0b00011: 'Fan', + 0b00100: 'Centrifugal Blower', + 0b00101: 'Chip Fan', + 0b00110: 'Cabinet Fan', + 0b00111: 'Power Supply Fan', + 0b01000: 'Heat Pipe', + 0b01001: 'Integrated Refrigeration', + 0b10000: 'Active Cooling', + 0b10001: 'Passive Cooling' + } + self.add_field('status', bitfields.getbits(self.device_type_and_status, 7, 5), unpack.format_table("device_type_and_status[7:5]={}", _status)) + self.add_field('device_type', bitfields.getbits(self.device_type_and_status, 4, 0), unpack.format_table("device_type_and_status[4:0]={}", _type)) + if self.length > 0x7: + self.add_field('cooling_unit_group', u.unpack_one("B")) + if self.length > 0x8: + self.add_field('OEM_defined', u.unpack_one(" 0xC: + self.add_field('nominal_speed', u.unpack_one(" 0xE: + self.add_field('description', u.unpack_one("B"), self.fmtstr) + except: + self.decodeFailure = True + print "Error parsing CoolingDevice" + import traceback + traceback.print_exc() + self.fini() + +class TemperatureProbe(SmbiosBaseStructure): + smbios_structure_type = 28 + + def __init__(self, u, sm): + super(TemperatureProbe, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + self.add_field('description', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('location_and_status', u.unpack_one("B")) + _status = { + 0b001: 'Other', + 0b010: 'Unknown', + 0b011: 'OK', + 0b100: 'Non-critical', + 0b101: 'Critical', + 0b110: 'Non-recoverable' + } + _location = { + 0b00001: 'Other', + 0b00010: 'Unknown', + 0b00011: 'Processor', + 0b00100: 'Disk', + 0b00101: 'Peripheral Bay', + 0b00110: 'System Management Module', + 0b00111: 'Motherboard', + 0b01000: 'Memory Module', + 0b01001: 'Processor Module', + 0b01010: 'Power Unit', + 0b01011: 'Add-in Card', + 0b01100: 'Front Panel Board', + 0b01101: 'Back Panel Board', + 0b01110: 'Power System Board', + 0b01111: 'Drive Back Plane' + } + self.add_field('status', bitfields.getbits(self.location_and_status, 7, 5), unpack.format_table("location_and_status[7:5]={}", _status)) + self.add_field('location', bitfields.getbits(self.location_and_status, 4, 0), unpack.format_table("location_and_status[4:0]={}", _location)) + if self.length > 0x6: + self.add_field('maximum_value', u.unpack_one(" 0x8: + self.add_field('minimum_value', u.unpack_one(" 0xA: + self.add_field('resolution', u.unpack_one(" 0xC: + self.add_field('tolerance', u.unpack_one(" 0xE: + self.add_field('accuracy', u.unpack_one(" 0x10: + self.add_field('OEM_defined', u.unpack_one(" 0x14: + self.add_field('nominal_value', u.unpack_one(" 0x4: + self.add_field('description', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('location_and_status', u.unpack_one("B")) + _status = { + 0b001: 'Other', + 0b010: 'Unknown', + 0b011: 'OK', + 0b100: 'Non-critical', + 0b101: 'Critical', + 0b110: 'Non-recoverable' + } + _location = { + 0b00001: 'Other', + 0b00010: 'Unknown', + 0b00011: 'Processor', + 0b00100: 'Disk', + 0b00101: 'Peripheral Bay', + 0b00110: 'System Management Module', + 0b00111: 'Motherboard', + 0b01000: 'Memory Module', + 0b01001: 'Processor Module', + 0b01010: 'Power Unit', + 0b01011: 'Add-in Card', + 0b01100: 'Front Panel Board', + 0b01101: 'Back Panel Board', + 0b01110: 'Power System Board', + 0b01111: 'Drive Back Plane' + } + self.add_field('status', bitfields.getbits(self.location_and_status, 7, 5), unpack.format_table("location_and_status[7:5]={}", _status)) + self.add_field('location', bitfields.getbits(self.location_and_status, 4, 0), unpack.format_table("location_and_status[4:0]={}", _location)) + if self.length > 0x6: + self.add_field('maximum_value', u.unpack_one(" 0x8: + self.add_field('minimum_value', u.unpack_one(" 0xA: + self.add_field('resolution', u.unpack_one(" 0xC: + self.add_field('tolerance', u.unpack_one(" 0xE: + self.add_field('accuracy', u.unpack_one(" 0x10: + self.add_field('OEM_defined', u.unpack_one(" 0x14: + self.add_field('nominal_value', u.unpack_one(" 0x4: + self.add_field('manufacturer_name', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('connections', u.unpack_one("B")) + self.add_field('outbound_connection_enabled', bool(bitfields.getbits(self.connections, 1)), "connections[1]={}") + self.add_field('inbound_connection_enabled', bool(bitfields.getbits(self.connections, 0)), "connections[0]={}") + except: + self.decodeFailure = True + print "Error parsing OutOfBandRemoteAccess" + import traceback + traceback.print_exc() + self.fini() + +class BootIntegrityServicesEntryPoint(SmbiosBaseStructure): + smbios_structure_type = 31 + +class SystemBootInformation(SmbiosBaseStructure): + smbios_structure_type = 32 + + def __init__(self, u, sm): + super(SystemBootInformation, self).__init__(u, sm) + u = self.u + try: + if self.length > 0xA: + u.skip(6) + _boot_status = { + 0: 'No errors detected', + 1: 'No bootable media', + 2: '"normal" operating system failed to load', + 3: 'Firmware-detected hardware failure, including "unknown" failure types', + 4: 'Operating system-detected hardware failure', + 5: 'User-requested boot, usually through a keystroke', + 6: 'System security violation', + 7: 'Previously-requested image', + 8: 'System watchdog timer expired, causing the system to reboot', + xrange(9,127): 'Reserved for future assignment', + xrange(128, 191): 'Vendor/OEM-specific implementations', + xrange(192, 255): 'Product-specific implementations' + } + self.add_field('boot_status', u.unpack_one("B"), unpack.format_table("{}", _boot_status)) + except: + self.decodeFailure = True + print "Error parsing SystemBootInformation" + import traceback + traceback.print_exc() + self.fini() + +class MemoryErrorInfo64Bit(SmbiosBaseStructure): + smbios_structure_type = 33 + + def __init__(self, u, sm): + super(MemoryErrorInfo64Bit, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + _error_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'OK', + 0x04: 'Bad read', + 0x05: 'Parity error', + 0x06: 'Single-bit error', + 0x07: 'Double-bit error', + 0x08: 'Multi-bit error', + 0x09: 'Nibble error', + 0x0A: 'Checksum error', + 0x0B: 'CRC error', + 0x0C: 'Corrected single-bit error', + 0x0D: 'Corrected error', + 0x0E: 'Uncorrectable error' + } + self.add_field('error_type', u.unpack_one("B"), unpack.format_table("{}", _error_types)) + if self.length > 0x5: + _error_granularity_field = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Device level', + 0x04: 'Memory partition level' + } + self.add_field('error_granularity', u.unpack_one("B"), unpack.format_table("{}", _error_granularity_field)) + if self.length > 0x6: + _error_operation_field = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Read', + 0x04: 'Write', + 0x05: 'Partial write' + } + self.add_field('error_operation', u.unpack_one("B"), unpack.format_table("{}", _error_operation_field)) + if self.length > 0x7: + self.add_field('vendor_syndrome', u.unpack_one(" 0xB: + self.add_field('memory_array_error_address', u.unpack_one(" 0xF: + self.add_field('device_error_address', u.unpack_one(" 0x13: + self.add_field('error_resolution', u.unpack_one(" 0x4: + self.add_field('description', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + _type = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'National Semiconductor LM75', + 0x04: 'National Semiconductor LM78', + 0x05: 'National Semiconductor LM79', + 0x06: 'National Semiconductor LM80', + 0x07: 'National Semiconductor LM81', + 0x08: 'Analog Devices ADM9240', + 0x09: 'Dallas Semiconductor DS1780', + 0x0A: 'Maxim 1617', + 0x0B: 'Genesys GL518SM', + 0x0C: 'Winbond W83781D', + 0x0D: 'Holtek HT82H791' + } + self.add_field('device_type', u.unpack_one("B"), unpack.format_table("{}", _type)) + if self.length > 0x6: + self.add_field('address', u.unpack_one(" 0xA: + _address_type = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'I/O Port', + 0x04: 'Memory', + 0x05: 'SM Bus' + } + self.add_field('address_type', u.unpack_one("B"), unpack.format_table("{}", _address_type)) + except: + self.decodeFailure = True + print "Error parsing ManagementDevice" + import traceback + traceback.print_exc() + self.fini() + +class ManagementDeviceComponent(SmbiosBaseStructure): + smbios_structure_type = 35 + + def __init__(self, u, sm): + super(ManagementDeviceComponent, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + self.add_field('description', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('management_device_handle', u.unpack_one(" 0x7: + self.add_field('component_handle', u.unpack_one(" 0x9: + self.add_field('threshold_handle', u.unpack_one(" 0x4: + self.add_field('lower_threshold_noncritical', u.unpack_one(" 0x6: + self.add_field('upper_threshold_noncritical', u.unpack_one(" 0x8: + self.add_field('lower_threshold_critical', u.unpack_one(" 0xA: + self.add_field('upper_threshold_critical', u.unpack_one(" 0xC: + self.add_field('lower_threshold_nonrecoverable', u.unpack_one(" 0xE: + self.add_field('upper_threshold_nonrecoverable', u.unpack_one(" 0x4: + _channel_type = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'RamBus', + 0x04: 'SyncLink' + } + self.add_field('channel_type', u.unpack_one("B"), unpack.format_table("{}", _channel_type)) + if self.length > 0x6: + self.add_field('max_channel_load', u.unpack_one("B")) + if self.length > 0x8: + self.add_field('memory_device_count', u.unpack_one("B")) + if self.length > 0xA: + self.add_field('memory_device_load', u.unpack_one("B")) + if self.length > 0xC: + self.add_field('memory_device_handle', u.unpack_one(" 0x4: + self.add_field('power_unit_group', u.unpack_one("B")) + if self.length > 0x5: + self.add_field('location', u.unpack_one("B"), self.fmtstr) + if self.length > 0x6: + self.add_field('device_name', u.unpack_one("B"), self.fmtstr) + if self.length > 0x7: + self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr) + if self.length > 0x8: + self.add_field('serial_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0x9: + self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr) + if self.length > 0xA: + self.add_field('model_part_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0xB: + self.add_field('revision_level', u.unpack_one("B"), self.fmtstr) + if self.length > 0xC: + self.add_field('max_power_capacity', u.unpack_one(" 0xE: + self.add_field('power_supply_characteristics', u.unpack_one(" 0x10: + self.add_field('input_voltage_probe_handle', u.unpack_one(" 0x12: + self.add_field('cooling_device_handle', u.unpack_one(" 0x14: + self.add_field('input_current_probe_handle', u.unpack_one(" 0x4: + self.add_field('num_additional_information_entries', u.unpack_one("B")) + if self.length > 0x5: + self.add_field('additional_information_entry_length', u.unpack_one("B")) + self.add_field('referenced_handle', u.unpack_one(" 0x4: + self.add_field('reference_designation', u.unpack_one("B"), self.fmtstr) + if self.length > 0x5: + self.add_field('device_type', u.unpack_one("B")) + self.add_field('device_enabled', bool(bitfields.getbits(self.device_type, 7)), "device_type[7]={}") + _device_types = { + 0x01: 'Other', + 0x02: 'Unknown', + 0x03: 'Video', + 0x04: 'SCSI Controller', + 0x05: 'Ethernet', + 0x06: 'Token Ring', + 0x07: 'Sound', + 0x08: 'PATA Controller', + 0x09: 'SATA Controller', + 0x0A: 'SAS Controller' + } + self.add_field('type_of_device', bitfields.getbits(self.device_type, 6, 0), unpack.format_table("device_type[6:0]={}", _device_types)) + if self.length > 0x6: + self.add_field('device_type_instance', u.unpack_one("B")) + if self.length > 0x7: + self.add_field('segment_group_number', u.unpack_one(" 0x9: + self.add_field('bus_number', u.unpack_one("B"), self.fmtstr) + if self.length > 0xA: + self.add_field('device_and_function_number', u.unpack_one("B")) + self.add_field('device_number', bitfields.getbits(self.device_type, 7, 3), "device_and_function_number[7:3]={}") + self.add_field('function_number', bitfields.getbits(self.device_type, 2, 0), "device_and_function_number[2:0]={}") + except: + self.decodeFailure = True + print "Error parsing OnboardDevicesExtendedInformation" + import traceback + traceback.print_exc() + self.fini() + +class ManagementControllerHostInterface(SmbiosBaseStructure): + smbios_structure_type = 42 + + def __init__(self, u, sm): + super(ManagementControllerHostInterface, self).__init__(u, sm) + u = self.u + try: + if self.length > 0x4: + _interface_types = { + 0x00: 'Reserved', + 0x01: 'Reserved', + 0x02: 'KCS: Keyboard Controller Style', + 0x03: '8250 UART Register Compatible', + 0x04: '16450 UART Register Compatible', + 0x05: '16550/16550A UART Register Compatible', + 0x06: '16650/16650A UART Register Compatible', + 0x07: '16750/16750A UART Register Compatible', + 0x08: '16850/16850A UART Register Compatible', + 0xF0: 'OEM' + } + self.add_field('interface_type', u.unpack_one("B"), unpack.format_table("{}", _interface_types)) + if self.length > 0x5: + self.add_field('mc_host_interface_data', u.unpack_rest(), self.fmtstr) + except: + self.decodeFailure = True + print "Error parsing ManagementControllerHostInterface" + import traceback + traceback.print_exc() + self.fini() + +class Inactive(SmbiosBaseStructure): + smbios_structure_type = 126 + + def __init__(self, u, sm): + super(Inactive, self).__init__(u, sm) + self.fini() + +class EndOfTable(SmbiosBaseStructure): + smbios_structure_type = 127 + + def __init__(self, u, sm): + super(EndOfTable, self).__init__(u, sm) + self.fini() + +class SmbiosStructureUnknown(SmbiosBaseStructure): + smbios_structure_type = None + + def __init__(self, u, sm): + super(SmbiosStructureUnknown, self).__init__(u, sm) + self.fini() + +_smbios_structures = [ + BIOSInformation, + SystemInformation, + BaseboardInformation, + SystemEnclosure, + ProcessorInformation, + MemoryControllerInformation, + MemoryModuleInformation, + CacheInformation, + PortConnectorInfo, + SystemSlots, + OnBoardDevicesInformation, + OEMStrings, + SystemConfigOptions, + BIOSLanguageInformation, + GroupAssociations, + SystemEventLog, + PhysicalMemoryArray, + MemoryDevice, + MemoryErrorInfo32Bit, + MemoryArrayMappedAddress, + MemoryDeviceMappedAddress, + BuiltInPointingDevice, + PortableBattery, + SystemReset, + HardwareSecurity, + SystemPowerControls, + VoltageProbe, + CoolingDevice, + TemperatureProbe, + ElectricalCurrentProbe, + OutOfBandRemoteAccess, + BootIntegrityServicesEntryPoint, + SystemBootInformation, + MemoryErrorInfo64Bit, + ManagementDevice, + ManagementDeviceComponent, + ManagementDeviceThresholdData, + MemoryChannel, + IPMIDeviceInformation, + SystemPowerSupply, + AdditionalInformation, + OnboardDevicesExtendedInformation, + ManagementControllerHostInterface, + Inactive, + EndOfTable, + SmbiosStructureUnknown, # Must always come last +] + +def log_smbios_info(): + with redirect.logonly(): + try: + sm = SMBIOS() + print + if sm is None: + print "No SMBIOS structures found" + return + output = {} + known_types = (0, 1) + for sm_struct in sm.structures: + if sm_struct.type in known_types: + output.setdefault(sm_struct.type, []).append(sm_struct) + if len(output) == len(known_types): + break + + print "SMBIOS information:" + for key in sorted(known_types): + for s in output.get(key, ["No structure of type {} found".format(key)]): + print ttypager._wrap("{}: {}".format(key, s)) + except: + print "Error parsing SMBIOS information:" + import traceback + traceback.print_exc() + +def dump_raw(): + try: + sm = SMBIOS() + if sm: + s = "SMBIOS -- Raw bytes and structure decode.\n\n" + + s += str(sm.header) + '\n' + s += bits.dumpmem(sm._header_memory) + '\n' + + s += "Raw bytes for the SMBIOS structures\n" + s += bits.dumpmem(sm._structure_memory) + '\n' + + for sm_struct in sm.structures: + s += str(sm_struct) + '\n' + s += bits.dumpmem(sm_struct.raw_data) + + s += "Strings:\n" + for n in range(1, len(getattr(sm_struct, "strings", [])) + 1): + s += str(sm_struct.fmtstr(n)) + '\n' + s += bits.dumpmem(sm_struct.raw_strings) + '\n' + else: + s = "No SMBIOS structures found" + ttypager.ttypager_wrap(s, indent=False) + except: + print "Error parsing SMBIOS information:" + import traceback + traceback.print_exc() + +def dump(): + try: + sm = SMBIOS() + if sm: + s = str(sm) + else: + s = "No SMBIOS structures found" + ttypager.ttypager_wrap(s, indent=False) + except: + print "Error parsing SMBIOS information:" + import traceback + traceback.print_exc() + +def annex_a_conformance(): + try: + sm = SMBIOS() + + # check: 1. The table anchor string "_SM_" is present in the address range 0xF0000 to 0xFFFFF on a 16-byte bound + + def table_entry_point_verification(): + ''' Verify table entry-point''' + if (sm.header.length < 0x1F): + print "Failure: Table entry-point - The entry-point Length must be at least 0x1F" + if sm.header.checksum != 0: + print "Failure: Table entry-point - The entry-point checksum must evaluate to 0" + if ((sm.header.major_version < 2) and (sm.header.minor_version < 4)): + print "Failure: Table entry-point - SMBIOS version must be at least 2.4" + if (sm.header.intermediate_anchor_string == '_DMI_'): + print "Failure: Table entry-point - The Intermediate Anchor String must be '_DMI_'" + if (sm.header.intermediate_checksum != 0): + print "Failure: Table entry-point - The Intermediate checksum must evaluate to 0" + + #check: 3. The structure-table is traversable and conforms to the entry-point specifications: + + def req_structures(): + '''Checks for required structures and corresponding data''' + types_present = [sm.structures[x].smbios_structure_type for x in range(len(sm.structures))] + required = [0, 1, 4, 7, 9, 16, 17, 19, 31, 32] + for s in required: + if s not in set(types_present): + print "Failure: Type {} required but not found".format(s) + + else: + if s == 0: + if types_present.count(s) > 1: + print "Failure: Type {} - One and only one structure of this type must be present.".format(s) + if sm.structure_type(s).length < 0x18: + print "Failure: Type {} - The structure Length field must be at least 0x18".format(s) + if sm.structure_type(s).version is None: + print "Failure: Type {} - BIOS Version string must be present and non-null.".format(s) + if sm.structure_type(s).release_date is None: + print "Failure: Type {} - BIOS Release Date string must be present, non-null, and include a 4-digit year".format(s) + if bitfields.getbits(sm.structure_type(s).characteristics, 3, 0) != 0 or bitfields.getbits(sm.structure_type(s).characteristics, 31, 4) == 0: + print "Failure: Type {} - BIOS Characteristics: bits 3:0 must all be 0, and at least one of bits 31:4 must be set to 1.".format(s) + elif s == 1: + if types_present.count(s) > 1: + print "Failure: Type {} - One and only one structure of this type must be present.".format(s) + if sm.structure_type(s).length < 0x1B: + print "Failure: Type {} - The structure Length field must be at least 0x1B".format(s) + if sm.structure_type(s).manufacturer == None: + print "Failure: Type {} - Manufacturer string must be present and non-null.".format(s) + if sm.structure_type(s).product_name == None: + print "Failure: Type {} - Product Name string must be present and non-null".format(s) + if sm.structure_type(s).uuid == '00000000 00000000' and sm.structure_type(s).uuid == 'FFFFFFFF FFFFFFFF': + print "Failure: Type {} - UUID field must be neither 00000000 00000000 nor FFFFFFFF FFFFFFFF.".format(s) + if sm.structure_type(s).wakeup_type == 00 and sm.structure_type(s).wakeup_type == 0x02: + print "Failure: Type {} - Wake-up Type field must be neither 00h (Reserved) nor 02h (Unknown).".format(s) + # continue for remaining required types + + # check remaining conformance guidelines + + table_entry_point_verification() + req_structures() + except: + print "Error checking ANNEX A conformance guidelines" + import traceback + traceback.print_exc() diff --git a/tests/functional/acpi-bits/bits-tests/smilatency.py2 b/tests/functional/acpi-bits/bits-tests/smilatency.py2 new file mode 100644 index 0000000000..405af67e19 --- /dev/null +++ b/tests/functional/acpi-bits/bits-tests/smilatency.py2 @@ -0,0 +1,107 @@ +# Copyright (c) 2015, Intel Corporation +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. + +# This script runs only from the biosbits VM. + +"""SMI latency test.""" + +import bits +from collections import namedtuple +import testsuite +import time +import usb + +def register_tests(): + pass +# testsuite.add_test("SMI latency test", smi_latency); +# testsuite.add_test("SMI latency test with USB disabled via BIOS handoff", test_with_usb_disabled, runall=False); + +def smi_latency(): + MSR_SMI_COUNT = 0x34 + + print "Warning: touching the keyboard can affect the results of this test." + + tsc_per_sec = bits.tsc_per_sec() + tsc_per_usec = tsc_per_sec / (1000 * 1000) + bins = [long(tsc_per_usec * 10**i) for i in range(9)] + bin_descs = [ + "0 < t <= 1us", + "1us < t <= 10us", + "10us < t <= 100us", + "100us < t <= 1ms", + "1ms < t <= 10ms", + "10ms < t <= 100ms", + "100ms < t <= 1s ", + "1s < t <= 10s ", + "10s < t <= 100s ", + "100s < t ", + ] + + print "Starting test. Wait here, I will be back in 15 seconds." + (max_latency, smi_count_delta, bins) = bits.smi_latency(long(15 * tsc_per_sec), bins) + BinType = namedtuple('BinType', ("max", "total", "count", "times")) + bins = [BinType(*b) for b in bins] + + testsuite.test("SMI latency < 150us to minimize risk of OS timeouts", max_latency / tsc_per_usec <= 150) + if not testsuite.show_detail(): + return + + for bin, desc in zip(bins, bin_descs): + if bin.count == 0: + continue + testsuite.print_detail("{}; average = {}; count = {}".format(desc, bits.format_tsc(bin.total/bin.count), bin.count)) + deltas = (bits.format_tsc(t2 - t1) for t1,t2 in zip(bin.times, bin.times[1:])) + testsuite.print_detail(" Times between first few observations: {}".format(" ".join("{:>6}".format(delta) for delta in deltas))) + + if smi_count_delta is not None: + testsuite.print_detail("{} SMI detected using MSR_SMI_COUNT (MSR {:#x})".format(smi_count_delta, MSR_SMI_COUNT)) + + testsuite.print_detail("Summary of impact: observed maximum latency = {}".format(bits.format_tsc(max_latency))) + +def test_with_usb_disabled(): + if usb.handoff_to_os(): + smi_latency() + +def average_io_smi(port, value, count): + def f(): + tsc_start = bits.rdtsc() + bits.outb(port, value) + return bits.rdtsc() - tsc_start + counts = [f() for i in range(count)] + return sum(counts)/len(counts) + +def time_io_smi(port=0xb2, value=0, count=1000): + count_for_estimate = 10 + start = time.time() + average_io_smi(port, value, count_for_estimate) + avg10 = time.time() - start + estimate = avg10 * count/count_for_estimate + if estimate > 1: + print "Running test, estimated time: {}s".format(int(estimate)) + average = average_io_smi(port, value, count) + print "Average of {} SMIs (via outb, port={:#x}, value={:#x}): {}".format(count, port, value, bits.format_tsc(average)) diff --git a/tests/functional/acpi-bits/bits-tests/testacpi.py2 b/tests/functional/acpi-bits/bits-tests/testacpi.py2 new file mode 100644 index 0000000000..7bf9075c1b --- /dev/null +++ b/tests/functional/acpi-bits/bits-tests/testacpi.py2 @@ -0,0 +1,287 @@ +# Copyright (c) 2015, Intel Corporation +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. + +# This script runs only from the biosbits VM. + +"""Tests for ACPI""" + +import acpi +import bits +import bits.mwait +import struct +import testutil +import testsuite +import time + +def register_tests(): + testsuite.add_test("ACPI _MAT (Multiple APIC Table Entry) under Processor objects", test_mat, submenu="ACPI Tests") +# testsuite.add_test("ACPI _PSS (Pstate) table conformance tests", test_pss, submenu="ACPI Tests") +# testsuite.add_test("ACPI _PSS (Pstate) runtime tests", test_pstates, submenu="ACPI Tests") + testsuite.add_test("ACPI DSDT (Differentiated System Description Table)", test_dsdt, submenu="ACPI Tests") + testsuite.add_test("ACPI FACP (Fixed ACPI Description Table)", test_facp, submenu="ACPI Tests") + testsuite.add_test("ACPI HPET (High Precision Event Timer Table)", test_hpet, submenu="ACPI Tests") + testsuite.add_test("ACPI MADT (Multiple APIC Description Table)", test_apic, submenu="ACPI Tests") + testsuite.add_test("ACPI MPST (Memory Power State Table)", test_mpst, submenu="ACPI Tests") + testsuite.add_test("ACPI RSDP (Root System Description Pointer Structure)", test_rsdp, submenu="ACPI Tests") + testsuite.add_test("ACPI XSDT (Extended System Description Table)", test_xsdt, submenu="ACPI Tests") + +def test_mat(): + cpupaths = acpi.get_cpupaths() + apic = acpi.parse_apic() + procid_apicid = apic.procid_apicid + uid_x2apicid = apic.uid_x2apicid + for cpupath in cpupaths: + # Find the ProcId defined by the processor object + processor = acpi.evaluate(cpupath) + # Find the UID defined by the processor object's _UID method + uid = acpi.evaluate(cpupath + "._UID") + mat_buffer = acpi.evaluate(cpupath + "._MAT") + if mat_buffer is None: + continue + # Process each _MAT subtable + mat = acpi._MAT(mat_buffer) + for index, subtable in enumerate(mat): + if subtable.subtype == acpi.MADT_TYPE_LOCAL_APIC: + if subtable.flags.bits.enabled: + testsuite.test("{} Processor declaration ProcId = _MAT ProcId".format(cpupath), processor.ProcId == subtable.proc_id) + testsuite.print_detail("{} ProcId ({:#02x}) != _MAT ProcId ({:#02x})".format(cpupath, processor.ProcId, subtable.proc_id)) + testsuite.print_detail("Processor Declaration: {}".format(processor)) + testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) + if testsuite.test("{} with local APIC in _MAT has local APIC in MADT".format(cpupath), processor.ProcId in procid_apicid): + testsuite.test("{} ApicId derived using Processor declaration ProcId = _MAT ApicId".format(cpupath), procid_apicid[processor.ProcId] == subtable.apic_id) + testsuite.print_detail("{} ApicId derived from MADT ({:#02x}) != _MAT ApicId ({:#02x})".format(cpupath, procid_apicid[processor.ProcId], subtable.apic_id)) + testsuite.print_detail("Processor Declaration: {}".format(processor)) + testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) + if subtable.subtype == acpi.MADT_TYPE_LOCAL_X2APIC: + if subtable.flags.bits.enabled: + if testsuite.test("{} with x2Apic in _MAT has _UID".format(cpupath), uid is not None): + testsuite.test("{}._UID = _MAT UID".format(cpupath), uid == subtable.uid) + testsuite.print_detail("{}._UID ({:#x}) != _MAT UID ({:#x})".format(cpupath, uid, subtable.uid)) + testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) + if testsuite.test("{} with _MAT x2Apic has x2Apic in MADT".format(cpupath), subtable.uid in uid_x2apicid): + testsuite.test("{} x2ApicId derived from MADT using UID = _MAT x2ApicId".format(cpupath), uid_x2apicid[subtable.uid] == subtable.x2apicid) + testsuite.print_detail("{} x2ApicId derived from MADT ({:#02x}) != _MAT x2ApicId ({:#02x})".format(cpupath, uid_x2apicid[subtable.uid], subtable.x2apicid)) + testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) + +def test_pss(): + uniques = acpi.parse_cpu_method("_PSS") + # We special-case None here to avoid a double-failure for CPUs without a _PSS + testsuite.test("_PSS must be identical for all CPUs", len(uniques) <= 1 or (len(uniques) == 2 and None in uniques)) + for pss, cpupaths in uniques.iteritems(): + if not testsuite.test("_PSS must exist", pss is not None): + testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) + testsuite.print_detail('No _PSS exists') + continue + + if not testsuite.test("_PSS must not be empty", pss.pstates): + testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) + testsuite.print_detail('_PSS is empty') + continue + + testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) + for index, pstate in enumerate(pss.pstates): + testsuite.print_detail("P[{}]: {}".format(index, pstate)) + + testsuite.test("_PSS must contain at most 16 Pstates", len(pss.pstates) <= 16) + testsuite.test("_PSS must have no duplicate Pstates", len(pss.pstates) == len(set(pss.pstates))) + + frequencies = [p.core_frequency for p in pss.pstates] + testsuite.test("_PSS must list Pstates in descending order of frequency", frequencies == sorted(frequencies, reverse=True)) + + testsuite.test("_PSS must have Pstates with no duplicate frequencies", len(frequencies) == len(set(frequencies))) + + dissipations = [p.power for p in pss.pstates] + testsuite.test("_PSS must list Pstates in descending order of power dissipation", dissipations == sorted(dissipations, reverse=True)) + +def test_pstates(): + """Execute and verify frequency for each Pstate in the _PSS""" + IA32_PERF_CTL = 0x199 + with bits.mwait.use_hint(), bits.preserve_msr(IA32_PERF_CTL): + cpupath_procid = acpi.find_procid() + cpupath_uid = acpi.find_uid() + apic = acpi.parse_apic() + procid_apicid = apic.procid_apicid + uid_x2apicid = apic.uid_x2apicid + def cpupath_apicid(cpupath): + if procid_apicid is not None: + procid = cpupath_procid.get(cpupath, None) + if procid is not None: + apicid = procid_apicid.get(procid, None) + if apicid is not None: + return apicid + if uid_x2apicid is not None: + uid = cpupath_uid.get(cpupath, None) + if uid is not None: + apicid = uid_x2apicid.get(uid, None) + if apicid is not None: + return apicid + return bits.cpus()[0] + + bclk = testutil.adjust_to_nearest(bits.bclk(), 100.0/12) * 1000000 + + uniques = acpi.parse_cpu_method("_PSS") + for pss, cpupaths in uniques.iteritems(): + if not testsuite.test("_PSS must exist", pss is not None): + testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) + testsuite.print_detail('No _PSS exists') + continue + + for n, pstate in enumerate(pss.pstates): + for cpupath in cpupaths: + apicid = cpupath_apicid(cpupath) + if apicid is None: + print 'Failed to find apicid for cpupath {}'.format(cpupath) + continue + bits.wrmsr(apicid, IA32_PERF_CTL, pstate.control) + + # Detecting Turbo frequency requires at least 2 pstates + # since turbo frequency = max non-turbo frequency + 1 + turbo = False + if len(pss.pstates) >= 2: + turbo = (n == 0 and pstate.core_frequency == (pss.pstates[1].core_frequency + 1)) + if turbo: + # Needs to busywait, not sleep + start = time.time() + while (time.time() - start < 2): + pass + + for duration in (0.1, 1.0): + frequency_data = bits.cpu_frequency(duration) + # Abort the test if no cpu frequency is not available + if frequency_data is None: + continue + aperf = frequency_data[1] + aperf = testutil.adjust_to_nearest(aperf, bclk/2) + aperf = int(aperf / 1000000) + if turbo: + if aperf >= pstate.core_frequency: + break + else: + if aperf == pstate.core_frequency: + break + + if turbo: + testsuite.test("P{}: Turbo measured frequency {} >= expected {} MHz".format(n, aperf, pstate.core_frequency), aperf >= pstate.core_frequency) + else: + testsuite.test("P{}: measured frequency {} MHz == expected {} MHz".format(n, aperf, pstate.core_frequency), aperf == pstate.core_frequency) + +def test_psd_thread_scope(): + uniques = acpi.parse_cpu_method("_PSD") + if not testsuite.test("_PSD (P-State Dependency) must exist for each processor", None not in uniques): + testsuite.print_detail(acpi.factor_commonprefix(uniques[None])) + testsuite.print_detail('No _PSD exists') + return + unique_num_dependencies = {} + unique_num_entries = {} + unique_revision = {} + unique_domain = {} + unique_coordination_type = {} + unique_num_processors = {} + for value, cpupaths in uniques.iteritems(): + unique_num_dependencies.setdefault(len(value.dependencies), []).extend(cpupaths) + unique_num_entries.setdefault(value.dependencies[0].num_entries, []).extend(cpupaths) + unique_revision.setdefault(value.dependencies[0].revision, []).extend(cpupaths) + unique_domain.setdefault(value.dependencies[0].domain, []).extend(cpupaths) + unique_coordination_type.setdefault(value.dependencies[0].coordination_type, []).extend(cpupaths) + unique_num_processors.setdefault(value.dependencies[0].num_processors, []).extend(cpupaths) + def detail(d, fmt): + for value, cpupaths in sorted(d.iteritems(), key=(lambda (k,v): v)): + testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) + testsuite.print_detail(fmt.format(value)) + + testsuite.test('Dependency count for each processor must be 1', unique_num_dependencies.keys() == [1]) + detail(unique_num_dependencies, 'Dependency count for each processor = {} (Expected 1)') + testsuite.test('_PSD.num_entries must be 5', unique_num_entries.keys() == [5]) + detail(unique_num_entries, 'num_entries = {} (Expected 5)') + testsuite.test('_PSD.revision must be 0', unique_revision.keys() == [0]) + detail(unique_revision, 'revision = {}') + testsuite.test('_PSD.coordination_type must be 0xFE (HW_ALL)', unique_coordination_type.keys() == [0xfe]) + detail(unique_coordination_type, 'coordination_type = {:#x} (Expected 0xFE HW_ALL)') + testsuite.test('_PSD.domain must be unique (thread-scoped) for each processor', len(unique_domain) == len(acpi.get_cpupaths())) + detail(unique_domain, 'domain = {:#x} (Expected a unique value for each processor)') + testsuite.test('_PSD.num_processors must be 1', unique_num_processors.keys() == [1]) + detail(unique_num_processors, 'num_processors = {} (Expected 1)') + +def test_table_checksum(data): + csum = sum(ord(c) for c in data) % 0x100 + testsuite.test('ACPI table cumulative checksum must equal 0', csum == 0) + testsuite.print_detail("Cumulative checksum = {} (Expected 0)".format(csum)) + +def test_apic(): + data = acpi.get_table("APIC") + if data is None: + return + test_table_checksum(data) + apic = acpi.parse_apic() + +def test_dsdt(): + data = acpi.get_table("DSDT") + if data is None: + return + test_table_checksum(data) + +def test_facp(): + data = acpi.get_table("FACP") + if data is None: + return + test_table_checksum(data) + facp = acpi.parse_facp() + +def test_hpet(): + data = acpi.get_table("HPET") + if data is None: + return + test_table_checksum(data) + hpet = acpi.parse_hpet() + +def test_mpst(): + data = acpi.get_table("MPST") + if data is None: + return + test_table_checksum(data) + mpst = acpi.MPST(data) + +def test_rsdp(): + data = acpi.get_table("RSD PTR ") + if data is None: + return + + # Checksum the first 20 bytes per ACPI 1.0 + csum = sum(ord(c) for c in data[:20]) % 0x100 + testsuite.test('ACPI 1.0 table first 20 bytes cumulative checksum must equal 0', csum == 0) + testsuite.print_detail("Cumulative checksum = {} (Expected 0)".format(csum)) + + test_table_checksum(data) + rsdp = acpi.parse_rsdp() + +def test_xsdt(): + data = acpi.get_table("XSDT") + if data is None: + return + test_table_checksum(data) + xsdt = acpi.parse_xsdt() diff --git a/tests/functional/acpi-bits/bits-tests/testcpuid.py2 b/tests/functional/acpi-bits/bits-tests/testcpuid.py2 new file mode 100644 index 0000000000..7adefbe355 --- /dev/null +++ b/tests/functional/acpi-bits/bits-tests/testcpuid.py2 @@ -0,0 +1,87 @@ +# Copyright (c) 2012, Intel Corporation +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. + +# This script runs only from the biosbits VM. + +"""Tests and helpers for CPUID.""" + +import bits +import testsuite +import testutil + +def cpuid_helper(function, index=None, shift=0, mask=~0, eax_mask=~0, ebx_mask=~0, ecx_mask=~0, edx_mask=~0): + if index is None: + index = 0 + indexdesc = "" + else: + indexdesc = " index {0:#x}".format(index) + + def find_mask(m): + if m == ~0: + return mask + return m + masks = map(find_mask, [eax_mask, ebx_mask, ecx_mask, edx_mask]) + + uniques = {} + for cpu in bits.cpus(): + regs = bits.cpuid_result(*[(r >> shift) & m for r, m in zip(bits.cpuid(cpu, function, index), masks)]) + uniques.setdefault(regs, []).append(cpu) + + desc = ["CPUID function {:#x}{}".format(function, indexdesc)] + + if shift != 0: + desc.append("Register values have been shifted by {}".format(shift)) + if mask != ~0 or eax_mask != ~0 or ebx_mask != ~0 or ecx_mask != ~0 or edx_mask != ~0: + desc.append("Register values have been masked:") + shifted_masks = bits.cpuid_result(*[m << shift for m in masks]) + desc.append("Masks: eax={eax:#010x} ebx={ebx:#010x} ecx={ecx:#010x} edx={edx:#010x}".format(**shifted_masks._asdict())) + + if len(uniques) > 1: + regvalues = zip(*uniques.iterkeys()) + common_masks = bits.cpuid_result(*map(testutil.find_common_mask, regvalues)) + common_values = bits.cpuid_result(*[v[0] & m for v, m in zip(regvalues, common_masks)]) + desc.append('Register values are not unique across all logical processors') + desc.append("Common bits: eax={eax:#010x} ebx={ebx:#010x} ecx={ecx:#010x} edx={edx:#010x}".format(**common_values._asdict())) + desc.append("Mask of common bits: {eax:#010x} {ebx:#010x} {ecx:#010x} {edx:#010x}".format(**common_masks._asdict())) + + for regs in sorted(uniques.iterkeys()): + cpus = uniques[regs] + desc.append("Register value: eax={eax:#010x} ebx={ebx:#010x} ecx={ecx:#010x} edx={edx:#010x}".format(**regs._asdict())) + desc.append("On {0} CPUs: {1}".format(len(cpus), testutil.apicid_list(cpus))) + + return uniques, desc + +def test_cpuid_consistency(text, function, index=None, shift=0, mask=~0, eax_mask=~0, ebx_mask=~0, ecx_mask=~0, edx_mask=~0): + uniques, desc = cpuid_helper(function, index, shift, mask, eax_mask, ebx_mask, ecx_mask, edx_mask) + desc[0] += " Consistency Check" + if text: + desc.insert(0, text) + status = testsuite.test(desc[0], len(uniques) == 1) + for line in desc[1:]: + testsuite.print_detail(line) + return status diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 61cdd1d598..3bbe80b05d 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -11,6 +11,7 @@ endif # Timeouts for individual tests that can be slow e.g. with debugging enabled test_timeouts = { + 'acpi_bits' : 240, 'netdev_ethtool' : 180, 'ppc_40p' : 240, 'ppc64_hv' : 1000, @@ -96,6 +97,7 @@ tests_x86_64_system_quick = [ ] tests_x86_64_system_thorough = [ + 'acpi_bits', 'netdev_ethtool', 'virtio_gpu', ] diff --git a/tests/functional/test_acpi_bits.py b/tests/functional/test_acpi_bits.py new file mode 100755 index 0000000000..ee40647d5b --- /dev/null +++ b/tests/functional/test_acpi_bits.py @@ -0,0 +1,410 @@ +#!/usr/bin/env python3 +# +# Exercise QEMU generated ACPI/SMBIOS tables using biosbits, +# https://biosbits.org/ +# +# 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, see . +# +# +# Author: +# Ani Sinha + +# pylint: disable=invalid-name +# pylint: disable=consider-using-f-string + +""" +This is QEMU ACPI/SMBIOS functional tests using biosbits. +Biosbits is available originally at https://biosbits.org/. +This test uses a fork of the upstream bits and has numerous fixes +including an upgraded acpica. The fork is located here: +https://gitlab.com/qemu-project/biosbits-bits . +""" + +import logging +import os +import platform +import re +import shutil +import subprocess +import tarfile +import tempfile +import time +import zipfile + +from pathlib import Path +from typing import ( + List, + Optional, + Sequence, +) +from qemu.machine import QEMUMachine +from unittest import skipIf +from qemu_test import QemuBaseTest, Asset + +deps = ["xorriso", "mformat"] # dependent tools needed in the test setup/box. +supported_platforms = ['x86_64'] # supported test platforms. + +# default timeout of 120 secs is sometimes not enough for bits test. +BITS_TIMEOUT = 200 + +def which(tool): + """ looks up the full path for @tool, returns None if not found + or if @tool does not have executable permissions. + """ + paths=os.getenv('PATH') + for p in paths.split(os.path.pathsep): + p = os.path.join(p, tool) + if os.path.exists(p) and os.access(p, os.X_OK): + return p + return None + +def missing_deps(): + """ returns True if any of the test dependent tools are absent. + """ + for dep in deps: + if which(dep) is None: + return True + return False + +def supported_platform(): + """ checks if the test is running on a supported platform. + """ + return platform.machine() in supported_platforms + +class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods + """ + A QEMU VM, with isa-debugcon enabled and bits iso passed + using -cdrom to QEMU commandline. + + """ + def __init__(self, + binary: str, + args: Sequence[str] = (), + wrapper: Sequence[str] = (), + name: Optional[str] = None, + base_temp_dir: str = "/var/tmp", + debugcon_log: str = "debugcon-log.txt", + debugcon_addr: str = "0x403", + qmp_timer: Optional[float] = None): + # pylint: disable=too-many-arguments + + if name is None: + name = "qemu-bits-%d" % os.getpid() + super().__init__(binary, args, wrapper=wrapper, name=name, + base_temp_dir=base_temp_dir, + qmp_timer=qmp_timer) + self.debugcon_log = debugcon_log + self.debugcon_addr = debugcon_addr + self.base_temp_dir = base_temp_dir + + @property + def _base_args(self) -> List[str]: + args = super()._base_args + args.extend([ + '-chardev', + 'file,path=%s,id=debugcon' %os.path.join(self.base_temp_dir, + self.debugcon_log), + '-device', + 'isa-debugcon,iobase=%s,chardev=debugcon' %self.debugcon_addr, + ]) + return args + + def base_args(self): + """return the base argument to QEMU binary""" + return self._base_args + +@skipIf(not supported_platform() or missing_deps(), + 'unsupported platform or dependencies (%s) not installed' \ + % ','.join(deps)) +class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes + """ + ACPI and SMBIOS tests using biosbits. + """ + # in slower systems the test can take as long as 3 minutes to complete. + timeout = BITS_TIMEOUT + + # following are some standard configuration constants + # gitlab CI does shallow clones of depth 20 + BITS_INTERNAL_VER = 2020 + # commit hash must match the artifact tag below + BITS_COMMIT_HASH = 'c7920d2b' + # this is the latest bits release as of today. + BITS_TAG = "qemu-bits-10262023" + + ASSET_BITS = Asset(("https://gitlab.com/qemu-project/" + "biosbits-bits/-/jobs/artifacts/%s/" + "download?job=qemu-bits-build" % BITS_TAG), + '1b8dd612c6831a6b491716a77acc486666aaa867051cdc34f7ce169c2e25f487') + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._vm = None + self._workDir = None + self._baseDir = None + + self._debugcon_addr = '0x403' + self._debugcon_log = 'debugcon-log.txt' + self.logger = self.log + + def _print_log(self, log): + self.logger.info('\nlogs from biosbits follows:') + self.logger.info('==========================================\n') + self.logger.info(log) + self.logger.info('==========================================\n') + + def copy_bits_config(self): + """ copies the bios bits config file into bits. + """ + config_file = 'bits-cfg.txt' + bits_config_dir = os.path.join(self._baseDir, 'acpi-bits', + 'bits-config') + target_config_dir = os.path.join(self._workDir, + 'bits-%d' %self.BITS_INTERNAL_VER, + 'boot') + self.assertTrue(os.path.exists(bits_config_dir)) + self.assertTrue(os.path.exists(target_config_dir)) + self.assertTrue(os.access(os.path.join(bits_config_dir, + config_file), os.R_OK)) + shutil.copy2(os.path.join(bits_config_dir, config_file), + target_config_dir) + self.logger.info('copied config file %s to %s', + config_file, target_config_dir) + + def copy_test_scripts(self): + """copies the python test scripts into bits. """ + + bits_test_dir = os.path.join(self._baseDir, 'acpi-bits', + 'bits-tests') + target_test_dir = os.path.join(self._workDir, + 'bits-%d' %self.BITS_INTERNAL_VER, + 'boot', 'python') + + self.assertTrue(os.path.exists(bits_test_dir)) + self.assertTrue(os.path.exists(target_test_dir)) + + for filename in os.listdir(bits_test_dir): + if os.path.isfile(os.path.join(bits_test_dir, filename)) and \ + filename.endswith('.py2'): + # all test scripts are named with extension .py2 so that + # avocado does not try to load them. These scripts are + # written for python 2.7 not python 3 and hence if avocado + # loaded them, it would complain about python 3 specific + # syntaxes. + newfilename = os.path.splitext(filename)[0] + '.py' + shutil.copy2(os.path.join(bits_test_dir, filename), + os.path.join(target_test_dir, newfilename)) + self.logger.info('copied test file %s to %s', + filename, target_test_dir) + + # now remove the pyc test file if it exists, otherwise the + # changes in the python test script won't be executed. + testfile_pyc = os.path.splitext(filename)[0] + '.pyc' + if os.access(os.path.join(target_test_dir, testfile_pyc), + os.F_OK): + os.remove(os.path.join(target_test_dir, testfile_pyc)) + self.logger.info('removed compiled file %s', + os.path.join(target_test_dir, + testfile_pyc)) + + def fix_mkrescue(self, mkrescue): + """ grub-mkrescue is a bash script with two variables, 'prefix' and + 'libdir'. They must be pointed to the right location so that the + iso can be generated appropriately. We point the two variables to + the directory where we have extracted our pre-built bits grub + tarball. + """ + grub_x86_64_mods = os.path.join(self._workDir, 'grub-inst-x86_64-efi') + grub_i386_mods = os.path.join(self._workDir, 'grub-inst') + + self.assertTrue(os.path.exists(grub_x86_64_mods)) + self.assertTrue(os.path.exists(grub_i386_mods)) + + new_script = "" + with open(mkrescue, 'r', encoding='utf-8') as filehandle: + orig_script = filehandle.read() + new_script = re.sub('(^prefix=)(.*)', + r'\1"%s"' %grub_x86_64_mods, + orig_script, flags=re.M) + new_script = re.sub('(^libdir=)(.*)', r'\1"%s/lib"' %grub_i386_mods, + new_script, flags=re.M) + + with open(mkrescue, 'w', encoding='utf-8') as filehandle: + filehandle.write(new_script) + + def generate_bits_iso(self): + """ Uses grub-mkrescue to generate a fresh bits iso with the python + test scripts + """ + bits_dir = os.path.join(self._workDir, + 'bits-%d' %self.BITS_INTERNAL_VER) + iso_file = os.path.join(self._workDir, + 'bits-%d.iso' %self.BITS_INTERNAL_VER) + mkrescue_script = os.path.join(self._workDir, + 'grub-inst-x86_64-efi', 'bin', + 'grub-mkrescue') + + self.assertTrue(os.access(mkrescue_script, + os.R_OK | os.W_OK | os.X_OK)) + + self.fix_mkrescue(mkrescue_script) + + self.logger.info('using grub-mkrescue for generating biosbits iso ...') + + try: + if os.getenv('V') or os.getenv('BITS_DEBUG'): + proc = subprocess.run([mkrescue_script, '-o', iso_file, + bits_dir], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + check=True) + self.logger.info("grub-mkrescue output %s" % proc.stdout) + else: + subprocess.check_call([mkrescue_script, '-o', + iso_file, bits_dir], + stderr=subprocess.DEVNULL, + stdout=subprocess.DEVNULL) + except Exception as e: # pylint: disable=broad-except + self.skipTest("Error while generating the bits iso. " + "Pass V=1 in the environment to get more details. " + + str(e)) + + self.assertTrue(os.access(iso_file, os.R_OK)) + + self.logger.info('iso file %s successfully generated.', iso_file) + + def setUp(self): # pylint: disable=arguments-differ + super().setUp('qemu-system-') + self.logger = self.log + + self._baseDir = Path(__file__).parent + + # workdir could also be avocado's own workdir in self.workdir. + # At present, I prefer to maintain my own temporary working + # directory. It gives us more control over the generated bits + # log files and also for debugging, we may chose not to remove + # this working directory so that the logs and iso can be + # inspected manually and archived if needed. + self._workDir = tempfile.mkdtemp(prefix='acpi-bits-', + suffix='.tmp') + self.logger.info('working dir: %s', self._workDir) + + prebuiltDir = os.path.join(self._workDir, 'prebuilt') + if not os.path.isdir(prebuiltDir): + os.mkdir(prebuiltDir, mode=0o775) + + bits_zip_file = os.path.join(prebuiltDir, 'bits-%d-%s.zip' + %(self.BITS_INTERNAL_VER, + self.BITS_COMMIT_HASH)) + grub_tar_file = os.path.join(prebuiltDir, + 'bits-%d-%s-grub.tar.gz' + %(self.BITS_INTERNAL_VER, + self.BITS_COMMIT_HASH)) + + bitsLocalArtLoc = self.ASSET_BITS.fetch() + self.logger.info("downloaded bits artifacts to %s", bitsLocalArtLoc) + + # extract the bits artifact in the temp working directory + with zipfile.ZipFile(bitsLocalArtLoc, 'r') as zref: + zref.extractall(prebuiltDir) + + # extract the bits software in the temp working directory + with zipfile.ZipFile(bits_zip_file, 'r') as zref: + zref.extractall(self._workDir) + + with tarfile.open(grub_tar_file, 'r', encoding='utf-8') as tarball: + tarball.extractall(self._workDir) + + self.copy_test_scripts() + self.copy_bits_config() + self.generate_bits_iso() + + def parse_log(self): + """parse the log generated by running bits tests and + check for failures. + """ + debugconf = os.path.join(self._workDir, self._debugcon_log) + log = "" + with open(debugconf, 'r', encoding='utf-8') as filehandle: + log = filehandle.read() + + matchiter = re.finditer(r'(.*Summary: )(\d+ passed), (\d+ failed).*', + log) + for match in matchiter: + # verify that no test cases failed. + try: + self.assertEqual(match.group(3).split()[0], '0', + 'Some bits tests seems to have failed. ' \ + 'Please check the test logs for more info.') + except AssertionError as e: + self._print_log(log) + raise e + else: + if os.getenv('V') or os.getenv('BITS_DEBUG'): + self._print_log(log) + + def tearDown(self): + """ + Lets do some cleanups. + """ + if self._vm: + self.assertFalse(not self._vm.is_running) + if not os.getenv('BITS_DEBUG') and self._workDir: + self.logger.info('removing the work directory %s', self._workDir) + shutil.rmtree(self._workDir) + else: + self.logger.info('not removing the work directory %s ' \ + 'as BITS_DEBUG is ' \ + 'passed in the environment', self._workDir) + super().tearDown() + + def test_acpi_smbios_bits(self): + """The main test case implementation.""" + + iso_file = os.path.join(self._workDir, + 'bits-%d.iso' %self.BITS_INTERNAL_VER) + + self.assertTrue(os.access(iso_file, os.R_OK)) + + self._vm = QEMUBitsMachine(binary=self.qemu_bin, + base_temp_dir=self._workDir, + debugcon_log=self._debugcon_log, + debugcon_addr=self._debugcon_addr) + + self._vm.add_args('-cdrom', '%s' %iso_file) + # the vm needs to be run under icount so that TCG emulation is + # consistent in terms of timing. smilatency tests have consistent + # timing requirements. + self._vm.add_args('-icount', 'auto') + # currently there is no support in bits for recognizing 64-bit SMBIOS + # entry points. QEMU defaults to 64-bit entry points since the + # upstream commit bf376f3020 ("hw/i386/pc: Default to use SMBIOS 3.0 + # for newer machine models"). Therefore, enforce 32-bit entry point. + self._vm.add_args('-machine', 'smbios-entry-point-type=32') + + # enable console logging + self._vm.set_console() + self._vm.launch() + + + # biosbits has been configured to run all the specified test suites + # in batch mode and then automatically initiate a vm shutdown. + # Set timeout to BITS_TIMEOUT for SHUTDOWN event from bits VM at par + # with the avocado test timeout. + self._vm.event_wait('SHUTDOWN', timeout=BITS_TIMEOUT) + self._vm.wait(timeout=None) + self.logger.debug("Checking console output ...") + self.parse_log() + +if __name__ == '__main__': + QemuBaseTest.main()