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