/* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. Copyright (C) 2009-2012 Michael Möller */ using System; using System.Collections.Generic; using System.IO; using System.Management; using System.Text; namespace OpenHardwareMonitor.Hardware { public class SMBIOS { private readonly byte[] raw; private readonly Structure[] table; private readonly Version version; private readonly BIOSInformation biosInformation; private readonly SystemInformation systemInformation; private readonly BaseBoardInformation baseBoardInformation; private readonly ChassisInformation chassisInformation; private readonly ProcessorInformation processorInformation; private readonly MemoryDevice[] memoryDevices; private static string ReadSysFS(string path) { try { if (File.Exists(path)) { using (StreamReader reader = new StreamReader(path)) return reader.ReadLine(); } else { return null; } } catch { return null; } } public SMBIOS() { if (Software.OperatingSystem.IsLinux) { this.raw = null; this.table = null; string boardVendor = ReadSysFS("/sys/class/dmi/id/board_vendor"); string boardName = ReadSysFS("/sys/class/dmi/id/board_name"); string boardVersion = ReadSysFS("/sys/class/dmi/id/board_version"); this.baseBoardInformation = new BaseBoardInformation( boardVendor, boardName, boardVersion, null); string systemVendor = ReadSysFS("/sys/class/dmi/id/sys_vendor"); string productName = ReadSysFS("/sys/class/dmi/id/product_name"); string productVersion = ReadSysFS("/sys/class/dmi/id/product_version"); this.systemInformation = new SystemInformation(systemVendor, productName, productVersion, null, null); string biosVendor = ReadSysFS("/sys/class/dmi/id/bios_vendor"); string biosVersion = ReadSysFS("/sys/class/dmi/id/bios_version"); this.biosInformation = new BIOSInformation(biosVendor, biosVersion); this.memoryDevices = new MemoryDevice[0]; } else { List structureList = new List(); List memoryDeviceList = new List(); raw = null; byte majorVersion = 0; byte minorVersion = 0; try { ManagementObjectCollection collection; using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\WMI", "SELECT * FROM MSSMBios_RawSMBiosTables")) { collection = searcher.Get(); } foreach (ManagementObject mo in collection) { raw = (byte[])mo["SMBiosData"]; majorVersion = (byte)mo["SmbiosMajorVersion"]; minorVersion = (byte)mo["SmbiosMinorVersion"]; break; } } catch { } if (majorVersion > 0 || minorVersion > 0) version = new Version(majorVersion, minorVersion); if (raw != null && raw.Length > 0) { int offset = 0; byte type = raw[offset]; while (offset + 4 < raw.Length && type != 127) { type = raw[offset]; int length = raw[offset + 1]; ushort handle = (ushort)((raw[offset + 2] << 8) | raw[offset + 3]); if (offset + length > raw.Length) break; byte[] data = new byte[length]; Array.Copy(raw, offset, data, 0, length); offset += length; List stringsList = new List(); if (offset < raw.Length && raw[offset] == 0) offset++; while (offset < raw.Length && raw[offset] != 0) { StringBuilder sb = new StringBuilder(); while (offset < raw.Length && raw[offset] != 0) { sb.Append((char)raw[offset]); offset++; } offset++; stringsList.Add(sb.ToString()); } offset++; switch (type) { case 0x00: this.biosInformation = new BIOSInformation( type, handle, data, stringsList.ToArray()); structureList.Add(this.biosInformation); break; case 0x01: this.systemInformation = new SystemInformation( type, handle, data, stringsList.ToArray()); structureList.Add(this.systemInformation); break; case 0x02: this.baseBoardInformation = new BaseBoardInformation( type, handle, data, stringsList.ToArray()); structureList.Add(this.baseBoardInformation); break; case 0x03: this.chassisInformation = new ChassisInformation( type, handle, data, stringsList.ToArray()); structureList.Add(chassisInformation); break; case 0x04: this.processorInformation = new ProcessorInformation( type, handle, data, stringsList.ToArray()); structureList.Add(this.processorInformation); break; case 0x11: MemoryDevice m = new MemoryDevice( type, handle, data, stringsList.ToArray()); memoryDeviceList.Add(m); structureList.Add(m); break; default: structureList.Add(new Structure( type, handle, data, stringsList.ToArray())); break; } } } memoryDevices = memoryDeviceList.ToArray(); table = structureList.ToArray(); } } public string GetReport() { StringBuilder r = new StringBuilder(); if (version != null) { r.Append("SMBIOS Version: "); r.AppendLine(version.ToString(2)); r.AppendLine(); } if (BIOS != null) { r.Append("BIOS Vendor: "); r.AppendLine(BIOS.Vendor); r.Append("BIOS Version: "); r.AppendLine(BIOS.Version); r.AppendLine(); } if (System != null) { r.Append("System Manufacturer: "); r.AppendLine(System.ManufacturerName); r.Append("System Name: "); r.AppendLine(System.ProductName); r.Append("System Version: "); r.AppendLine(System.Version); r.AppendLine(); } if (Board != null) { r.Append("Mainboard Manufacturer: "); r.AppendLine(Board.ManufacturerName); r.Append("Mainboard Name: "); r.AppendLine(Board.ProductName); r.Append("Mainboard Version: "); r.AppendLine(Board.Version); r.Append("Mainboard Serial: "); r.AppendLine(Board.SerialNumber); r.AppendLine(); } if (Chassis != null) { r.Append("Chassis Type: "); r.AppendLine(Chassis.ChassisType.ToString()); r.Append("Chassis Manufacturer: "); r.AppendLine(Chassis.ManufacturerName); r.Append("Chassis Version: "); r.AppendLine(Chassis.Version); r.Append("Chassis Serial: "); r.AppendLine(Chassis.SerialNumber); r.Append("Chassis Asset Tag: "); r.AppendLine(Chassis.AssetTag); if (!String.IsNullOrEmpty(Chassis.SKU)) { r.Append("Chassis SKU: "); r.AppendLine(Chassis.SKU); } r.Append("Chassis Boot Up State: "); r.AppendLine(Chassis.BootUpState.ToString()); r.Append("Chassis Power Supply State: "); r.AppendLine(Chassis.PowerSupplyState.ToString()); r.Append("Chassis Thermal State: "); r.AppendLine(Chassis.ThermalState.ToString()); r.Append("Chassis Power Cords: "); r.AppendLine(Chassis.PowerCords.ToString()); if (Chassis.RackHeight > 0) { r.Append("Chassis Rack Height: "); r.AppendLine(Chassis.RackHeight.ToString()); } r.Append("Chassis Lock Detected: "); r.AppendLine(Chassis.LockDetected ? "Yes" : "No"); r.Append("Chassis Security Status: "); r.AppendLine(Chassis.SecurityStatus.ToString()); r.AppendLine(); } if (Processor != null) { r.Append("Processor Manufacturer: "); r.AppendLine(Processor.ManufacturerName); r.Append("Processor Version: "); r.AppendLine(Processor.Version); r.Append("Processor Core Count: "); r.AppendLine(Processor.CoreCount.ToString()); r.Append("Processor Core Enabled: "); r.AppendLine(Processor.CoreEnabled.ToString()); r.Append("Processor Thread Count: "); r.AppendLine(Processor.ThreadCount.ToString()); r.Append("Processor External Clock: "); r.Append(Processor.ExternalClock); r.AppendLine(" Mhz"); r.AppendLine(); } for (int i = 0; i < MemoryDevices.Length; i++) { r.Append("Memory Device [" + i + "] Manufacturer: "); r.AppendLine(MemoryDevices[i].ManufacturerName); r.Append("Memory Device [" + i + "] Part Number: "); r.AppendLine(MemoryDevices[i].PartNumber); r.Append("Memory Device [" + i + "] Device Locator: "); r.AppendLine(MemoryDevices[i].DeviceLocator); r.Append("Memory Device [" + i + "] Bank Locator: "); r.AppendLine(MemoryDevices[i].BankLocator); r.Append("Memory Device [" + i + "] Speed: "); r.Append(MemoryDevices[i].Speed); r.AppendLine(" MHz"); r.AppendLine(); } if (raw != null) { string base64 = Convert.ToBase64String(raw); r.AppendLine("SMBIOS Table"); r.AppendLine(); for (int i = 0; i < Math.Ceiling(base64.Length / 64.0); i++) { r.Append(" "); for (int j = 0; j < 0x40; j++) { int index = (i << 6) | j; if (index < base64.Length) { r.Append(base64[index]); } } r.AppendLine(); } r.AppendLine(); } return r.ToString(); } public BIOSInformation BIOS { get { return biosInformation; } } public SystemInformation System { get { return systemInformation; } } public BaseBoardInformation Board { get { return baseBoardInformation; } } public ChassisInformation Chassis { get { return chassisInformation; } } public ProcessorInformation Processor { get { return processorInformation; } } public MemoryDevice[] MemoryDevices { get { return memoryDevices; } } public class Structure { private readonly byte type; private readonly ushort handle; private readonly byte[] data; private readonly string[] strings; protected int GetByte(int offset) { if (offset < data.Length && offset >= 0) return data[offset]; else return 0; } protected int GetWord(int offset) { if (offset + 1 < data.Length && offset >= 0) return (data[offset + 1] << 8) | data[offset]; else return 0; } protected string GetString(int offset) { if (offset < data.Length && data[offset] > 0 && data[offset] <= strings.Length) return strings[data[offset] - 1]; else return ""; } public Structure(byte type, ushort handle, byte[] data, string[] strings) { this.type = type; this.handle = handle; this.data = data; this.strings = strings; } public byte Type { get { return type; } } public ushort Handle { get { return handle; } } } public class BIOSInformation : Structure { private readonly string vendor; private readonly string version; public BIOSInformation(string vendor, string version) : base (0x00, 0, null, null) { this.vendor = vendor; this.version = version; } public BIOSInformation(byte type, ushort handle, byte[] data, string[] strings) : base(type, handle, data, strings) { this.vendor = GetString(0x04); this.version = GetString(0x05); } public string Vendor { get { return vendor; } } public string Version { get { return version; } } } public class SystemInformation : Structure { private readonly string manufacturerName; private readonly string productName; private readonly string version; private readonly string serialNumber; private readonly string family; public SystemInformation(string manufacturerName, string productName, string version, string serialNumber, string family) : base (0x01, 0, null, null) { this.manufacturerName = manufacturerName; this.productName = productName; this.version = version; this.serialNumber = serialNumber; this.family = family; } public SystemInformation(byte type, ushort handle, byte[] data, string[] strings) : base(type, handle, data, strings) { this.manufacturerName = GetString(0x04); this.productName = GetString(0x05); this.version = GetString(0x06); this.serialNumber = GetString(0x07); this.family = GetString(0x1A); } public string ManufacturerName { get { return manufacturerName; } } public string ProductName { get { return productName; } } public string Version { get { return version; } } public string SerialNumber { get { return serialNumber; } } public string Family { get { return family; } } } public class ChassisInformation : Structure { public ChassisInformation(byte type, ushort handle, byte[] data, string[] strings) : base(type, handle, data, strings) { ManufacturerName = GetString(0x04).Trim(); Version = GetString(0x06).Trim(); SerialNumber = GetString(0x07).Trim(); AssetTag = GetString(0x08).Trim(); RackHeight = GetByte(0x11); PowerCords = GetByte(0x12); SKU = GetString(0x15).Trim(); LockDetected = (GetByte(0x05) & 128) == 128; ChassisType = (ChassisType)(GetByte(0x05) & 127); BootUpState = (ChassisStates)GetByte(0x09); PowerSupplyState = (ChassisStates)GetByte(0x0A); ThermalState = (ChassisStates)GetByte(0x0B); SecurityStatus = (ChassisSecurityStatus)GetByte(0x0C); } public string ManufacturerName { get; private set; } public string Version { get; private set; } public string SerialNumber { get; private set; } public string AssetTag { get; private set; } public string SKU { get; private set; } public int RackHeight { get; private set; } public int PowerCords { get; private set; } public ChassisType ChassisType { get; private set; } public ChassisStates BootUpState { get; private set; } public ChassisStates PowerSupplyState { get; private set; } public ChassisStates ThermalState { get; private set; } public ChassisSecurityStatus SecurityStatus { get; set; } public bool LockDetected { get; set; } } public enum ChassisType { Other = 1, Unknown, Desktop, LowProfileDesktop, PizzaBox, MiniTower, Tower, Portable, Laptop, Notebook, HandHeld, DockingStation, AllInOne, SubNotebook, SpaceSaving, LunchBox, MainServerChassis, ExpansionChassis, SubChassis, BusExpansionChassis, PeripheralChassis, RAIDChassis, RackMountChassis, SealedCasePC, MultiSystemChassis, CompactPCI, AdvancedTCA, Blade, BladeEnclosure, Tablet, Convertible, Detachable, IoTGateway, EmbeddedPC, MiniPC, StickPC } public enum ChassisStates { Other = 1, Unknown, Safe, Warning, Critical, NonRecoverable } public enum ChassisSecurityStatus { Other = 1, Unknown, None, ExternalInterfaceLockedOut, ExternalInterfaceEnabled } public class BaseBoardInformation : Structure { private readonly string manufacturerName; private readonly string productName; private readonly string version; private readonly string serialNumber; public BaseBoardInformation(string manufacturerName, string productName, string version, string serialNumber) : base(0x02, 0, null, null) { this.manufacturerName = manufacturerName; this.productName = productName; this.version = version; this.serialNumber = serialNumber; } public BaseBoardInformation(byte type, ushort handle, byte[] data, string[] strings) : base(type, handle, data, strings) { this.manufacturerName = GetString(0x04).Trim(); this.productName = GetString(0x05).Trim(); this.version = GetString(0x06).Trim(); this.serialNumber = GetString(0x07).Trim(); } public string ManufacturerName { get { return manufacturerName; } } public string ProductName { get { return productName; } } public string Version { get { return version; } } public string SerialNumber { get { return serialNumber; } } } public class ProcessorInformation : Structure { public ProcessorInformation(byte type, ushort handle, byte[] data, string[] strings) : base(type, handle, data, strings) { this.ManufacturerName = GetString(0x07).Trim(); this.Version = GetString(0x10).Trim(); this.CoreCount = GetByte(0x23) != 255 ? GetByte(0x23) : GetWord(0x2A); this.CoreEnabled = GetByte(0x24) != 255 ? GetByte(0x24) : GetWord(0x2C); this.ThreadCount = GetByte(0x25) != 255 ? GetByte(0x25) : GetWord(0x2E); this.ExternalClock = GetWord(0x12); } public string ManufacturerName { get; private set; } public string Version { get; private set; } public int CoreCount { get; private set; } public int CoreEnabled { get; private set; } public int ThreadCount { get; private set; } public int ExternalClock { get; private set; } } public class MemoryDevice : Structure { private readonly string deviceLocator; private readonly string bankLocator; private readonly string manufacturerName; private readonly string serialNumber; private readonly string partNumber; private readonly int speed; public MemoryDevice(byte type, ushort handle, byte[] data, string[] strings) : base(type, handle, data, strings) { this.deviceLocator = GetString(0x10).Trim(); this.bankLocator = GetString(0x11).Trim(); this.manufacturerName = GetString(0x17).Trim(); this.serialNumber = GetString(0x18).Trim(); this.partNumber = GetString(0x1A).Trim(); this.speed = GetWord(0x15); } public string DeviceLocator { get { return deviceLocator; } } public string BankLocator { get { return bankLocator; } } public string ManufacturerName { get { return manufacturerName; } } public string SerialNumber { get { return serialNumber; } } public string PartNumber { get { return partNumber; } } public int Speed { get { return speed; } } } } }