1# Copyright (c) 2015, Intel Corporation
2# All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are met:
8#
9#     * Redistributions of source code must retain the above copyright notice,
10#       this list of conditions and the following disclaimer.
11#     * Redistributions in binary form must reproduce the above copyright notice,
12#       this list of conditions and the following disclaimer in the documentation
13#       and/or other materials provided with the distribution.
14#     * Neither the name of Intel Corporation nor the names of its contributors
15#       may be used to endorse or promote products derived from this software
16#       without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29# This script runs only from the biosbits VM.
30
31"""SMBIOS/DMI module."""
32
33import bits
34import bitfields
35import ctypes
36import redirect
37import struct
38import uuid
39import unpack
40import ttypager
41import sys
42
43class SMBIOS(unpack.Struct):
44    def __new__(cls):
45        if sys.platform == "BITS-EFI":
46            import efi
47            sm_ptr = efi.system_table.ConfigurationTableDict.get(efi.SMBIOS_TABLE_GUID)
48        else:
49            address = 0xF0000
50            mem = bits.memory(0xF0000, 0x10000)
51            for offset in range(0, len(mem), 16):
52                signature = (ctypes.c_char * 4).from_address(address + offset).value
53                if signature == "_SM_":
54                    entry_point_length = ctypes.c_ubyte.from_address(address + offset + 5).value
55                    csum = sum(map(ord, mem[offset:offset + entry_point_length])) & 0xff
56                    if csum == 0:
57                        sm_ptr = address + offset
58                        break
59            else:
60                return None
61
62        if not sm_ptr:
63            return None
64
65        sm = super(SMBIOS, cls).__new__(cls)
66        sm._header_memory = bits.memory(sm_ptr, 0x1f)
67        return sm
68
69    def __init__(self):
70        super(SMBIOS, self).__init__()
71        u = unpack.Unpackable(self._header_memory)
72        self.add_field('header', Header(u))
73        self._structure_memory = bits.memory(self.header.structure_table_address, self.header.structure_table_length)
74        u = unpack.Unpackable(self._structure_memory)
75        self.add_field('structures', unpack.unpack_all(u, _smbios_structures, self), unpack.format_each("\n\n{!r}"))
76
77    def structure_type(self, num):
78        '''Dumps structure of given Type if present'''
79        try:
80            types_present = [self.structures[x].smbios_structure_type for x in range(len(self.structures))]
81            matrix = dict()
82            for index in range(len(types_present)):
83                if types_present.count(types_present[index]) == 1:
84                    matrix[types_present[index]] = self.structures[index]
85                else: # if multiple structures of the same type, return a list of structures for the type number
86                    if matrix.has_key(types_present[index]):
87                        matrix[types_present[index]].append(self.structures[index])
88                    else:
89                        matrix[types_present[index]] = [self.structures[index]]
90            return matrix[num]
91        except:
92            print "Failure: Type {} - not found".format(num)
93
94class Header(unpack.Struct):
95    def __new__(cls, u):
96        return super(Header, cls).__new__(cls)
97
98    def __init__(self, u):
99        super(Header, self).__init__()
100        self.raw_data = u.unpack_rest()
101        u = unpack.Unpackable(self.raw_data)
102        self.add_field('anchor_string', u.unpack_one("4s"))
103        self.add_field('checksum', u.unpack_one("B"))
104        self.add_field('length', u.unpack_one("B"))
105        self.add_field('major_version', u.unpack_one("B"))
106        self.add_field('minor_version', u.unpack_one("B"))
107        self.add_field('max_structure_size', u.unpack_one("<H"))
108        self.add_field('entry_point_revision', u.unpack_one("B"))
109        self.add_field('formatted_area', u.unpack_one("5s"))
110        self.add_field('intermediate_anchor_string', u.unpack_one("5s"))
111        self.add_field('intermediate_checksum', u.unpack_one("B"))
112        self.add_field('structure_table_length', u.unpack_one("<H"))
113        self.add_field('structure_table_address', u.unpack_one("<I"))
114        self.add_field('number_structures', u.unpack_one("<H"))
115        self.add_field('bcd_revision', u.unpack_one("B"))
116        if not u.at_end():
117            self.add_field('data', u.unpack_rest())
118
119class SmbiosBaseStructure(unpack.Struct):
120    def __new__(cls, u, sm):
121        t = u.unpack_peek_one("B")
122        if cls.smbios_structure_type is not None and t != cls.smbios_structure_type:
123            return None
124        return super(SmbiosBaseStructure, cls).__new__(cls)
125
126    def __init__(self, u, sm):
127        super(SmbiosBaseStructure, self).__init__()
128        self.start_offset = u.offset
129        length = u.unpack_peek_one("<xB")
130        self.raw_data = u.unpack_raw(length)
131        self.u = unpack.Unpackable(self.raw_data)
132
133        self.strings_offset = u.offset
134        def unpack_string():
135            return "".join(iter(lambda: u.unpack_one("c"), "\x00"))
136        strings = list(iter(unpack_string, ""))
137        if not strings:
138            u.skip(1)
139
140        self.strings_length = u.offset - self.strings_offset
141        self.raw_strings = str(bits.memory(sm.header.structure_table_address + self.strings_offset, self.strings_length))
142
143        if len(strings):
144            self.strings = strings
145
146        self.add_field('type', self.u.unpack_one("B"))
147        self.add_field('length', self.u.unpack_one("B"))
148        self.add_field('handle', self.u.unpack_one("<H"))
149
150    def fini(self):
151        if not self.u.at_end():
152            self.add_field('data', self.u.unpack_rest())
153        del self.u
154
155    def fmtstr(self, i):
156        """Format the specified index and the associated string"""
157        return "{} '{}'".format(i, self.getstr(i))
158
159    def getstr(self, i):
160        """Get the string associated with the given index"""
161        if i == 0:
162            return "(none)"
163        if not hasattr(self, "strings"):
164            return "(error: structure has no strings)"
165        if i > len(self.strings):
166            return "(error: string index out of range)"
167        return self.strings[i - 1]
168
169class BIOSInformation(SmbiosBaseStructure):
170    smbios_structure_type = 0
171
172    def __init__(self, u, sm):
173        super(BIOSInformation, self).__init__(u, sm)
174        u = self.u
175        try:
176            self.add_field('vendor', u.unpack_one("B"), self.fmtstr)
177            self.add_field('version', u.unpack_one("B"), self.fmtstr)
178            self.add_field('starting_address_segment', u.unpack_one("<H"))
179            self.add_field('release_date', u.unpack_one("B"), self.fmtstr)
180            self.add_field('rom_size', u.unpack_one("B"))
181            self.add_field('characteristics', u.unpack_one("<Q"))
182            minor_version_str = str(sm.header.minor_version) # 34 is .34, 4 is .4, 41 is .41; compare ASCIIbetically to compare initial digits rather than numeric value
183            if (sm.header.major_version, minor_version_str) >= (2,"4"):
184                characteristic_bytes = 2
185            else:
186                characteristic_bytes = self.length - 0x12
187            self.add_field('characteristics_extensions', [u.unpack_one("B") for b in range(characteristic_bytes)])
188            if (sm.header.major_version, minor_version_str) >= (2,"4"):
189                self.add_field('major_release', u.unpack_one("B"))
190                self.add_field('minor_release', u.unpack_one("B"))
191                self.add_field('ec_major_release', u.unpack_one("B"))
192                self.add_field('ec_minor_release', u.unpack_one("B"))
193        except:
194            self.decode_failure = True
195            print "Error parsing BIOSInformation"
196            import traceback
197            traceback.print_exc()
198        self.fini()
199
200class SystemInformation(SmbiosBaseStructure):
201    smbios_structure_type = 1
202
203    def __init__(self, u, sm):
204        super(SystemInformation, self).__init__(u, sm)
205        u = self.u
206        try:
207            self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr)
208            self.add_field('product_name', u.unpack_one("B"), self.fmtstr)
209            self.add_field('version', u.unpack_one("B"), self.fmtstr)
210            self.add_field('serial_number', u.unpack_one("B"), self.fmtstr)
211            if self.length > 0x8:
212                self.add_field('uuid', uuid.UUID(bytes_le=u.unpack_one("16s")))
213                wakeup_types = {
214                    0: 'Reserved',
215                    1: 'Other',
216                    2: 'Unknown',
217                    3: 'APM Timer',
218                    4: 'Modem Ring',
219                    5: 'LAN Remote',
220                    6: 'Power Switch',
221                    7: 'PCI PME#',
222                    8: 'AC Power Restored'
223                }
224                self.add_field('wakeup_type', u.unpack_one("B"), unpack.format_table("{}", wakeup_types))
225            if self.length > 0x19:
226                self.add_field('sku_number', u.unpack_one("B"), self.fmtstr)
227                self.add_field('family', u.unpack_one("B"), self.fmtstr)
228        except:
229            self.decode_failure = True
230            print "Error parsing SystemInformation"
231            import traceback
232            traceback.print_exc()
233        self.fini()
234
235_board_types = {
236    1: 'Unknown',
237    2: 'Other',
238    3: 'Server Blade',
239    4: 'Connectivity Switch',
240    5: 'System Management Module',
241    6: 'Processor Module',
242    7: 'I/O Module',
243    8: 'Memory Module',
244    9: 'Daughter Board',
245    0xA: 'Motherboard',
246    0xB: 'Processor/Memory Module',
247    0xC: 'Processor/IO Module',
248    0xD: 'Interconnect Board'
249}
250
251class BaseboardInformation(SmbiosBaseStructure):
252    smbios_structure_type = 2
253
254    def __init__(self, u, sm):
255        super(BaseboardInformation, self).__init__(u, sm)
256        u = self.u
257        try:
258            self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr)
259            self.add_field('product', u.unpack_one("B"), self.fmtstr)
260            self.add_field('version', u.unpack_one("B"), self.fmtstr)
261            self.add_field('serial_number', u.unpack_one("B"), self.fmtstr)
262
263            if self.length > 0x8:
264                self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr)
265
266            if self.length > 0x9:
267                self.add_field('feature_flags', u.unpack_one("B"))
268                self.add_field('hosting_board', bool(bitfields.getbits(self.feature_flags, 0)), "feature_flags[0]={}")
269                self.add_field('requires_daughter_card', bool(bitfields.getbits(self.feature_flags, 1)), "feature_flags[1]={}")
270                self.add_field('removable', bool(bitfields.getbits(self.feature_flags, 2)), "feature_flags[2]={}")
271                self.add_field('replaceable', bool(bitfields.getbits(self.feature_flags, 3)), "feature_flags[3]={}")
272                self.add_field('hot_swappable', bool(bitfields.getbits(self.feature_flags, 4)), "feature_flags[4]={}")
273
274            if self.length > 0xA:
275                self.add_field('location', u.unpack_one("B"), self.fmtstr)
276
277            if self.length > 0xB:
278                self.add_field('chassis_handle', u.unpack_one("<H"))
279
280            if self.length > 0xD:
281                self.add_field('board_type', u.unpack_one("B"), unpack.format_table("{}", _board_types))
282
283            if self.length > 0xE:
284                self.add_field('handle_count', u.unpack_one("B"))
285                if self.handle_count > 0:
286                    self.add_field('contained_object_handles', tuple(u.unpack_one("<H") for i in range(self.handle_count)))
287        except:
288            self.decode_failure = True
289            print "Error parsing BaseboardInformation"
290            import traceback
291            traceback.print_exc()
292        self.fini()
293
294class SystemEnclosure(SmbiosBaseStructure):
295    smbios_structure_type = 3
296
297    def __init__(self, u, sm):
298        super(SystemEnclosure, self).__init__(u, sm)
299        u = self.u
300        try:
301            self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr)
302            self.add_field('enumerated_type', u.unpack_one("B"))
303            self.add_field('chassis_lock_present', bool(bitfields.getbits(self.enumerated_type, 7)), "enumerated_type[7]={}")
304            board_types = {
305                0x01: 'Other',
306                0x02: 'Unknown',
307                0x03: 'Desktop',
308                0x04: 'Low Profile Desktop',
309                0x05: 'Pizza Box',
310                0x06: 'Mini Tower',
311                0x07: 'Tower',
312                0x08: 'Portable',
313                0x09: 'Laptop',
314                0x0A: 'Notebook',
315                0x0B: 'Hand Held',
316                0x0C: 'Docking Station',
317                0x0D: 'All in One',
318                0x0E: 'Sub Notebook',
319                0x0F: 'Space-saving',
320                0x10: 'Lunch Box',
321                0x11: 'Main Server Chassis',
322                0x12: 'Expansion Chassis',
323                0x13: 'SubChassis',
324                0x14: 'Bus Expansion Chassis',
325                0x15: 'Peripheral Chassis',
326                0x16: 'RAID Chassis',
327                0x17: 'Rack Mount Chassis',
328                0x18: 'Sealed-case PC',
329                0x19: 'Multi-system chassis W',
330                0x1A: 'Compact PCI',
331                0x1B: 'Advanced TCA',
332                0x1C: 'Blade',
333                0x1D: 'Blade Enclosure',
334            }
335            self.add_field('system_enclosure_type', bitfields.getbits(self.enumerated_type, 6, 0), unpack.format_table("enumerated_type[6:0]={}", board_types))
336            self.add_field('version', u.unpack_one("B"), self.fmtstr)
337            self.add_field('serial_number', u.unpack_one("B"), self.fmtstr)
338            self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr)
339            minor_version_str = str(sm.header.minor_version) # 34 is .34, 4 is .4, 41 is .41; compare ASCIIbetically to compare initial digits rather than numeric value
340            if self.length > 9:
341                chassis_states = {
342                    0x01: 'Other',
343                    0x02: 'Unknown',
344                    0x03: 'Safe',
345                    0x04: 'Warning',
346                    0x05: 'Critical',
347                    0x06: 'Non-recoverable',
348                }
349                self.add_field('bootup_state', u.unpack_one("B"), unpack.format_table("{}", chassis_states))
350                self.add_field('power_supply_state', u.unpack_one("B"), unpack.format_table("{}", chassis_states))
351                self.add_field('thermal_state', u.unpack_one("B"), unpack.format_table("{}", chassis_states))
352                security_states = {
353                    0x01: 'Other',
354                    0x02: 'Unknown',
355                    0x03: 'None',
356                    0x04: 'External interface locked out',
357                    0x05: 'External interface enabled',
358                }
359                self.add_field('security_status', u.unpack_one("B"), unpack.format_table("{}", security_states))
360            if self.length > 0xd:
361                self.add_field('oem_defined', u.unpack_one("<I"))
362            if self.length > 0x11:
363                self.add_field('height', u.unpack_one("B"))
364                self.add_field('num_power_cords', u.unpack_one("B"))
365                self.add_field('contained_element_count', u.unpack_one("B"))
366                self.add_field('contained_element_length', u.unpack_one("B"))
367            if getattr(self, 'contained_element_count', 0):
368                self.add_field('contained_elements', tuple(SystemEnclosureContainedElement(u, self.contained_element_length) for i in range(self.contained_element_count)))
369            if self.length > (0x15 + (getattr(self, 'contained_element_count', 0) * getattr(self, 'contained_element_length', 0))):
370                self.add_field('sku_number', u.unpack_one("B"), self.fmtstr)
371        except:
372            self.decode_failure = True
373            print "Error parsing SystemEnclosure"
374            import traceback
375            traceback.print_exc()
376        self.fini()
377
378class SystemEnclosureContainedElement(unpack.Struct):
379    def __init__(self, u, length):
380        super(SystemEnclosureContainedElement, self).__init__()
381        self.start_offset = u.offset
382        self.raw_data = u.unpack_raw(length)
383        self.u = unpack.Unpackable(self.raw_data)
384        u = self.u
385        self.add_field('contained_element_type', u.unpack_one("B"))
386        type_selections = {
387            0: 'SMBIOS baseboard type enumeration',
388            1: 'SMBIOS structure type enumeration',
389        }
390        self.add_field('type_select', bitfields.getbits(self.contained_element_type, 7), unpack.format_table("contained_element_type[7]={}", type_selections))
391        self.add_field('type', bitfields.getbits(self.contained_element_type, 6, 0))
392        if self.type_select == 0:
393            self.add_field('smbios_board_type', self.type, unpack.format_table("{}", _board_types))
394        else:
395            self.add_field('smbios_structure_type', self.type)
396        self.add_field('minimum', u.unpack_one("B"))
397        self.add_field('maximum', u.unpack_one("B"))
398        if not u.at_end():
399            self.add_field('data', u.unpack_rest())
400        del self.u
401
402class ProcessorInformation(SmbiosBaseStructure):
403    smbios_structure_type = 4
404
405    def __init__(self, u, sm):
406        super(ProcessorInformation, self).__init__(u, sm)
407        u = self.u
408        try:
409            self.add_field('socket_designation', u.unpack_one("B"), self.fmtstr)
410            processor_types = {
411                0x01: 'Other',
412                0x02: 'Unknown',
413                0x03: 'Central Processor',
414                0x04: 'Math Processor',
415                0x05: 'DSP Processor',
416                0x06: 'Video Processor',
417            }
418            self.add_field('processor_type', u.unpack_one("B"), unpack.format_table("{}", processor_types))
419            self.add_field('processor_family', u.unpack_one("B"))
420            self.add_field('processor_manufacturer', u.unpack_one("B"), self.fmtstr)
421            self.add_field('processor_id', u.unpack_one("<Q"))
422            self.add_field('processor_version', u.unpack_one("B"), self.fmtstr)
423            self.add_field('voltage', u.unpack_one("B"))
424            self.add_field('external_clock', u.unpack_one("<H"))
425            self.add_field('max_speed', u.unpack_one("<H"))
426            self.add_field('current_speed', u.unpack_one("<H"))
427            self.add_field('status', u.unpack_one("B"))
428            processor_upgrades = {
429                0x01: 'Other',
430                0x02: 'Unknown',
431                0x03: 'Daughter Board',
432                0x04: 'ZIF Socket',
433                0x05: 'Replaceable Piggy Back',
434                0x06: 'None',
435                0x07: 'LIF Socket',
436                0x08: 'Slot 1',
437                0x09: 'Slot 2',
438                0x0A: '370-pin socket',
439                0x0B: 'Slot A',
440                0x0C: 'Slot M',
441                0x0D: 'Socket 423',
442                0x0E: 'Socket A (Socket 462)',
443                0x0F: 'Socket 478',
444                0x10: 'Socket 754',
445                0x11: 'Socket 940',
446                0x12: 'Socket 939',
447                0x13: 'Socket mPGA604',
448                0x14: 'Socket LGA771',
449                0x15: 'Socket LGA775',
450                0x16: 'Socket S1',
451                0x17: 'Socket AM2',
452                0x18: 'Socket F (1207)',
453                0x19: 'Socket LGA1366',
454                0x1A: 'Socket G34',
455                0x1B: 'Socket AM3',
456                0x1C: 'Socket C32',
457                0x1D: 'Socket LGA1156',
458                0x1E: 'Socket LGA1567',
459                0x1F: 'Socket PGA988A',
460                0x20: 'Socket BGA1288',
461                0x21: 'Socket rPGA988B',
462                0x22: 'Socket BGA1023',
463                0x23: 'Socket BGA1224',
464                0x24: 'Socket BGA1155',
465                0x25: 'Socket LGA1356',
466                0x26: 'Socket LGA2011',
467                0x27: 'Socket FS1',
468                0x28: 'Socket FS2',
469                0x29: 'Socket FM1',
470                0x2A: 'Socket FM2',
471            }
472            self.add_field('processor_upgrade', u.unpack_one("B"), unpack.format_table("{}", processor_upgrades))
473            if self.length > 0x1A:
474                self.add_field('l1_cache_handle', u.unpack_one("<H"))
475                self.add_field('l2_cache_handle', u.unpack_one("<H"))
476                self.add_field('l3_cache_handle', u.unpack_one("<H"))
477            if self.length > 0x20:
478                self.add_field('serial_number', u.unpack_one("B"), self.fmtstr)
479                self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr)
480                self.add_field('part_number', u.unpack_one("B"), self.fmtstr)
481            if self.length > 0x24:
482                self.add_field('core_count', u.unpack_one("B"))
483                self.add_field('core_enabled', u.unpack_one("B"))
484                self.add_field('thread_count', u.unpack_one("B"))
485                self.add_field('processor_characteristics', u.unpack_one("<H"))
486            if self.length > 0x28:
487                self.add_field('processor_family_2', u.unpack_one("<H"))
488            if self.length > 0x2A:
489                self.add_field('core_count2', u.unpack_one("<H"))
490                self.add_field('core_enabled2', u.unpack_one("<H"))
491                self.add_field('thread_count2', u.unpack_one("<H"))
492        except:
493            self.decode_failure = True
494            print "Error parsing Processor Information"
495            import traceback
496            traceback.print_exc()
497        self.fini()
498
499class MemoryControllerInformation(SmbiosBaseStructure): #obsolete starting with v2.1
500    smbios_structure_type = 5
501
502    def __init__(self, u, sm):
503        super(MemoryControllerInformation, self).__init__(u, sm)
504        u = self.u
505        try:
506            _error_detecting_method = {
507                0x01: 'Other',
508                0x02: 'Unknown',
509                0x03: 'None',
510                0x04: '8-bit Parity',
511                0x05: '32-bit ECC',
512                0x06: '64-bit ECC',
513                0x07: '128-bit ECC',
514                0x08: 'CRC'
515                }
516            self.add_field('error_detecting_method', u.unpack_one("B"), unpack.format_table("{}", _error_detecting_method))
517            self.add_field('error_correcting_capability', u.unpack_one("B"))
518            _interleaves = {
519                0x01: 'Other',
520                0x02: 'Unknown',
521                0x03: 'One-Way Interleave',
522                0x04: 'Two-Way Interleave',
523                0x05: 'Four-Way Interleave',
524                0x06: 'Eight-Way Interleave',
525                0x07: 'Sixteen-Way Interleave'
526                }
527            self.add_field('supported_interleave', u.unpack_one("B"), unpack.format_table("{}", _interleaves))
528            self.add_field('current_interleave', u.unpack_one("B"), unpack.format_table("{}", _interleaves))
529            self.add_field('max_memory_module_size', u.unpack_one("B"), self.fmtstr)
530            self.add_field('supported_speeds', u.unpack_one("<H"))
531            self.add_field('supported_memory_types', u.unpack_one("<H"))
532            self.add_field('memory_module_voltage', u.unpack_one("B"))
533            self.add_field('req_voltage_b2', bitfields.getbits(self.memory_module_voltage, 2), "memory_module_voltage[2]={}")
534            self.add_field('req_voltage_b1', bitfields.getbits(self.memory_module_voltage, 1), "memory_module_voltage[1]={}")
535            self.add_field('req_voltage_b0', bitfields.getbits(self.memory_module_voltage, 0), "memory_module_voltage[0]={}")
536            self.add_field('num_associated_memory_slots', u.unpack_one("B"))
537            self.add_field('memory_module_configuration_handles', u.unpack_one("<(self.num_associated_memory_slots)H"))
538            self.add_field('enabled_error_correcting_capabilities', u.unpack_one("B"))
539        except:
540            self.decode_failure = True
541            print "Error parsing MemoryControllerInformation"
542            import traceback
543            traceback.print_exc()
544        self.fini()
545
546class MemoryModuleInformation(SmbiosBaseStructure): #obsolete starting with v2.1
547    smbios_structure_type = 6
548
549    def __init__(self, u, sm):
550        super(MemoryModuleInformation, self).__init__(u, sm)
551        u = self.u
552        try:
553            self.add_field('socket_designation', u.unpack_one("B"), self.fmtstr)
554            self.add_field('bank_connections', u.unpack_one("B"))
555            self.add_field('current_speed', u.unpack_one("B"))
556            self.add_field('current_memory_type', u.unpack_one("<H"))
557            _mem_connection = {
558                0: 'single',
559                1: 'double-bank'
560                }
561            self.add_field('installed_mem', u.unpack_one("B"))
562            self.add_field('installed_size', bitfields.getbits(self.installed_mem, 6, 0), "installed_mem[6:0]={}")
563            self.add_field('installed_memory_module_connection', bitfields.getbits(self.installed_mem, 7), unpack.format_table("installed_mem[7]={}", _mem_connection))
564            self.add_field('enabled_mem', u.unpack_one("B"))
565            self.add_field('enabled_size', bitfields.getbits(self.installed_mem, 6, 0), "enabled_mem[6:0]={}")
566            self.add_field('enabled_memory_module_connection', bitfields.getbits(self.installed_mem, 7), unpack.format_table("enabled_mem[7]={}", _mem_connection))
567            self.add_field('error_status', u.unpack_one("B"))
568            self.add_field('error_status_info_obstained_from_event_log', bool(bitfields.getbits(self.error_status, 2)), unpack.format_table("error_status[2]={}", _mem_connection))
569            self.add_field('correctable_errors_received', bool(bitfields.getbits(self.error_status, 1)), unpack.format_table("error_status[1]={}", _mem_connection))
570            self.add_field('uncorrectable_errors_received', bool(bitfields.getbits(self.error_status, 0)), unpack.format_table("error_status[0]={}", _mem_connection))
571        except:
572            self.decode_failure = True
573            print "Error parsing MemoryModuleInformation"
574            import traceback
575            traceback.print_exc()
576        self.fini()
577
578class CacheInformation(SmbiosBaseStructure):
579    smbios_structure_type = 7
580
581    def __init__(self, u, sm):
582        super(CacheInformation, self).__init__(u, sm)
583        u = self.u
584        try:
585            self.add_field('socket_designation', u.unpack_one("B"), self.fmtstr)
586            processor_types = {
587                0x01: 'Other',
588                0x02: 'Unknown',
589                0x03: 'Central Processor',
590                0x04: 'Math Processor',
591                0x05: 'DSP Processor',
592                0x06: 'Video Processor',
593            }
594            self.add_field('cache_configuration', u.unpack_one("<H"))
595            _operational_mode = {
596                0b00: 'Write Through',
597                0b01: 'Write Back',
598                0b10: 'Varies with Memory Address',
599                0b11: 'Unknown'
600                }
601            self.add_field('operational_mode', bitfields.getbits(self.cache_configuration, 9, 8), unpack.format_table("cache_configuration[9:8]={}", _operational_mode))
602            self.add_field('enabled_at_boot_time', bool(bitfields.getbits(self.cache_configuration, 7)), "cache_configuration[7]={}")
603            _location = {
604                0b00: 'Internal',
605                0b01: 'External',
606                0b10: 'Reserved',
607                0b11: 'Unknown'
608                }
609            self.add_field('location_relative_to_cpu_module', bitfields.getbits(self.cache_configuration, 6, 5), unpack.format_table("cache_configuration[6:5]={}", _location))
610            self.add_field('cache_socketed', bool(bitfields.getbits(self.cache_configuration, 3)), "cache_configuration[3]={}")
611            self.add_field('cache_level', bitfields.getbits(self.cache_configuration, 2, 0), "cache_configuration[2:0]={}")
612            self.add_field('max_cache_size', u.unpack_one("<H"))
613            _granularity = {
614                0: '1K granularity',
615                1: '64K granularity'
616                }
617            self.add_field('max_granularity', bitfields.getbits(self.cache_configuration, 15), unpack.format_table("max_cache_size[15]={}", _granularity))
618            self.add_field('max_size_in_granularity', bitfields.getbits(self.cache_configuration, 14, 0), "max_cache_size[14, 0]={}")
619            self.add_field('installed_size', u.unpack_one("<H"))
620            if self.installed_size != 0:
621                self.add_field('installed_granularity', bitfields.getbits(self.cache_configuration, 15), unpack.format_table("installed_size[15]={}", _granularity))
622                self.add_field('installed_size_in_granularity', bitfields.getbits(self.cache_configuration, 14, 0), "installed_size[14, 0]={}")
623            self.add_field('supported_sram_type', u.unpack_one("<H"))
624            self.add_field('current_sram_type', u.unpack_one("<H"))
625            if self.length > 0x0F:
626                self.add_field('cache_speed', u.unpack_one("B"))
627            if self.length > 0x10:
628                _error_correction = {
629                    0x01: 'Other',
630                    0x02: 'Unknown',
631                    0x03: 'None',
632                    0x04: 'Parity',
633                    0x05: 'Single-bit ECC',
634                    0x06: 'Multi-bit ECC'
635                    }
636                self.add_field('error_correction', u.unpack_one("B"), unpack.format_table("{}", _error_correction))
637            if self.length > 0x10:
638                _system_cache_type = {
639                    0x01: 'Other',
640                    0x02: 'Unknown',
641                    0x03: 'Instruction',
642                    0x04: 'Data',
643                    0x05: 'Unified'
644                    }
645                self.add_field('system_cache_type', u.unpack_one("B"), unpack.format_table("{}", _system_cache_type))
646            if self.length > 0x12:
647                _associativity = {
648                    0x01: 'Other',
649                    0x02: 'Unknown',
650                    0x03: 'Direct Mapped',
651                    0x04: '2-way Set-Associative',
652                    0x05: '4-way Set-Associative',
653                    0x06: 'Fully Associative',
654                    0x07: '8-way Set-Associative',
655                    0x08: '16-way Set-Associative',
656                    0x09: '12-way Set-Associative',
657                    0x0A: '24-way Set-Associative',
658                    0x0B: '32-way Set-Associative',
659                    0x0C: '48-way Set-Associative',
660                    0x0D: '64-way Set-Associative',
661                    0x0E: '20-way Set-Associative'
662                    }
663                self.add_field('associativity', u.unpack_one("B"), unpack.format_table("{}", _associativity))
664
665        except:
666            self.decode_failure = True
667            print "Error parsing CacheInformation"
668            import traceback
669            traceback.print_exc()
670        self.fini()
671
672class PortConnectorInfo(SmbiosBaseStructure):
673    smbios_structure_type = 8
674
675    def __init__(self, u, sm):
676        super(PortConnectorInfo, self).__init__(u, sm)
677        u = self.u
678        try:
679            self.add_field('internal_reference_designator', u.unpack_one("B"), self.fmtstr)
680            connector_types = {
681                0x00: 'None',
682                0x01: 'Centronics',
683                0x02: 'Mini Centronics',
684                0x03: 'Proprietary',
685                0x04: 'DB-25 pin male',
686                0x05: 'DB-25 pin female',
687                0x06: 'DB-15 pin male',
688                0x07: 'DB-15 pin female',
689                0x08: 'DB-9 pin male',
690                0x09: 'DB-9 pin female',
691                0x0A: 'RJ-11',
692                0x0B: 'RJ-45',
693                0x0C: '50-pin MiniSCSI',
694                0x0D: 'Mini-DIN',
695                0x0E: 'Micro-DIN',
696                0x0F: 'PS/2',
697                0x10: 'Infrared',
698                0x11: 'HP-HIL',
699                0x12: 'Access Bus (USB)',
700                0x13: 'SSA SCSI',
701                0x14: 'Circular DIN-8 male',
702                0x15: 'Circular DIN-8 female',
703                0x16: 'On Board IDE',
704                0x17: 'On Board Floppy',
705                0x18: '9-pin Dual Inline (pin 10 cut)',
706                0x19: '25-pin Dual Inline (pin 26 cut)',
707                0x1A: '50-pin Dual Inline',
708                0x1B: '68-pin Dual Inline',
709                0x1C: 'On Board Sound Input from CD-ROM',
710                0x1D: 'Mini-Centronics Type-14',
711                0x1E: 'Mini-Centronics Type-26',
712                0x1F: 'Mini-jack (headphones)',
713                0x20: 'BNC',
714                0x21: '1394',
715                0x22: 'SAS/SATA Plug Receptacle',
716                0xA0: 'PC-98',
717                0xA1: 'PC-98Hireso',
718                0xA2: 'PC-H98',
719                0xA3: 'PC-98Note',
720                0xA4: 'PC-98Full',
721                0xFF: 'Other',
722            }
723            self.add_field('internal_connector_type', u.unpack_one("B"), unpack.format_table("{}", connector_types))
724            self.add_field('external_reference_designator', u.unpack_one("B"), self.fmtstr)
725            self.add_field('external_connector_type', u.unpack_one("B"), unpack.format_table("{}", connector_types))
726            port_types = {
727                0x00: 'None',
728                0x01: 'Parallel Port XT/AT Compatible',
729                0x02: 'Parallel Port PS/2',
730                0x03: 'Parallel Port ECP',
731                0x04: 'Parallel Port EPP',
732                0x05: 'Parallel Port ECP/EPP',
733                0x06: 'Serial Port XT/AT Compatible',
734                0x07: 'Serial Port 16450 Compatible',
735                0x08: 'Serial Port 16550 Compatible',
736                0x09: 'Serial Port 16550A Compatible',
737                0x0A: 'SCSI Port',
738                0x0B: 'MIDI Port',
739                0x0C: 'Joy Stick Port',
740                0x0D: 'Keyboard Port',
741                0x0E: 'Mouse Port',
742                0x0F: 'SSA SCSI',
743                0x10: 'USB',
744                0x11: 'FireWire (IEEE P1394)',
745                0x12: 'PCMCIA Type I2',
746                0x13: 'PCMCIA Type II',
747                0x14: 'PCMCIA Type III',
748                0x15: 'Cardbus',
749                0x16: 'Access Bus Port',
750                0x17: 'SCSI II',
751                0x18: 'SCSI Wide',
752                0x19: 'PC-98',
753                0x1A: 'PC-98-Hireso',
754                0x1B: 'PC-H98',
755                0x1C: 'Video Port',
756                0x1D: 'Audio Port',
757                0x1E: 'Modem Port',
758                0x1F: 'Network Port',
759                0x20: 'SATA',
760                0x21: 'SAS',
761                0xA0: '8251 Compatible',
762                0xA1: '8251 FIFO Compatible',
763                0xFF: 'Other',
764            }
765            self.add_field('port_type', u.unpack_one("B"), unpack.format_table("{}", port_types))
766        except:
767            self.decodeFailure = True
768            print "Error parsing PortConnectorInfo"
769            import traceback
770            traceback.print_exc()
771        self.fini()
772
773class SystemSlots(SmbiosBaseStructure):
774    smbios_structure_type = 9
775
776    def __init__(self, u, sm):
777        super(SystemSlots, self).__init__(u, sm)
778        u = self.u
779        try:
780            self.add_field('designation', u.unpack_one("B"), self.fmtstr)
781            _slot_types = {
782                0x01: 'Other',
783                0x02: 'Unknown',
784                0x03: 'ISA',
785                0x04: 'MCA',
786                0x05: 'EISA',
787                0x06: 'PCI',
788                0x07: 'PC Card (PCMCIA)',
789                0x08: 'VL-VESA',
790                0x09: 'Proprietary',
791                0x0A: 'Processor Card Slot',
792                0x0B: 'Proprietary Memory Card Slot',
793                0x0C: 'I/O Riser Card Slot',
794                0x0D: 'NuBus',
795                0x0E: 'PCI 66MHz Capable',
796                0x0F: 'AGP',
797                0x10: 'AGP 2X',
798                0x11: 'AGP 4X',
799                0x12: 'PCI-X',
800                0x13: 'AGP 8X',
801                0xA0: 'PC-98/C20',
802                0xA1: 'PC-98/C24',
803                0xA2: 'PC-98/E',
804                0xA3: 'PC-98/Local Bus',
805                0xA4: 'PC-98/Card',
806                0xA5: 'PCI Express',
807                0xA6: 'PCI Express x1',
808                0xA7: 'PCI Express x2',
809                0xA8: 'PCI Express x4',
810                0xA9: 'PCI Express x8',
811                0xAA: 'PCI Express x16',
812                0xAB: 'PCI Express Gen 2',
813                0xAC: 'PCI Express Gen 2 x1',
814                0xAD: 'PCI Express Gen 2 x2',
815                0xAE: 'PCI Express Gen 2 x4',
816                0xAF: 'PCI Express Gen 2 x8',
817                0xB0: 'PCI Express Gen 2 x16',
818                0xB1: 'PCI Express Gen 3',
819                0xB2: 'PCI Express Gen 3 x1',
820                0xB3: 'PCI Express Gen 3 x2',
821                0xB4: 'PCI Express Gen 3 x4',
822                0xB5: 'PCI Express Gen 3 x8',
823                0xB6: 'PCI Express Gen 3 x16',
824            }
825            self.add_field('slot_type', u.unpack_one("B"), unpack.format_table("{}", _slot_types))
826            _slot_data_bus_widths = {
827                0x01: 'Other',
828                0x02: 'Unknown',
829                0x03: '8 bit',
830                0x04: '16 bit',
831                0x05: '32 bit',
832                0x06: '64 bit',
833                0x07: '128 bit',
834                0x08: '1x or x1',
835                0x09: '2x or x2',
836                0x0A: '4x or x4',
837                0x0B: '8x or x8',
838                0x0C: '12x or x12',
839                0x0D: '16x or x16',
840                0x0E: '32x or x32',
841            }
842            self.add_field('slot_data_bus_width', u.unpack_one('B'), unpack.format_table("{}", _slot_data_bus_widths))
843            _current_usages = {
844                0x01: 'Other',
845                0x02: 'Unknown',
846                0x03: 'Available',
847                0x04: 'In use',
848            }
849            self.add_field('current_usage', u.unpack_one('B'), unpack.format_table("{}", _current_usages))
850            _slot_lengths = {
851                0x01: 'Other',
852                0x02: 'Unknown',
853                0x03: 'Short Length',
854                0x04: 'Long Length',
855            }
856            self.add_field('slot_length', u.unpack_one('B'), unpack.format_table("{}", _slot_lengths))
857            self.add_field('slot_id', u.unpack_one('<H'))
858            self.add_field('characteristics1', u.unpack_one('B'))
859            self.add_field('characteristics_unknown', bool(bitfields.getbits(self.characteristics1, 0)), "characteristics1[0]={}")
860            self.add_field('provides_5_0_volts', bool(bitfields.getbits(self.characteristics1, 1)), "characteristics1[1]={}")
861            self.add_field('provides_3_3_volts', bool(bitfields.getbits(self.characteristics1, 2)), "characteristics1[2]={}")
862            self.add_field('shared_slot', bool(bitfields.getbits(self.characteristics1, 3)), "characteristics1[3]={}")
863            self.add_field('supports_pc_card_16', bool(bitfields.getbits(self.characteristics1, 4)), "characteristics1[4]={}")
864            self.add_field('supports_cardbus', bool(bitfields.getbits(self.characteristics1, 5)), "characteristics1[5]={}")
865            self.add_field('supports_zoom_video', bool(bitfields.getbits(self.characteristics1, 6)), "characteristics1[6]={}")
866            self.add_field('supports_modem_ring_resume', bool(bitfields.getbits(self.characteristics1, 7)), "characteristics1[7]={}")
867            if self.length > 0x0C:
868                self.add_field('characteristics2', u.unpack_one('B'))
869                self.add_field('supports_PME', bool(bitfields.getbits(self.characteristics2, 0)), "characteristics2[0]={}")
870                self.add_field('supports_hot_plug', bool(bitfields.getbits(self.characteristics2, 1)), "characteristics2[1]={}")
871                self.add_field('supports_smbus', bool(bitfields.getbits(self.characteristics2, 2)), "characteristics2[2]={}")
872            if self.length > 0x0D:
873                self.add_field('segment_group_number', u.unpack_one('<H'))
874                self.add_field('bus_number', u.unpack_one('B'))
875                self.add_field('device_function_number', u.unpack_one('B'))
876                self.add_field('device_number', bitfields.getbits(self.device_function_number, 7, 3), "device_function_number[7:3]={}")
877                self.add_field('function_number', bitfields.getbits(self.device_function_number, 2, 0), "device_function_number[2:0]={}")
878        except:
879            self.decodeFailure = True
880            print "Error parsing SystemSlots"
881            import traceback
882            traceback.print_exc()
883        self.fini()
884
885class OnBoardDevicesInformation(SmbiosBaseStructure):
886    smbios_structure_type = 10
887
888    def __init__(self, u, sm):
889        super(OnBoardDevicesInformation, self).__init__(u, sm)
890        u = self.u
891        try:
892            self.add_field('device_type', u.unpack_one("B"))
893            self.add_field('device_enabled', bool(bitfields.getbits(self.device_type, 7)), "device_type[7]={}")
894            _device_types = {
895                0x01: 'Other',
896                0x02: 'Unknown',
897                0x03: 'Video',
898                0x04: 'SCSI Controller',
899                0x05: 'Ethernet',
900                0x06: 'Token Ring',
901                0x07: 'Sound',
902                0x08: 'PATA Controller',
903                0x09: 'SATA Controller',
904                0x0A: 'SAS Controller'
905            }
906            self.add_field('type_of_device', bitfields.getbits(self.device_type, 6, 0), unpack.format_table("device_type[6:0]={}", _device_types))
907            self.add_field('description_string', u.unpack_one("B"), self.fmtstr)
908        except:
909            self.decodeFailure = True
910            print "Error parsing OnBoardDevicesInformation"
911            import traceback
912            traceback.print_exc()
913        self.fini()
914
915class OEMStrings(SmbiosBaseStructure):
916    smbios_structure_type = 11
917
918    def __init__(self, u, sm):
919        super(OEMStrings, self).__init__(u, sm)
920        u = self.u
921        try:
922            self.add_field('count', u.unpack_one("B"))
923        except:
924            self.decodeFailure = True
925            print "Error parsing OEMStrings"
926            import traceback
927            traceback.print_exc()
928        self.fini()
929
930class SystemConfigOptions(SmbiosBaseStructure):
931    smbios_structure_type = 12
932
933    def __init__(self, u, sm):
934        super(SystemConfigOptions, self).__init__(u, sm)
935        u = self.u
936        try:
937            self.add_field('count', u.unpack_one("B"))
938        except:
939            self.decodeFailure = True
940            print "Error parsing SystemConfigOptions"
941            import traceback
942            traceback.print_exc()
943        self.fini()
944
945class BIOSLanguageInformation(SmbiosBaseStructure):
946    smbios_structure_type = 13
947
948    def __init__(self, u, sm):
949        super(BIOSLanguageInformation, self).__init__(u, sm)
950        u = self.u
951        try:
952            self.add_field('installable_languages', u.unpack_one("B"))
953            if self.length > 0x05:
954                self.add_field('flags', u.unpack_one('B'))
955                self.add_field('abbreviated_format', bool(bitfields.getbits(self.flags, 0)), "flags[0]={}")
956            if self.length > 0x6:
957                u.skip(15)
958                self.add_field('current_language', u.unpack_one('B'), self.fmtstr)
959        except:
960            self.decodeFailure = True
961            print "Error parsing BIOSLanguageInformation"
962            import traceback
963            traceback.print_exc()
964        self.fini()
965
966class GroupAssociations(SmbiosBaseStructure):
967    smbios_structure_type = 14
968
969    def __init__(self, u, sm):
970        super(GroupAssociations, self).__init__(u, sm)
971        u = self.u
972        try:
973            self.add_field('group_name', u.unpack_one("B"), self.fmtstr)
974            self.add_field('item_type', u.unpack_one('B'))
975            self.add_field('item_handle', u.unpack_one('<H'))
976        except:
977            self.decodeFailure = True
978            print "Error parsing GroupAssociations"
979            import traceback
980            traceback.print_exc()
981        self.fini()
982
983class SystemEventLog(SmbiosBaseStructure):
984    smbios_structure_type = 15
985
986    def __init__(self, u, sm):
987        super(SystemEventLog, self).__init__(u, sm)
988        u = self.u
989        try:
990            self.add_field('log_area_length', u.unpack_one("<H"))
991            self.add_field('log_header_start_offset', u.unpack_one('<H'))
992            self.add_field('log_data_start_offset', u.unpack_one('<H'))
993            _access_method = {
994                0x00: 'Indexed I/O: 1 8-bit index port, 1 8-bit data port',
995                0x01: 'Indexed I/O: 2 8-bit index ports, 1 8-bit data port',
996                0x02: 'Indexed I/O: 1 16-bit index port, 1 8-bit data port',
997                0x03: 'Memory-mapped physical 32-bit address',
998                0x04: 'Available through General-Purpose NonVolatile Data functions',
999                xrange(0x05, 0x07F): 'Available for future assignment',
1000                xrange(0x80, 0xFF): 'BIOS Vendor/OEM-specific'
1001                }
1002            self.add_field('access_method', u.unpack_one('B'), unpack.format_table("{}", _access_method))
1003            self.add_field('log_status', u.unpack_one('B'))
1004            self.add_field('log_area_full', bool(bitfields.getbits(self.log_status, 1)), "log_status[1]={}")
1005            self.add_field('log_area_valid', bool(bitfields.getbits(self.log_status, 0)), "log_status[0]={}")
1006            self.add_field('log_change_token', u.unpack_one('<I'))
1007            self.add_field('access_method_address', u.unpack_one('<I'))
1008            if self.length > 0x14:
1009                _log_header_formats = {
1010                    0: 'No header',
1011                    1: 'Type 1 log header',
1012                    xrange(2, 0x7f): 'Available for future assignment',
1013                    xrange(0x80, 0xff): 'BIOS vendor or OEM-specific format'
1014                    }
1015                self.add_field('log_header_format', u.unpack_one("B"), unpack.format_table("{}", _log_header_formats))
1016            if self.length > 0x15:
1017                self.add_field('num_supported_log_type_descriptors', u.unpack_one('B'))
1018            if self.length > 0x16:
1019                self.add_field('length_log_type_descriptor', u.unpack_one('B'))
1020            if self.length != (0x17 + (self.num_supported_log_type_descriptors * self.length_log_type_descriptor)):
1021                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)
1022                print "structure length = {}".format(self.length)
1023                print "num_supported_log_type_descriptors = {}".format(self.num_supported_log_type_descriptors)
1024                print "length_log_type_descriptor = {}".format(self.length_log_type_descriptor)
1025                self.decodeFailure = True
1026            self.add_field('descriptors', tuple(EventLogDescriptor.unpack(u) for i in range(self.num_supported_log_type_descriptors)), unpack.format_each("\n{!r}"))
1027        except:
1028            self.decodeFailure = True
1029            print "Error parsing SystemEventLog"
1030            import traceback
1031            traceback.print_exc()
1032        self.fini()
1033
1034class EventLogDescriptor(unpack.Struct):
1035    @staticmethod
1036    def _unpack(u):
1037        _event_log_type_descriptors = {
1038            0x00: 'Reserved',
1039            0x01: 'Single-bit ECC memory error',
1040            0x02: 'Multi-bit ECC memory error',
1041            0x03: 'Parity memory error',
1042            0x04: 'Bus time-out',
1043            0x05: 'I/O Channel Check',
1044            0x06: 'Software NMI',
1045            0x07: 'POST Memory Resize',
1046            0x08: 'POST Error',
1047            0x09: 'PCI Parity Error',
1048            0x0A: 'PCI System Error',
1049            0x0B: 'CPU Failure',
1050            0x0C: 'EISA FailSafe Timer time-out',
1051            0x0D: 'Correctable memory log disabled',
1052            0x0E: 'Logging disabled for a specific Event Type - too many errors of the same type received in a short amount of time',
1053            0x0F: 'Reserved',
1054            0x10: 'System Limit Exceeded',
1055            0x11: 'Asynchronous hardware timer expired and issued a system reset',
1056            0x12: 'System configuration information',
1057            0x13: 'Hard-disk information',
1058            0x14: 'System reconfigured',
1059            0x15: 'Uncorrectable CPU-complex error',
1060            0x16: 'Log Area Reset/Cleared',
1061            0x17: 'System boot',
1062            xrange(0x18, 0x7F): 'Unused, available for assignment',
1063            xrange(0x80, 0xFE): 'Availalbe for system- and OEM-specific assignments',
1064            0xFF: 'End of log'
1065        }
1066        yield 'log_type', u.unpack_one('B'), unpack.format_table("{}", _event_log_type_descriptors)
1067        _event_log_format = {
1068            0x00: 'None',
1069            0x01: 'Handle',
1070            0x02: 'Multiple-Event',
1071            0x03: 'Multiple-Event Handle',
1072            0x04: 'POST Results Bitmap',
1073            0x05: 'System Management Type',
1074            0x06: 'Multiple-Event System Management Type',
1075            xrange(0x80, 0xFF): 'OEM assigned'
1076        }
1077        yield 'variable_data_format_type', u.unpack_one('B'), unpack.format_table("{}", _event_log_format)
1078
1079class PhysicalMemoryArray(SmbiosBaseStructure):
1080    smbios_structure_type = 16
1081
1082    def __init__(self, u, sm):
1083        super(PhysicalMemoryArray, self).__init__(u, sm)
1084        u = self.u
1085        try:
1086            if self.length > 0x4:
1087                _location_field = {
1088                    0x01: "Other",
1089                    0x02: "Unknown",
1090                    0x03: "System board or motherboard",
1091                    0x04: "ISA add-on card",
1092                    0x05: "EISA add-on card",
1093                    0x06: "PCI add-on card",
1094                    0x07: "MCA add-on card",
1095                    0x08: "PCMCIA add-on card",
1096                    0x09: "Proprietary add-on card",
1097                    0x0A: "NuBus",
1098                    0xA0: "PC-98/C20 add-on card",
1099                    0xA1: "PC-98/C24 add-on card",
1100                    0xA2: "PC-98/E add-on card",
1101                    0xA3: "PC-98/Local bus add-on card"
1102                    }
1103                self.add_field('location', u.unpack_one("B"), unpack.format_table("{}", _location_field))
1104            if self.length > 0x05:
1105                _use = {
1106                    0x01: "Other",
1107                    0x02: "Unknown",
1108                    0x03: "System memory",
1109                    0x04: "Video memory",
1110                    0x05: "Flash memory",
1111                    0x06: "Non-volatile RAM",
1112                    0x07: "Cache memory"
1113                    }
1114                self.add_field('use', u.unpack_one('B'), unpack.format_table("{}", _use))
1115            if self.length > 0x06:
1116                _error_correction = {
1117                    0x01: "Other",
1118                    0x02: "Unknown",
1119                    0x03: "None",
1120                    0x04: "Parity",
1121                    0x05: "Single-bit ECC",
1122                    0x06: "Multi-bit ECC",
1123                    0x07: "CRC"
1124                    }
1125                self.add_field('memory_error_correction', u.unpack_one('B'), unpack.format_table("{}", _error_correction))
1126            if self.length > 0x07:
1127                self.add_field('maximum_capacity', u.unpack_one('<I'))
1128            if self.length > 0x0B:
1129                self.add_field('memory_error_information_handle', u.unpack_one('<H'))
1130            if self.length > 0x0D:
1131                self.add_field('num_memory_devices', u.unpack_one('<H'))
1132            if self.length > 0x0F:
1133                self.add_field('extended_maximum_capacity', u.unpack_one('<Q'))
1134        except:
1135            self.decodeFailure = True
1136            print "Error parsing PhysicalMemoryArray"
1137            import traceback
1138            traceback.print_exc()
1139        self.fini()
1140
1141class MemoryDevice(SmbiosBaseStructure):
1142    smbios_structure_type = 17
1143
1144    def __init__(self, u, sm):
1145        super(MemoryDevice, self).__init__(u, sm)
1146        u = self.u
1147        try:
1148            if self.length > 0x4:
1149                self.add_field('physical_memory_array_handle', u.unpack_one("<H"))
1150            if self.length > 0x6:
1151                self.add_field('memory_error_information_handle', u.unpack_one("<H"))
1152            if self.length > 0x8:
1153                self.add_field('total_width', u.unpack_one("<H"))
1154            if self.length > 0xA:
1155                self.add_field('data_width', u.unpack_one("<H"))
1156            if self.length > 0xC:
1157                self.add_field('size', u.unpack_one("<H"))
1158            if self.length > 0xE:
1159                _form_factors = {
1160                    0x01: 'Other',
1161                    0x02: 'Unknown',
1162                    0x03: 'SIMM',
1163                    0x04: 'SIP',
1164                    0x05: 'Chip',
1165                    0x06: 'DIP',
1166                    0x07: 'ZIP',
1167                    0x08: 'Proprietary Card',
1168                    0x09: 'DIMM',
1169                    0x0A: 'TSOP',
1170                    0x0B: 'Row of chips',
1171                    0x0C: 'RIMM',
1172                    0x0D: 'SODIMM',
1173                    0x0E: 'SRIMM',
1174                    0x0F: 'FB-DIMM'
1175                    }
1176                self.add_field('form_factor', u.unpack_one("B"), unpack.format_table("{}", _form_factors))
1177            if self.length > 0xF:
1178                self.add_field('device_set', u.unpack_one("B"))
1179            if self.length > 0x10:
1180                self.add_field('device_locator', u.unpack_one("B"), self.fmtstr)
1181            if self.length > 0x11:
1182                self.add_field('bank_locator', u.unpack_one("B"), self.fmtstr)
1183            if self.length > 0x12:
1184                _memory_types = {
1185                    0x01: 'Other',
1186                    0x02: 'Unknown',
1187                    0x03: 'DRAM',
1188                    0x04: 'EDRAM',
1189                    0x05: 'VRAM',
1190                    0x06: 'SRAM',
1191                    0x07: 'RAM',
1192                    0x08: 'ROM',
1193                    0x09: 'FLASH',
1194                    0x0A: 'EEPROM',
1195                    0x0B: 'FEPROM',
1196                    0x0C: 'EPROM',
1197                    0x0D: 'CDRAM',
1198                    0x0E: '3DRAM',
1199                    0x0F: 'SDRAM',
1200                    0x10: 'SGRAM',
1201                    0x11: 'RDRAM',
1202                    0x12: 'DDR',
1203                    0x13: 'DDR2',
1204                    0x14: 'DDR2 FB-DIMM',
1205                    xrange(0x15, 0x17): 'Reserved',
1206                    0x18: 'DDR3',
1207                    0x19: 'FBD2'
1208                    }
1209                self.add_field('memory_type', u.unpack_one("B"), unpack.format_table("{}", _memory_types))
1210            if self.length > 0x13:
1211                self.add_field('type_detail', u.unpack_one('<H'))
1212            if self.length > 0x15:
1213                self.add_field('speed', u.unpack_one("<H"))
1214            if self.length > 0x17:
1215                self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr)
1216            if self.length > 0x18:
1217                self.add_field('serial_number', u.unpack_one("B"), self.fmtstr)
1218            if self.length > 0x19:
1219                self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr)
1220            if self.length > 0x1A:
1221                self.add_field('part_number', u.unpack_one("B"), self.fmtstr)
1222            if self.length > 0x1B:
1223                self.add_field('attributes', u.unpack_one("B"))
1224                self.add_field('rank', bitfields.getbits(self.attributes, 3, 0), "attributes[3:0]={}")
1225            if self.length > 0x1C:
1226                if self.size == 0x7FFF:
1227                    self.add_field('extended_size', u.unpack_one('<I'))
1228                    self.add_field('mem_size', bitfields.getbits(self.type_detail, 30, 0), "type_detail[30:0]={}")
1229                else:
1230                    u.skip(4)
1231            if self.length > 0x20:
1232                self.add_field('configured_memory_clock_speed', u.unpack_one("<H"))
1233            if self.length > 0x22:
1234                self.add_field('minimum_voltage', u.unpack_one("<H"))
1235            if self.length > 0x24:
1236                self.add_field('maximum_voltage', u.unpack_one("<H"))
1237            if self.length > 0x26:
1238                self.add_field('configured_voltage', u.unpack_one("<H"))
1239        except:
1240            self.decodeFailure = True
1241            print "Error parsing MemoryDevice"
1242            import traceback
1243            traceback.print_exc()
1244        self.fini()
1245
1246class MemoryErrorInfo32Bit(SmbiosBaseStructure):
1247    smbios_structure_type = 18
1248
1249    def __init__(self, u, sm):
1250        super(MemoryErrorInfo32Bit, self).__init__(u, sm)
1251        u = self.u
1252        try:
1253            if self.length > 0x4:
1254                _error_types = {
1255                    0x01: 'Other',
1256                    0x02: 'Unknown',
1257                    0x03: 'OK',
1258                    0x04: 'Bad read',
1259                    0x05: 'Parity error',
1260                    0x06: 'Single-bit error',
1261                    0x07: 'Double-bit error',
1262                    0x08: 'Multi-bit error',
1263                    0x09: 'Nibble error',
1264                    0x0A: 'Checksum error',
1265                    0x0B: 'CRC error',
1266                    0x0C: 'Corrected single-bit error',
1267                    0x0D: 'Corrected error',
1268                    0x0E: 'Uncorrectable error'
1269                    }
1270                self.add_field('error_type', u.unpack_one("B"), unpack.format_table("{}", _error_types))
1271            if self.length > 0x5:
1272                 _error_granularity_field = {
1273                    0x01: 'Other',
1274                    0x02: 'Unknown',
1275                    0x03: 'Device level',
1276                    0x04: 'Memory partition level'
1277                    }
1278                 self.add_field('error_granularity', u.unpack_one("B"), unpack.format_table("{}", _error_granularity_field))
1279            if self.length > 0x6:
1280                _error_operation_field = {
1281                    0x01: 'Other',
1282                    0x02: 'Unknown',
1283                    0x03: 'Read',
1284                    0x04: 'Write',
1285                    0x05: 'Partial write'
1286                    }
1287                self.add_field('error_operation', u.unpack_one("B"), unpack.format_table("{}", _error_operation_field))
1288            if self.length > 0x7:
1289                self.add_field('vendor_syndrome', u.unpack_one("<I"))
1290            if self.length > 0xB:
1291                self.add_field('memory_array_error_address', u.unpack_one("<I"))
1292            if self.length > 0xF:
1293                self.add_field('device_error_address', u.unpack_one("<I"))
1294            if self.length > 0x13:
1295                self.add_field('error_resolution', u.unpack_one("<I"))
1296        except:
1297            self.decodeFailure = True
1298            print "Error parsing MemoryErrorInfo32Bit"
1299            import traceback
1300            traceback.print_exc()
1301        self.fini()
1302
1303class MemoryArrayMappedAddress(SmbiosBaseStructure):
1304    smbios_structure_type = 19
1305
1306    def __init__(self, u, sm):
1307        super(MemoryArrayMappedAddress, self).__init__(u, sm)
1308        u = self.u
1309        try:
1310            if self.length > 0x4:
1311                self.add_field('starting_address', u.unpack_one("<I"))
1312                # if FFFF FFFF: address stored in Extended Starting Address
1313            if self.length > 0x8:
1314                self.add_field('ending_address', u.unpack_one("<I"))
1315            if self.length > 0xC:
1316                self.add_field('memory_array_handle', u.unpack_one("<H"))
1317            if self.length > 0xE:
1318                self.add_field('partition_width', u.unpack_one("B"))
1319            if self.length > 0xF:
1320                # valid if starting_address = FFFF FFFF
1321                if self.starting_address == 0xFFFFFFFF:
1322                    self.add_field('extended_starting_address', u.unpack_one("<Q"))
1323                    if self.length > 0x17:
1324                        self.add_field('extended_ending_address', u.unpack_one("<Q"))
1325                else:
1326                    u.skip(16)
1327
1328        except:
1329            self.decodeFailure = True
1330            print "Error parsing MemoryArrayMappedAddress"
1331            import traceback
1332            traceback.print_exc()
1333        self.fini()
1334
1335class MemoryDeviceMappedAddress(SmbiosBaseStructure):
1336    smbios_structure_type = 20
1337
1338    def __init__(self, u, sm):
1339        super(MemoryDeviceMappedAddress, self).__init__(u, sm)
1340        u = self.u
1341        try:
1342            if self.length > 0x4:
1343                self.add_field('starting_address', u.unpack_one("<I"))
1344                # if FFFF FFFF: address stored in Extended Starting Address
1345            if self.length > 0x8:
1346                self.add_field('ending_address', u.unpack_one("<I"))
1347            if self.length > 0xC:
1348                self.add_field('memory_device_handle', u.unpack_one("<H"))
1349            if self.length > 0xE:
1350                self.add_field('memory_array_mapped_address_handle', u.unpack_one("<H"))
1351            if self.length > 0x10:
1352                self.add_field('partition_row_position', u.unpack_one("B"))
1353            if self.length > 0x11:
1354                self.add_field('interleave_position', u.unpack_one("B"))
1355            if self.length > 0x12:
1356                self.add_field('interleave_data_depth', u.unpack_one("B"))
1357            if self.length > 0x13:
1358                # valid if starting_address = FFFF FFFF
1359                if self.starting_address == 0xFFFFFFFF:
1360                    self.add_field('extended_starting_address', u.unpack_one("<Q"))
1361                    if self.length > 0x1B:
1362                        self.add_field('extended_ending_address', u.unpack_one("<Q"))
1363                else:
1364                    u.skip(16)
1365        except:
1366            self.decodeFailure = True
1367            print "Error parsing MemoryDeviceMappedAddress"
1368            import traceback
1369            traceback.print_exc()
1370        self.fini()
1371
1372class BuiltInPointingDevice(SmbiosBaseStructure):
1373    smbios_structure_type = 21
1374
1375    def __init__(self, u, sm):
1376        super(BuiltInPointingDevice, self).__init__(u, sm)
1377        u = self.u
1378        try:
1379            if self.length > 0x4:
1380                _pointing_device_types = {
1381                    0x01: 'Other',
1382                    0x02: 'Unknown',
1383                    0x03: 'Mouse',
1384                    0x04: 'Track Ball',
1385                    0x05: 'Track Point',
1386                    0x06: 'Glide Point',
1387                    0x07: 'Touch Pad',
1388                    0x08: 'Touch Screen',
1389                    0x09: 'Optical Sensor'
1390                    }
1391                self.add_field('pointing_device_type', u.unpack_one("B"), unpack.format_table("{}", _pointing_device_types))
1392            if self.length > 0x5:
1393                _interfaces = {
1394                    0x01: 'Other',
1395                    0x02: 'Unknown',
1396                    0x03: 'Serial',
1397                    0x04: 'PS/2',
1398                    0x05: 'Infared',
1399                    0x06: 'HP-HIL',
1400                    0x07: 'Bus mouse',
1401                    0x08: 'ADB (Apple Desktop Bus)',
1402                    0x09: 'Bus mouse DB-9',
1403                    0x0A: 'Bus mouse micro-DIN',
1404                    0x0B: 'USB'
1405                    }
1406                self.add_field('interface', u.unpack_one("B"), unpack.format_table("{}", _interfaces))
1407            if self.length > 0x6:
1408                self.add_field('num_buttons', u.unpack_one("B"))
1409        except:
1410            self.decodeFailure = True
1411            print "Error parsing BuiltInPointingDevice"
1412            import traceback
1413            traceback.print_exc()
1414        self.fini()
1415
1416class PortableBattery(SmbiosBaseStructure):
1417    smbios_structure_type = 22
1418
1419    def __init__(self, u, sm):
1420        super(PortableBattery, self).__init__(u, sm)
1421        u = self.u
1422        try:
1423            if self.length > 0x4:
1424                self.add_field('location', u.unpack_one("B"), self.fmtstr)
1425            if self.length > 0x5:
1426                self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr)
1427            if self.length > 0x6:
1428                self.add_field('manufacturer_date', u.unpack_one("B"), self.fmtstr)
1429            if self.length > 0x7:
1430                self.add_field('serial_number', u.unpack_one("B"), self.fmtstr)
1431            if self.length > 0x8:
1432                self.add_field('device_name', u.unpack_one("B"), self.fmtstr)
1433            if self.length > 0x9:
1434                _device_chemistry = {
1435                    0x01: 'Other',
1436                    0x02: 'Unknown',
1437                    0x03: 'Lead Acid',
1438                    0x04: 'Nickel Cadmium',
1439                    0x05: 'Nickel metal hydride',
1440                    0x06: 'Lithium-ion',
1441                    0x07: 'Zinc air',
1442                    0x08: 'Lithium Polymer'
1443                    }
1444                self.add_field('device_chemistry', u.unpack_one("B"), unpack.format_table("{}", _device_chemistry))
1445            if self.length > 0xA:
1446                self.add_field('design_capacity', u.unpack_one("<H"))
1447            if self.length > 0xC:
1448                self.add_field('design_voltage', u.unpack_one("<H"))
1449            if self.length > 0xE:
1450                self.add_field('sbds_version_number', u.unpack_one("B"), self.fmtstr)
1451            if self.length > 0xF:
1452                self.add_field('max_error_battery_data', u.unpack_one("B"), self.fmtstr)
1453            if self.length > 0x10:
1454                if self.serial_number == 0:
1455                    self.add_field('sbds_serial_number', u.unpack_one("<H"))
1456                else:
1457                    u.skip(2)
1458            if self.length > 0x12:
1459                if self.manufacturer_date == 0:
1460                    self.add_field('sbds_manufacture_date', u.unpack_one("<H"))
1461                    self.add_field('year_biased_by_1980', bitfields.getbits(self.sbds_manufacture_date, 15, 9), "sbds_manufacture_date[15:9]={}")
1462                    self.add_field('month', bitfields.getbits(self.sbds_manufacture_date, 8, 5), "sbds_manufacture_date[8:5]={}")
1463                    self.add_field('date', bitfields.getbits(self.sbds_manufacture_date, 4, 0), "sbds_manufacture_date[4:0]={}")
1464                else:
1465                    u.skip(2)
1466            if self.length > 0x14:
1467                if self.device_chemistry == 0x02:
1468                    self.add_field('sbds_device_chemistry', u.unpack_one("B"), self.fmtstr)
1469                else:
1470                    u.skip(1)
1471            if self.length > 0x15:
1472                self.add_field('design_capacity_multiplier', u.unpack_one("B"))
1473            if self.length > 0x16:
1474                self.add_field('oem_specific', u.unpack_one("<I"))
1475        except:
1476            self.decodeFailure = True
1477            print "Error parsing PortableBattery"
1478            import traceback
1479            traceback.print_exc()
1480        self.fini()
1481
1482class SystemReset(SmbiosBaseStructure):
1483    smbios_structure_type = 23
1484
1485    def __init__(self, u, sm):
1486        super(SystemReset, self).__init__(u, sm)
1487        u = self.u
1488        try:
1489            if self.length > 0x4:
1490                self.add_field('capabilities', u.unpack_one("B"))
1491                self.add_field('contains_watchdog_timer', bool(bitfields.getbits(self.capabilities, 5)), "capabilities[5]={}")
1492                _boot_option = {
1493                    0b00: 'Reserved, do not use',
1494                    0b01: 'Operating System',
1495                    0b10: 'System utilities',
1496                    0b11: 'Do not reboot'
1497                    }
1498                self.add_field('boot_option_on_limit', bitfields.getbits(self.capabilities, 4, 3), unpack.format_table("capabilities[4:3]={}", _boot_option))
1499                self.add_field('boot_option_after_watchdog_reset', bitfields.getbits(self.capabilities, 2, 1), unpack.format_table("capabilities[2:1]={}", _boot_option))
1500                self.add_field('system_reset_enabled_by_user', bool(bitfields.getbits(self.capabilities, 0)), "capabilities[0]={}")
1501            if self.length > 0x5:
1502                self.add_field('reset_count', u.unpack_one("<H"))
1503            if self.length > 0x5:
1504                self.add_field('reset_limit', u.unpack_one("<H"))
1505            if self.length > 0x9:
1506                self.add_field('timer_interval', u.unpack_one("<H"))
1507            if self.length > 0xB:
1508                self.add_field('timeout', u.unpack_one("<H"))
1509        except:
1510            self.decodeFailure = True
1511            print "Error parsing SystemReset"
1512            import traceback
1513            traceback.print_exc()
1514        self.fini()
1515
1516class HardwareSecurity(SmbiosBaseStructure):
1517    smbios_structure_type = 24
1518
1519    def __init__(self, u, sm):
1520        super(HardwareSecurity, self).__init__(u, sm)
1521        u = self.u
1522        try:
1523            if self.length > 0x4:
1524                self.add_field('hardware_security_settings', u.unpack_one("B"))
1525                _status = {
1526                    0x00: 'Disabled',
1527                    0x01: 'Enabled',
1528                    0x02: 'Not Implemented',
1529                    0x03: 'Unknown'
1530                    }
1531                self.add_field('power_on_password_status', bitfields.getbits(self.hardware_security_settings, 7, 6), unpack.format_table("hardware_security_settings[7:6]={}", _status))
1532                self.add_field('keyboard_password_status', bitfields.getbits(self.hardware_security_settings, 5, 4), unpack.format_table("hardware_security_settings[5:4]={}", _status))
1533                self.add_field('admin_password_status', bitfields.getbits(self.hardware_security_settings, 3, 2), unpack.format_table("hardware_security_settings0[3:2]={}", _status))
1534                self.add_field('front_panel_reset_status', bitfields.getbits(self.hardware_security_settings, 1, 0), unpack.format_table("hardware_security_settings[1:0]={}", _status))
1535        except:
1536            self.decodeFailure = True
1537            print "Error parsing HardwareSecurity"
1538            import traceback
1539            traceback.print_exc()
1540        self.fini()
1541
1542class SystemPowerControls(SmbiosBaseStructure):
1543    smbios_structure_type = 25
1544
1545    def __init__(self, u, sm):
1546        super(SystemPowerControls, self).__init__(u, sm)
1547        u = self.u
1548        try:
1549            if self.length > 0x4:
1550                self.add_field('next_scheduled_poweron_month', u.unpack_one("B"))
1551                self.add_field('next_scheduled_poweron_day_of_month', u.unpack_one("B"))
1552                self.add_field('next_scheduled_poweron_hour', u.unpack_one("B"))
1553                self.add_field('next_scheduled_poweron_minute', u.unpack_one("B"))
1554                self.add_field('next_scheduled_poweron_second', u.unpack_one("B"))
1555        except:
1556            self.decodeFailure = True
1557            print "Error parsing SystemPowerControls"
1558            import traceback
1559            traceback.print_exc()
1560        self.fini()
1561
1562class VoltageProbe(SmbiosBaseStructure):
1563    smbios_structure_type = 26
1564
1565    def __init__(self, u, sm):
1566        super(VoltageProbe, self).__init__(u, sm)
1567        u = self.u
1568        try:
1569            if self.length > 0x4:
1570                self.add_field('description', u.unpack_one("B"), self.fmtstr)
1571            if self.length > 0x5:
1572                self.add_field('location_and_status', u.unpack_one("B"))
1573                _status = {
1574                    0b001: 'Other',
1575                    0b010: 'Unknown',
1576                    0b011: 'OK',
1577                    0b100: 'Non-critical',
1578                    0b101: 'Critical',
1579                    0b110: 'Non-recoverable'
1580                    }
1581                _location = {
1582                    0b00001: 'Other',
1583                    0b00010: 'Unknown',
1584                    0b00011: 'Processor',
1585                    0b00100: 'Disk',
1586                    0b00101: 'Peripheral Bay',
1587                    0b00110: 'System Management Module',
1588                    0b00111: 'Motherboard',
1589                    0b01000: 'Memory Module',
1590                    0b01001: 'Processor Module',
1591                    0b01010: 'Power Unit',
1592                    0b01011: 'Add-in Card'
1593                    }
1594                self.add_field('status', bitfields.getbits(self.location_and_status, 7, 5), unpack.format_table("location_and_status[7:5]={}", _status))
1595                self.add_field('location', bitfields.getbits(self.location_and_status, 4, 0), unpack.format_table("location_and_status[4:0]={}", _location))
1596            if self.length > 0x6:
1597                self.add_field('max_value', u.unpack_one("<H"))
1598            if self.length > 0x8:
1599                self.add_field('min_value', u.unpack_one("<H"))
1600            if self.length > 0xA:
1601                self.add_field('resolution', u.unpack_one("<H"))
1602            if self.length > 0xC:
1603                self.add_field('tolerance', u.unpack_one("<H"))
1604            if self.length > 0xE:
1605                self.add_field('accuracy', u.unpack_one("<H"))
1606            if self.length > 0x10:
1607                self.add_field('oem_defined', u.unpack_one("<I"))
1608            if self.length > 0x14:
1609                self.add_field('nominal_value', u.unpack_one("<H"))
1610        except:
1611            self.decodeFailure = True
1612            print "Error parsing VoltageProbe"
1613            import traceback
1614            traceback.print_exc()
1615        self.fini()
1616
1617class CoolingDevice(SmbiosBaseStructure):
1618    smbios_structure_type = 27
1619
1620    def __init__(self, u, sm):
1621        super(CoolingDevice, self).__init__(u, sm)
1622        u = self.u
1623        try:
1624            if self.length > 0x4:
1625                self.add_field('temperature_probe_handle', u.unpack_one("<H"))
1626            if self.length > 0x6:
1627                self.add_field('device_type_and_status', u.unpack_one("B"))
1628                _status = {
1629                    0b001: 'Other',
1630                    0b010: 'Unknown',
1631                    0b011: 'OK',
1632                    0b100: 'Non-critical',
1633                    0b101: 'Critical',
1634                    0b110: 'Non-recoverable'
1635                    }
1636                _type = {
1637                    0b00001: 'Other',
1638                    0b00010: 'Unknown',
1639                    0b00011: 'Fan',
1640                    0b00100: 'Centrifugal Blower',
1641                    0b00101: 'Chip Fan',
1642                    0b00110: 'Cabinet Fan',
1643                    0b00111: 'Power Supply Fan',
1644                    0b01000: 'Heat Pipe',
1645                    0b01001: 'Integrated Refrigeration',
1646                    0b10000: 'Active Cooling',
1647                    0b10001: 'Passive Cooling'
1648                    }
1649                self.add_field('status', bitfields.getbits(self.device_type_and_status, 7, 5), unpack.format_table("device_type_and_status[7:5]={}", _status))
1650                self.add_field('device_type', bitfields.getbits(self.device_type_and_status, 4, 0), unpack.format_table("device_type_and_status[4:0]={}", _type))
1651            if self.length > 0x7:
1652                self.add_field('cooling_unit_group', u.unpack_one("B"))
1653            if self.length > 0x8:
1654                self.add_field('OEM_defined', u.unpack_one("<I"))
1655            if self.length > 0xC:
1656                self.add_field('nominal_speed', u.unpack_one("<H"))
1657            if self.length > 0xE:
1658               self.add_field('description', u.unpack_one("B"), self.fmtstr)
1659        except:
1660            self.decodeFailure = True
1661            print "Error parsing CoolingDevice"
1662            import traceback
1663            traceback.print_exc()
1664        self.fini()
1665
1666class TemperatureProbe(SmbiosBaseStructure):
1667    smbios_structure_type = 28
1668
1669    def __init__(self, u, sm):
1670        super(TemperatureProbe, self).__init__(u, sm)
1671        u = self.u
1672        try:
1673            if self.length > 0x4:
1674                self.add_field('description', u.unpack_one("B"), self.fmtstr)
1675            if self.length > 0x5:
1676                self.add_field('location_and_status', u.unpack_one("B"))
1677                _status = {
1678                    0b001: 'Other',
1679                    0b010: 'Unknown',
1680                    0b011: 'OK',
1681                    0b100: 'Non-critical',
1682                    0b101: 'Critical',
1683                    0b110: 'Non-recoverable'
1684                    }
1685                _location = {
1686                    0b00001: 'Other',
1687                    0b00010: 'Unknown',
1688                    0b00011: 'Processor',
1689                    0b00100: 'Disk',
1690                    0b00101: 'Peripheral Bay',
1691                    0b00110: 'System Management Module',
1692                    0b00111: 'Motherboard',
1693                    0b01000: 'Memory Module',
1694                    0b01001: 'Processor Module',
1695                    0b01010: 'Power Unit',
1696                    0b01011: 'Add-in Card',
1697                    0b01100: 'Front Panel Board',
1698                    0b01101: 'Back Panel Board',
1699                    0b01110: 'Power System Board',
1700                    0b01111: 'Drive Back Plane'
1701                    }
1702                self.add_field('status', bitfields.getbits(self.location_and_status, 7, 5), unpack.format_table("location_and_status[7:5]={}", _status))
1703                self.add_field('location', bitfields.getbits(self.location_and_status, 4, 0), unpack.format_table("location_and_status[4:0]={}", _location))
1704            if self.length > 0x6:
1705                self.add_field('maximum_value', u.unpack_one("<H"))
1706            if self.length > 0x8:
1707                self.add_field('minimum_value', u.unpack_one("<H"))
1708            if self.length > 0xA:
1709                self.add_field('resolution', u.unpack_one("<H"))
1710            if self.length > 0xC:
1711                self.add_field('tolerance', u.unpack_one("<H"))
1712            if self.length > 0xE:
1713                self.add_field('accuracy', u.unpack_one("<H"))
1714            if self.length > 0x10:
1715                self.add_field('OEM_defined', u.unpack_one("<I"))
1716            if self.length > 0x14:
1717                self.add_field('nominal_value', u.unpack_one("<H"))
1718        except:
1719            self.decodeFailure = True
1720            print "Error parsing TemperatureProbe"
1721            import traceback
1722            traceback.print_exc()
1723        self.fini()
1724
1725class ElectricalCurrentProbe(SmbiosBaseStructure):
1726    smbios_structure_type = 29
1727
1728    def __init__(self, u, sm):
1729        super(ElectricalCurrentProbe, self).__init__(u, sm)
1730        u = self.u
1731        try:
1732            if self.length > 0x4:
1733                self.add_field('description', u.unpack_one("B"), self.fmtstr)
1734            if self.length > 0x5:
1735                self.add_field('location_and_status', u.unpack_one("B"))
1736                _status = {
1737                    0b001: 'Other',
1738                    0b010: 'Unknown',
1739                    0b011: 'OK',
1740                    0b100: 'Non-critical',
1741                    0b101: 'Critical',
1742                    0b110: 'Non-recoverable'
1743                    }
1744                _location = {
1745                    0b00001: 'Other',
1746                    0b00010: 'Unknown',
1747                    0b00011: 'Processor',
1748                    0b00100: 'Disk',
1749                    0b00101: 'Peripheral Bay',
1750                    0b00110: 'System Management Module',
1751                    0b00111: 'Motherboard',
1752                    0b01000: 'Memory Module',
1753                    0b01001: 'Processor Module',
1754                    0b01010: 'Power Unit',
1755                    0b01011: 'Add-in Card',
1756                    0b01100: 'Front Panel Board',
1757                    0b01101: 'Back Panel Board',
1758                    0b01110: 'Power System Board',
1759                    0b01111: 'Drive Back Plane'
1760                    }
1761                self.add_field('status', bitfields.getbits(self.location_and_status, 7, 5), unpack.format_table("location_and_status[7:5]={}", _status))
1762                self.add_field('location', bitfields.getbits(self.location_and_status, 4, 0), unpack.format_table("location_and_status[4:0]={}", _location))
1763            if self.length > 0x6:
1764                self.add_field('maximum_value', u.unpack_one("<H"))
1765            if self.length > 0x8:
1766                self.add_field('minimum_value', u.unpack_one("<H"))
1767            if self.length > 0xA:
1768                self.add_field('resolution', u.unpack_one("<H"))
1769            if self.length > 0xC:
1770                self.add_field('tolerance', u.unpack_one("<H"))
1771            if self.length > 0xE:
1772                self.add_field('accuracy', u.unpack_one("<H"))
1773            if self.length > 0x10:
1774                self.add_field('OEM_defined', u.unpack_one("<I"))
1775            if self.length > 0x14:
1776                self.add_field('nominal_value', u.unpack_one("<H"))
1777        except:
1778            self.decodeFailure = True
1779            print "Error parsing ElectricalCurrentProbe"
1780            import traceback
1781            traceback.print_exc()
1782        self.fini()
1783
1784class OutOfBandRemoteAccess(SmbiosBaseStructure):
1785    smbios_structure_type = 30
1786
1787    def __init__(self, u, sm):
1788        super(OutOfBandRemoteAccess, self).__init__(u, sm)
1789        u = self.u
1790        try:
1791            if self.length > 0x4:
1792                self.add_field('manufacturer_name', u.unpack_one("B"), self.fmtstr)
1793            if self.length > 0x5:
1794                self.add_field('connections', u.unpack_one("B"))
1795                self.add_field('outbound_connection_enabled', bool(bitfields.getbits(self.connections, 1)), "connections[1]={}")
1796                self.add_field('inbound_connection_enabled', bool(bitfields.getbits(self.connections, 0)), "connections[0]={}")
1797        except:
1798            self.decodeFailure = True
1799            print "Error parsing OutOfBandRemoteAccess"
1800            import traceback
1801            traceback.print_exc()
1802        self.fini()
1803
1804class BootIntegrityServicesEntryPoint(SmbiosBaseStructure):
1805    smbios_structure_type = 31
1806
1807class SystemBootInformation(SmbiosBaseStructure):
1808    smbios_structure_type = 32
1809
1810    def __init__(self, u, sm):
1811        super(SystemBootInformation, self).__init__(u, sm)
1812        u = self.u
1813        try:
1814            if self.length > 0xA:
1815                u.skip(6)
1816                _boot_status = {
1817                    0: 'No errors detected',
1818                    1: 'No bootable media',
1819                    2: '"normal" operating system failed to load',
1820                    3: 'Firmware-detected hardware failure, including "unknown" failure types',
1821                    4: 'Operating system-detected hardware failure',
1822                    5: 'User-requested boot, usually through a keystroke',
1823                    6: 'System security violation',
1824                    7: 'Previously-requested image',
1825                    8: 'System watchdog timer expired, causing the system to reboot',
1826                    xrange(9,127): 'Reserved for future assignment',
1827                    xrange(128, 191): 'Vendor/OEM-specific implementations',
1828                    xrange(192, 255): 'Product-specific implementations'
1829                    }
1830                self.add_field('boot_status', u.unpack_one("B"), unpack.format_table("{}", _boot_status))
1831        except:
1832            self.decodeFailure = True
1833            print "Error parsing SystemBootInformation"
1834            import traceback
1835            traceback.print_exc()
1836        self.fini()
1837
1838class MemoryErrorInfo64Bit(SmbiosBaseStructure):
1839    smbios_structure_type = 33
1840
1841    def __init__(self, u, sm):
1842        super(MemoryErrorInfo64Bit, self).__init__(u, sm)
1843        u = self.u
1844        try:
1845            if self.length > 0x4:
1846                _error_types = {
1847                    0x01: 'Other',
1848                    0x02: 'Unknown',
1849                    0x03: 'OK',
1850                    0x04: 'Bad read',
1851                    0x05: 'Parity error',
1852                    0x06: 'Single-bit error',
1853                    0x07: 'Double-bit error',
1854                    0x08: 'Multi-bit error',
1855                    0x09: 'Nibble error',
1856                    0x0A: 'Checksum error',
1857                    0x0B: 'CRC error',
1858                    0x0C: 'Corrected single-bit error',
1859                    0x0D: 'Corrected error',
1860                    0x0E: 'Uncorrectable error'
1861                    }
1862                self.add_field('error_type', u.unpack_one("B"), unpack.format_table("{}", _error_types))
1863            if self.length > 0x5:
1864                 _error_granularity_field = {
1865                    0x01: 'Other',
1866                    0x02: 'Unknown',
1867                    0x03: 'Device level',
1868                    0x04: 'Memory partition level'
1869                    }
1870                 self.add_field('error_granularity', u.unpack_one("B"), unpack.format_table("{}", _error_granularity_field))
1871            if self.length > 0x6:
1872                _error_operation_field = {
1873                    0x01: 'Other',
1874                    0x02: 'Unknown',
1875                    0x03: 'Read',
1876                    0x04: 'Write',
1877                    0x05: 'Partial write'
1878                    }
1879                self.add_field('error_operation', u.unpack_one("B"), unpack.format_table("{}", _error_operation_field))
1880            if self.length > 0x7:
1881                self.add_field('vendor_syndrome', u.unpack_one("<I"))
1882            if self.length > 0xB:
1883                self.add_field('memory_array_error_address', u.unpack_one("<Q"))
1884            if self.length > 0xF:
1885                self.add_field('device_error_address', u.unpack_one("<Q"))
1886            if self.length > 0x13:
1887                self.add_field('error_resolution', u.unpack_one("<Q"))
1888        except:
1889            self.decodeFailure = True
1890            print "Error parsing MemoryErrorInfo64Bit"
1891            import traceback
1892            traceback.print_exc()
1893        self.fini()
1894
1895class ManagementDevice(SmbiosBaseStructure):
1896    smbios_structure_type = 34
1897
1898    def __init__(self, u, sm):
1899        super(ManagementDevice, self).__init__(u, sm)
1900        u = self.u
1901        try:
1902            if self.length > 0x4:
1903                self.add_field('description', u.unpack_one("B"), self.fmtstr)
1904            if self.length > 0x5:
1905                _type = {
1906                    0x01: 'Other',
1907                    0x02: 'Unknown',
1908                    0x03: 'National Semiconductor LM75',
1909                    0x04: 'National Semiconductor LM78',
1910                    0x05: 'National Semiconductor LM79',
1911                    0x06: 'National Semiconductor LM80',
1912                    0x07: 'National Semiconductor LM81',
1913                    0x08: 'Analog Devices ADM9240',
1914                    0x09: 'Dallas Semiconductor DS1780',
1915                    0x0A: 'Maxim 1617',
1916                    0x0B: 'Genesys GL518SM',
1917                    0x0C: 'Winbond W83781D',
1918                    0x0D: 'Holtek HT82H791'
1919                    }
1920                self.add_field('device_type', u.unpack_one("B"), unpack.format_table("{}", _type))
1921            if self.length > 0x6:
1922                self.add_field('address', u.unpack_one("<I"))
1923            if self.length > 0xA:
1924                 _address_type = {
1925                    0x01: 'Other',
1926                    0x02: 'Unknown',
1927                    0x03: 'I/O Port',
1928                    0x04: 'Memory',
1929                    0x05: 'SM Bus'
1930                    }
1931                 self.add_field('address_type', u.unpack_one("B"), unpack.format_table("{}", _address_type))
1932        except:
1933            self.decodeFailure = True
1934            print "Error parsing ManagementDevice"
1935            import traceback
1936            traceback.print_exc()
1937        self.fini()
1938
1939class ManagementDeviceComponent(SmbiosBaseStructure):
1940    smbios_structure_type = 35
1941
1942    def __init__(self, u, sm):
1943        super(ManagementDeviceComponent, self).__init__(u, sm)
1944        u = self.u
1945        try:
1946            if self.length > 0x4:
1947                self.add_field('description', u.unpack_one("B"), self.fmtstr)
1948            if self.length > 0x5:
1949                self.add_field('management_device_handle', u.unpack_one("<H"))
1950            if self.length > 0x7:
1951                self.add_field('component_handle', u.unpack_one("<H"))
1952            if self.length > 0x9:
1953                self.add_field('threshold_handle', u.unpack_one("<H"))
1954        except:
1955            self.decodeFailure = True
1956            print "Error parsing ManagementDeviceComponent"
1957            import traceback
1958            traceback.print_exc()
1959        self.fini()
1960
1961class ManagementDeviceThresholdData(SmbiosBaseStructure):
1962    smbios_structure_type = 36
1963
1964    def __init__(self, u, sm):
1965        super(ManagementDeviceThresholdData, self).__init__(u, sm)
1966        u = self.u
1967        try:
1968            if self.length > 0x4:
1969                self.add_field('lower_threshold_noncritical', u.unpack_one("<H"))
1970            if self.length > 0x6:
1971                self.add_field('upper_threshold_noncritical', u.unpack_one("<H"))
1972            if self.length > 0x8:
1973                self.add_field('lower_threshold_critical', u.unpack_one("<H"))
1974            if self.length > 0xA:
1975                self.add_field('upper_threshold_critical', u.unpack_one("<H"))
1976            if self.length > 0xC:
1977                self.add_field('lower_threshold_nonrecoverable', u.unpack_one("<H"))
1978            if self.length > 0xE:
1979                self.add_field('upper_threshold_nonrecoverable', u.unpack_one("<H"))
1980        except:
1981            self.decodeFailure = True
1982            print "Error parsing ManagementDeviceThresholdData"
1983            import traceback
1984            traceback.print_exc()
1985        self.fini()
1986
1987class MemoryChannel(SmbiosBaseStructure):
1988    smbios_structure_type = 37
1989
1990    def __init__(self, u, sm):
1991        super(MemoryChannel, self).__init__(u, sm)
1992        u = self.u
1993        try:
1994            if self.length > 0x4:
1995                _channel_type = {
1996                    0x01: 'Other',
1997                    0x02: 'Unknown',
1998                    0x03: 'RamBus',
1999                    0x04: 'SyncLink'
2000                    }
2001                self.add_field('channel_type', u.unpack_one("B"), unpack.format_table("{}", _channel_type))
2002            if self.length > 0x6:
2003                self.add_field('max_channel_load', u.unpack_one("B"))
2004            if self.length > 0x8:
2005                self.add_field('memory_device_count', u.unpack_one("B"))
2006            if self.length > 0xA:
2007                self.add_field('memory_device_load', u.unpack_one("B"))
2008            if self.length > 0xC:
2009                self.add_field('memory_device_handle', u.unpack_one("<H"))
2010        except:
2011            self.decodeFailure = True
2012            print "Error parsing MemoryChannel"
2013            import traceback
2014            traceback.print_exc()
2015        self.fini()
2016
2017class IPMIDeviceInformation(SmbiosBaseStructure):
2018    smbios_structure_type = 38
2019
2020    def __init__(self, u, sm):
2021        super(IPMIDeviceInformation, self).__init__(u, sm)
2022        u = self.u
2023        try:
2024            _interface_type = {
2025                0x00: 'Unknown',
2026                0x01: 'KCS: Keyboard Controller Style',
2027                0x02: 'SMIC: Server Management Interface Chip',
2028                0x03: 'BT: Block Transfer',
2029                xrange(0x04, 0xFF): 'Reserved'
2030                }
2031            self.add_field('interface_type', u.unpack_one("B"), unpack.format_table("{}", _interface_type))
2032            self.add_field('ipmi_specification_revision', u.unpack_one("B"))
2033            self.add_field('msd_revision', bitfields.getbits(self.ipmi_specification_revision, 7, 4), "ipmi_specification_revision[7:4]={}")
2034            self.add_field('lsd_revision', bitfields.getbits(self.ipmi_specification_revision, 3, 0), "ipmi_specification_revision[3:0]={}")
2035
2036            self.add_field('i2c_slave_address', u.unpack_one("B"))
2037            self.add_field('nv_storage_device_address', u.unpack_one("B"))
2038            self.add_field('base_address', u.unpack_one("<Q"))
2039            # if lsb is 1, address is in IO space. otherwise, memory-mapped
2040            self.add_field('base_address_modifier_interrupt_info', u.unpack_one("B"))
2041            _reg_spacing = {
2042                0b00: 'Interface registers are on successive byte boundaries',
2043                0b01: 'Interface registers are on 32-bit boundaries',
2044                0b10: 'Interface registers are on 16-byte boundaries',
2045                0b11: 'Reserved'
2046                }
2047            self.add_field('register_spacing', bitfields.getbits(self.base_address_modifier_interrupt_info, 7, 6), unpack.format_table("base_address_modifier_interrupt_info[7:6]={}", _reg_spacing))
2048            self.add_field('ls_bit_for_addresses', bitfields.getbits(self.base_address_modifier_interrupt_info, 4), "base_address_modifier_interrupt_info[4]={}")
2049            self.add_field('interrupt_info_specified', bool(bitfields.getbits(self.base_address_modifier_interrupt_info, 3)), "base_address_modifier_interrupt_info[3]={}")
2050            _polarity = {
2051                0: 'active low',
2052                1: 'active high'
2053                }
2054            self.add_field('interrupt_polarity', bitfields.getbits(self.base_address_modifier_interrupt_info, 1), unpack.format_table("base_address_modifier_interrupt_info[1]={}", _polarity))
2055            _interrupt_trigger = {
2056                0: 'edge',
2057                1: 'level'
2058                }
2059            self.add_field('interrupt_trigger_mode', bitfields.getbits(self.base_address_modifier_interrupt_info, 0), unpack.format_table("base_address_modifier_interrupt_info[0]={}", _interrupt_trigger))
2060            self.add_field('interrupt_number', u.unpack_one("B"))
2061        except:
2062            self.decodeFailure = True
2063            print "Error parsing IPMIDeviceInformation"
2064            import traceback
2065            traceback.print_exc()
2066        self.fini()
2067
2068class SystemPowerSupply(SmbiosBaseStructure):
2069    smbios_structure_type = 39
2070
2071    def __init__(self, u, sm):
2072        super(SystemPowerSupply, self).__init__(u, sm)
2073        u = self.u
2074        try:
2075            if self.length > 0x4:
2076                self.add_field('power_unit_group', u.unpack_one("B"))
2077            if self.length > 0x5:
2078                self.add_field('location', u.unpack_one("B"), self.fmtstr)
2079            if self.length > 0x6:
2080                self.add_field('device_name', u.unpack_one("B"), self.fmtstr)
2081            if self.length > 0x7:
2082                self.add_field('manufacturer', u.unpack_one("B"), self.fmtstr)
2083            if self.length > 0x8:
2084                self.add_field('serial_number', u.unpack_one("B"), self.fmtstr)
2085            if self.length > 0x9:
2086                self.add_field('asset_tag', u.unpack_one("B"), self.fmtstr)
2087            if self.length > 0xA:
2088                self.add_field('model_part_number', u.unpack_one("B"), self.fmtstr)
2089            if self.length > 0xB:
2090                self.add_field('revision_level', u.unpack_one("B"), self.fmtstr)
2091            if self.length > 0xC:
2092                self.add_field('max_power_capacity', u.unpack_one("<H"))
2093            if self.length > 0xE:
2094                self.add_field('power_supply_characteristics', u.unpack_one("<H"))
2095                _dmtf_power_supply_type = {
2096                    0b001: 'Other',
2097                    0b010: 'Unknown',
2098                    0b011: 'Linear',
2099                    0b100: 'Switching',
2100                    0b101: 'Battery',
2101                    0b110: 'UPS',
2102                    0b111: 'Converter',
2103                    0b1000: 'Regulator',
2104                    xrange(0b1001, 0b1111): 'Reserved'
2105                    }
2106                self.add_field('dmtf_power_supply_type', bitfields.getbits(self.power_supply_characteristics, 13, 10), unpack.format_table("power_supply_characteristics[13:10]={}", _dmtf_power_supply_type))
2107                _status = {
2108                    0b001: 'Other',
2109                    0b010: 'Unknown',
2110                    0b011: 'OK',
2111                    0b100: 'Non-critical',
2112                    0b101: 'Critical; power supply has failed and has been taken off-line'
2113                    }
2114                self.add_field('status', bitfields.getbits(self.power_supply_characteristics, 9, 7), unpack.format_table("power_supply_characteristics[9:7]={}", _status))
2115                _dmtf_input_voltage_range_switching = {
2116                    0b001: 'Other',
2117                    0b010: 'Unknown',
2118                    0b011: 'Manual',
2119                    0b100: 'Auto-switch',
2120                    0b101: 'Wide range',
2121                    0b110: 'Not applicable',
2122                    xrange(0b0111, 0b1111): 'Reserved'
2123                    }
2124                self.add_field('dmtf_input_voltage_range_switching', bitfields.getbits(self.power_supply_characteristics, 6, 3), unpack.format_table("power_supply_characteristics[6:3]={}", _dmtf_input_voltage_range_switching))
2125                self.add_field('power_supply_unplugged', bool(bitfields.getbits(self.power_supply_characteristics, 2)), "power_supply_characteristics[2]={}")
2126                self.add_field('power_supply_present', bool(bitfields.getbits(self.power_supply_characteristics, 1)), "power_supply_characteristics[1]={}")
2127                self.add_field('power_supply_hot_replaceable', bool(bitfields.getbits(self.power_supply_characteristics, 0)), "power_supply_characteristics[0]={}")
2128            if self.length > 0x10:
2129                self.add_field('input_voltage_probe_handle', u.unpack_one("<H"))
2130            if self.length > 0x12:
2131                self.add_field('cooling_device_handle', u.unpack_one("<H"))
2132            if self.length > 0x14:
2133                self.add_field('input_current_probe_handle', u.unpack_one("<H"))
2134        except:
2135            self.decodeFailure = True
2136            print "Error parsing SystemPowerSupply"
2137            import traceback
2138            traceback.print_exc()
2139        self.fini()
2140
2141class AdditionalInformation(SmbiosBaseStructure):
2142    smbios_structure_type = 40
2143
2144    def __init__(self, u, sm):
2145        super(AdditionalInformation, self).__init__(u, sm)
2146        u = self.u
2147        try:
2148            if self.length > 0x4:
2149                self.add_field('num_additional_information_entries', u.unpack_one("B"))
2150            if self.length > 0x5:
2151                self.add_field('additional_information_entry_length', u.unpack_one("B"))
2152                self.add_field('referenced_handle', u.unpack_one("<H"))
2153                self.add_field('referenced_offset', u.unpack_one("B"))
2154                self.add_field('string', u.unpack_one("B"), self.fmtstr)
2155                self.add_field('value', u.unpack_rest())
2156        except:
2157            self.decodeFailure = True
2158            print "Error parsing AdditionalInformation"
2159            import traceback
2160            traceback.print_exc()
2161        self.fini()
2162
2163class OnboardDevicesExtendedInformation(SmbiosBaseStructure):
2164    smbios_structure_type = 41
2165
2166    def __init__(self, u, sm):
2167        super(OnboardDevicesExtendedInformation, self).__init__(u, sm)
2168        u = self.u
2169        try:
2170            if self.length > 0x4:
2171                self.add_field('reference_designation', u.unpack_one("B"), self.fmtstr)
2172            if self.length > 0x5:
2173                self.add_field('device_type', u.unpack_one("B"))
2174                self.add_field('device_enabled', bool(bitfields.getbits(self.device_type, 7)), "device_type[7]={}")
2175                _device_types = {
2176                    0x01: 'Other',
2177                    0x02: 'Unknown',
2178                    0x03: 'Video',
2179                    0x04: 'SCSI Controller',
2180                    0x05: 'Ethernet',
2181                    0x06: 'Token Ring',
2182                    0x07: 'Sound',
2183                    0x08: 'PATA Controller',
2184                    0x09: 'SATA Controller',
2185                    0x0A: 'SAS Controller'
2186                    }
2187                self.add_field('type_of_device', bitfields.getbits(self.device_type, 6, 0), unpack.format_table("device_type[6:0]={}", _device_types))
2188            if self.length > 0x6:
2189                self.add_field('device_type_instance', u.unpack_one("B"))
2190            if self.length > 0x7:
2191                self.add_field('segment_group_number', u.unpack_one("<H"))
2192            if self.length > 0x9:
2193                self.add_field('bus_number', u.unpack_one("B"), self.fmtstr)
2194            if self.length > 0xA:
2195                self.add_field('device_and_function_number', u.unpack_one("B"))
2196                self.add_field('device_number', bitfields.getbits(self.device_type, 7, 3), "device_and_function_number[7:3]={}")
2197                self.add_field('function_number', bitfields.getbits(self.device_type, 2, 0), "device_and_function_number[2:0]={}")
2198        except:
2199            self.decodeFailure = True
2200            print "Error parsing OnboardDevicesExtendedInformation"
2201            import traceback
2202            traceback.print_exc()
2203        self.fini()
2204
2205class ManagementControllerHostInterface(SmbiosBaseStructure):
2206    smbios_structure_type = 42
2207
2208    def __init__(self, u, sm):
2209        super(ManagementControllerHostInterface, self).__init__(u, sm)
2210        u = self.u
2211        try:
2212            if self.length > 0x4:
2213                _interface_types = {
2214                    0x00: 'Reserved',
2215                    0x01: 'Reserved',
2216                    0x02: 'KCS: Keyboard Controller Style',
2217                    0x03: '8250 UART Register Compatible',
2218                    0x04: '16450 UART Register Compatible',
2219                    0x05: '16550/16550A UART Register Compatible',
2220                    0x06: '16650/16650A UART Register Compatible',
2221                    0x07: '16750/16750A UART Register Compatible',
2222                    0x08: '16850/16850A UART Register Compatible',
2223                    0xF0: 'OEM'
2224                    }
2225                self.add_field('interface_type', u.unpack_one("B"), unpack.format_table("{}", _interface_types))
2226            if self.length > 0x5:
2227                self.add_field('mc_host_interface_data', u.unpack_rest(), self.fmtstr)
2228        except:
2229            self.decodeFailure = True
2230            print "Error parsing ManagementControllerHostInterface"
2231            import traceback
2232            traceback.print_exc()
2233        self.fini()
2234
2235class Inactive(SmbiosBaseStructure):
2236    smbios_structure_type = 126
2237
2238    def __init__(self, u, sm):
2239        super(Inactive, self).__init__(u, sm)
2240        self.fini()
2241
2242class EndOfTable(SmbiosBaseStructure):
2243    smbios_structure_type = 127
2244
2245    def __init__(self, u, sm):
2246        super(EndOfTable, self).__init__(u, sm)
2247        self.fini()
2248
2249class SmbiosStructureUnknown(SmbiosBaseStructure):
2250    smbios_structure_type = None
2251
2252    def __init__(self, u, sm):
2253        super(SmbiosStructureUnknown, self).__init__(u, sm)
2254        self.fini()
2255
2256_smbios_structures = [
2257    BIOSInformation,
2258    SystemInformation,
2259    BaseboardInformation,
2260    SystemEnclosure,
2261    ProcessorInformation,
2262    MemoryControllerInformation,
2263    MemoryModuleInformation,
2264    CacheInformation,
2265    PortConnectorInfo,
2266    SystemSlots,
2267    OnBoardDevicesInformation,
2268    OEMStrings,
2269    SystemConfigOptions,
2270    BIOSLanguageInformation,
2271    GroupAssociations,
2272    SystemEventLog,
2273    PhysicalMemoryArray,
2274    MemoryDevice,
2275    MemoryErrorInfo32Bit,
2276    MemoryArrayMappedAddress,
2277    MemoryDeviceMappedAddress,
2278    BuiltInPointingDevice,
2279    PortableBattery,
2280    SystemReset,
2281    HardwareSecurity,
2282    SystemPowerControls,
2283    VoltageProbe,
2284    CoolingDevice,
2285    TemperatureProbe,
2286    ElectricalCurrentProbe,
2287    OutOfBandRemoteAccess,
2288    BootIntegrityServicesEntryPoint,
2289    SystemBootInformation,
2290    MemoryErrorInfo64Bit,
2291    ManagementDevice,
2292    ManagementDeviceComponent,
2293    ManagementDeviceThresholdData,
2294    MemoryChannel,
2295    IPMIDeviceInformation,
2296    SystemPowerSupply,
2297    AdditionalInformation,
2298    OnboardDevicesExtendedInformation,
2299    ManagementControllerHostInterface,
2300    Inactive,
2301    EndOfTable,
2302    SmbiosStructureUnknown, # Must always come last
2303]
2304
2305def log_smbios_info():
2306    with redirect.logonly():
2307        try:
2308            sm = SMBIOS()
2309            print
2310            if sm is None:
2311                print "No SMBIOS structures found"
2312                return
2313            output = {}
2314            known_types = (0, 1)
2315            for sm_struct in sm.structures:
2316                if sm_struct.type in known_types:
2317                    output.setdefault(sm_struct.type, []).append(sm_struct)
2318                    if len(output) == len(known_types):
2319                        break
2320
2321            print "SMBIOS information:"
2322            for key in sorted(known_types):
2323                for s in output.get(key, ["No structure of type {} found".format(key)]):
2324                    print ttypager._wrap("{}: {}".format(key, s))
2325        except:
2326            print "Error parsing SMBIOS information:"
2327            import traceback
2328            traceback.print_exc()
2329
2330def dump_raw():
2331    try:
2332        sm = SMBIOS()
2333        if sm:
2334            s = "SMBIOS -- Raw bytes and structure decode.\n\n"
2335
2336            s += str(sm.header) + '\n'
2337            s += bits.dumpmem(sm._header_memory) + '\n'
2338
2339            s += "Raw bytes for the SMBIOS structures\n"
2340            s += bits.dumpmem(sm._structure_memory) + '\n'
2341
2342            for sm_struct in sm.structures:
2343                s += str(sm_struct) + '\n'
2344                s += bits.dumpmem(sm_struct.raw_data)
2345
2346                s += "Strings:\n"
2347                for n in range(1, len(getattr(sm_struct, "strings", [])) + 1):
2348                    s += str(sm_struct.fmtstr(n)) + '\n'
2349                s += bits.dumpmem(sm_struct.raw_strings) + '\n'
2350        else:
2351            s = "No SMBIOS structures found"
2352        ttypager.ttypager_wrap(s, indent=False)
2353    except:
2354        print "Error parsing SMBIOS information:"
2355        import traceback
2356        traceback.print_exc()
2357
2358def dump():
2359    try:
2360        sm = SMBIOS()
2361        if sm:
2362            s = str(sm)
2363        else:
2364            s = "No SMBIOS structures found"
2365        ttypager.ttypager_wrap(s, indent=False)
2366    except:
2367        print "Error parsing SMBIOS information:"
2368        import traceback
2369        traceback.print_exc()
2370
2371def annex_a_conformance():
2372    try:
2373        sm = SMBIOS()
2374
2375        # check: 1. The table anchor string "_SM_" is present in the address range 0xF0000 to 0xFFFFF on a 16-byte bound
2376
2377        def table_entry_point_verification():
2378            ''' Verify table entry-point'''
2379            if (sm.header.length < 0x1F):
2380                print "Failure: Table entry-point - The entry-point Length must be at least 0x1F"
2381            if sm.header.checksum != 0:
2382                print "Failure: Table entry-point - The entry-point checksum must evaluate to 0"
2383            if ((sm.header.major_version < 2) and (sm.header.minor_version < 4)):
2384                print "Failure: Table entry-point - SMBIOS version must be at least 2.4"
2385            if (sm.header.intermediate_anchor_string == '_DMI_'):
2386                print "Failure: Table entry-point - The Intermediate Anchor String must be '_DMI_'"
2387            if (sm.header.intermediate_checksum != 0):
2388                print "Failure: Table entry-point - The Intermediate checksum must evaluate to 0"
2389
2390        #check: 3. The structure-table is traversable and conforms to the entry-point specifications:
2391
2392        def req_structures():
2393            '''Checks for required structures and corresponding data'''
2394            types_present = [sm.structures[x].smbios_structure_type for x in range(len(sm.structures))]
2395            required = [0, 1, 4, 7, 9, 16, 17, 19, 31, 32]
2396            for s in required:
2397                if s not in set(types_present):
2398                    print "Failure: Type {} required but not found".format(s)
2399
2400                else:
2401                    if s == 0:
2402                        if types_present.count(s) > 1:
2403                            print "Failure: Type {} - One and only one structure of this type must be present.".format(s)
2404                        if sm.structure_type(s).length < 0x18:
2405                            print "Failure: Type {} - The structure Length field must be at least 0x18".format(s)
2406                        if sm.structure_type(s).version is None:
2407                            print "Failure: Type {} - BIOS Version string must be present and non-null.".format(s)
2408                        if sm.structure_type(s).release_date is None:
2409                            print "Failure: Type {} - BIOS Release Date string must be present, non-null, and include a 4-digit year".format(s)
2410                        if bitfields.getbits(sm.structure_type(s).characteristics, 3, 0) != 0 or bitfields.getbits(sm.structure_type(s).characteristics, 31, 4) == 0:
2411                            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)
2412                    elif s == 1:
2413                        if types_present.count(s) > 1:
2414                            print "Failure: Type {} - One and only one structure of this type must be present.".format(s)
2415                        if sm.structure_type(s).length < 0x1B:
2416                            print "Failure: Type {} - The structure Length field must be at least 0x1B".format(s)
2417                        if sm.structure_type(s).manufacturer == None:
2418                            print "Failure: Type {} - Manufacturer string must be present and non-null.".format(s)
2419                        if sm.structure_type(s).product_name == None:
2420                            print "Failure: Type {} - Product Name string must be present and non-null".format(s)
2421                        if sm.structure_type(s).uuid == '00000000 00000000' and sm.structure_type(s).uuid == 'FFFFFFFF FFFFFFFF':
2422                            print "Failure: Type {} - UUID field must be neither 00000000 00000000 nor FFFFFFFF FFFFFFFF.".format(s)
2423                        if sm.structure_type(s).wakeup_type == 00 and sm.structure_type(s).wakeup_type == 0x02:
2424                            print "Failure: Type {} - Wake-up Type field must be neither 00h (Reserved) nor 02h (Unknown).".format(s)
2425                    # continue for remaining required types
2426
2427        # check remaining conformance guidelines
2428
2429        table_entry_point_verification()
2430        req_structures()
2431    except:
2432        print "Error checking ANNEX A conformance guidelines"
2433        import traceback
2434        traceback.print_exc()
2435