Hardware/SMBIOS.cs
author moel.mich
Sat, 27 Oct 2012 11:40:28 +0000
changeset 384 76f859f4aea1
parent 373 3b8443edb0e6
permissions -rw-r--r--
Reduced the amount of dynamic memory allocation when reading from the T-Balancer or creating tray icons.
moel@370
     1
/*
moel@370
     2
 
moel@370
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@370
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@370
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@370
     6
 
moel@370
     7
  Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@370
     8
	
moel@370
     9
*/
moel@370
    10
moel@370
    11
using System;
moel@370
    12
using System.Collections.Generic;
moel@370
    13
using System.IO;
moel@370
    14
using System.Management;
moel@370
    15
using System.Text;
moel@370
    16
moel@370
    17
namespace OpenHardwareMonitor.Hardware {
moel@370
    18
moel@370
    19
  internal class SMBIOS {
moel@370
    20
moel@370
    21
    private readonly byte[] raw;
moel@370
    22
    private readonly Structure[] table;
moel@370
    23
moel@370
    24
    private readonly Version version;
moel@370
    25
    private readonly BIOSInformation biosInformation;
moel@370
    26
    private readonly SystemInformation systemInformation;
moel@370
    27
    private readonly BaseBoardInformation baseBoardInformation;
moel@378
    28
    private readonly ProcessorInformation processorInformation;
moel@370
    29
    private readonly MemoryDevice[] memoryDevices;
moel@370
    30
moel@370
    31
    private static string ReadSysFS(string path) {
moel@370
    32
      try {
moel@370
    33
        if (File.Exists(path)) {
moel@370
    34
          using (StreamReader reader = new StreamReader(path)) 
moel@370
    35
            return reader.ReadLine();
moel@370
    36
        } else {
moel@370
    37
          return null;
moel@370
    38
        }
moel@370
    39
      } catch {
moel@370
    40
        return null;
moel@370
    41
      }
moel@370
    42
    }
moel@370
    43
    
moel@370
    44
    public SMBIOS() {
moel@370
    45
      int p = (int)Environment.OSVersion.Platform;
moel@370
    46
      if ((p == 4) || (p == 128)) {
moel@370
    47
        this.raw = null;
moel@370
    48
        this.table = null;
moel@370
    49
        
moel@370
    50
        string boardVendor = ReadSysFS("/sys/class/dmi/id/board_vendor");
moel@370
    51
        string boardName = ReadSysFS("/sys/class/dmi/id/board_name");        
moel@370
    52
        string boardVersion = ReadSysFS("/sys/class/dmi/id/board_version");        
moel@370
    53
        this.baseBoardInformation = new BaseBoardInformation(
moel@370
    54
          boardVendor, boardName, boardVersion, null);
moel@370
    55
moel@370
    56
        string systemVendor = ReadSysFS("/sys/class/dmi/id/sys_vendor");
moel@370
    57
        string productName = ReadSysFS("/sys/class/dmi/id/product_name");
moel@370
    58
        string productVersion = ReadSysFS("/sys/class/dmi/id/product_version");    
moel@370
    59
        this.systemInformation = new SystemInformation(systemVendor, 
moel@370
    60
          productName, productVersion, null, null);
moel@370
    61
moel@370
    62
        string biosVendor = ReadSysFS("/sys/class/dmi/id/bios_vendor");
moel@370
    63
        string biosVersion = ReadSysFS("/sys/class/dmi/id/bios_version");
moel@370
    64
        this.biosInformation = new BIOSInformation(biosVendor, biosVersion);
moel@370
    65
moel@370
    66
        this.memoryDevices = new MemoryDevice[0];
moel@370
    67
      } else {              
moel@370
    68
        List<Structure> structureList = new List<Structure>();
moel@370
    69
        List<MemoryDevice> memoryDeviceList = new List<MemoryDevice>();
moel@370
    70
moel@370
    71
        raw = null;
moel@370
    72
        byte majorVersion = 0;
moel@370
    73
        byte minorVersion = 0;
moel@370
    74
        try {
moel@370
    75
          ManagementObjectCollection collection;
moel@370
    76
          using (ManagementObjectSearcher searcher = 
moel@370
    77
            new ManagementObjectSearcher("root\\WMI", 
moel@370
    78
              "SELECT * FROM MSSMBios_RawSMBiosTables")) {
moel@370
    79
            collection = searcher.Get();
moel@370
    80
          }
moel@370
    81
         
moel@370
    82
          foreach (ManagementObject mo in collection) {
moel@370
    83
            raw = (byte[])mo["SMBiosData"];
moel@370
    84
            majorVersion = (byte)mo["SmbiosMajorVersion"];
moel@370
    85
            minorVersion = (byte)mo["SmbiosMinorVersion"];            
moel@370
    86
            break;
moel@370
    87
          }
moel@378
    88
        } catch { }      
moel@370
    89
moel@370
    90
        if (majorVersion > 0 || minorVersion > 0)
moel@370
    91
          version = new Version(majorVersion, minorVersion);
moel@370
    92
  
moel@370
    93
        if (raw != null && raw.Length > 0) {
moel@370
    94
          int offset = 0;
moel@370
    95
          byte type = raw[offset];
moel@370
    96
          while (offset + 4 < raw.Length && type != 127) {
moel@370
    97
  
moel@370
    98
            type = raw[offset];
moel@370
    99
            int length = raw[offset + 1];
moel@370
   100
            ushort handle = (ushort)((raw[offset + 2] << 8) | raw[offset + 3]);
moel@370
   101
  
moel@370
   102
            if (offset + length > raw.Length)
moel@370
   103
              break;
moel@370
   104
            byte[] data = new byte[length];
moel@370
   105
            Array.Copy(raw, offset, data, 0, length);
moel@370
   106
            offset += length;
moel@370
   107
  
moel@370
   108
            List<string> stringsList = new List<string>();
moel@370
   109
            if (offset < raw.Length && raw[offset] == 0)
moel@370
   110
              offset++;
moel@370
   111
  
moel@370
   112
            while (offset < raw.Length && raw[offset] != 0) {
moel@370
   113
              StringBuilder sb = new StringBuilder();
moel@370
   114
              while (offset < raw.Length && raw[offset] != 0) {
moel@370
   115
                sb.Append((char)raw[offset]); offset++;
moel@370
   116
              }
moel@370
   117
              offset++;
moel@370
   118
              stringsList.Add(sb.ToString());
moel@370
   119
            }
moel@370
   120
            offset++;
moel@370
   121
            switch (type) {
moel@370
   122
              case 0x00:
moel@370
   123
                this.biosInformation = new BIOSInformation(
moel@370
   124
                  type, handle, data, stringsList.ToArray());
moel@370
   125
                structureList.Add(this.biosInformation); break;
moel@370
   126
              case 0x01:
moel@370
   127
                this.systemInformation = new SystemInformation(
moel@370
   128
                  type, handle, data, stringsList.ToArray());
moel@370
   129
                structureList.Add(this.systemInformation); break;
moel@370
   130
              case 0x02: this.baseBoardInformation = new BaseBoardInformation(
moel@370
   131
                  type, handle, data, stringsList.ToArray());
moel@370
   132
                structureList.Add(this.baseBoardInformation); break;
moel@378
   133
              case 0x04: this.processorInformation = new ProcessorInformation(
moel@378
   134
                  type, handle, data, stringsList.ToArray());
moel@378
   135
                structureList.Add(this.processorInformation); break;
moel@370
   136
              case 0x11: MemoryDevice m = new MemoryDevice(
moel@370
   137
                  type, handle, data, stringsList.ToArray());
moel@370
   138
                memoryDeviceList.Add(m);
moel@370
   139
                structureList.Add(m); break;
moel@370
   140
              default: structureList.Add(new Structure(
moel@370
   141
                type, handle, data, stringsList.ToArray())); break;
moel@370
   142
            }
moel@370
   143
          }
moel@370
   144
        }
moel@370
   145
moel@370
   146
        memoryDevices = memoryDeviceList.ToArray();
moel@370
   147
        table = structureList.ToArray();
moel@370
   148
      }
moel@370
   149
    }
moel@370
   150
moel@370
   151
    public string GetReport() {
moel@370
   152
      StringBuilder r = new StringBuilder();
moel@370
   153
moel@370
   154
      if (version != null) {
moel@370
   155
        r.Append("SMBIOS Version: "); r.AppendLine(version.ToString(2));
moel@370
   156
        r.AppendLine();
moel@370
   157
      }
moel@370
   158
moel@370
   159
      if (BIOS != null) {
moel@370
   160
        r.Append("BIOS Vendor: "); r.AppendLine(BIOS.Vendor);
moel@370
   161
        r.Append("BIOS Version: "); r.AppendLine(BIOS.Version);
moel@370
   162
        r.AppendLine();
moel@370
   163
      }
moel@370
   164
moel@370
   165
      if (System != null) {
moel@370
   166
        r.Append("System Manufacturer: ");
moel@370
   167
        r.AppendLine(System.ManufacturerName);
moel@370
   168
        r.Append("System Name: ");
moel@370
   169
        r.AppendLine(System.ProductName);
moel@370
   170
        r.Append("System Version: ");
moel@370
   171
        r.AppendLine(System.Version);
moel@370
   172
        r.AppendLine();
moel@370
   173
      }
moel@370
   174
moel@370
   175
      if (Board != null) {
moel@370
   176
        r.Append("Mainboard Manufacturer: ");
moel@370
   177
        r.AppendLine(Board.ManufacturerName);
moel@370
   178
        r.Append("Mainboard Name: ");
moel@370
   179
        r.AppendLine(Board.ProductName);
moel@370
   180
        r.Append("Mainboard Version: ");
moel@370
   181
        r.AppendLine(Board.Version);
moel@370
   182
        r.AppendLine();
moel@370
   183
      }
moel@370
   184
moel@378
   185
      if (Processor != null) {
moel@378
   186
        r.Append("Processor Manufacturer: ");
moel@378
   187
        r.AppendLine(Processor.ManufacturerName);
moel@378
   188
        r.Append("Processor Version: ");
moel@378
   189
        r.AppendLine(Processor.Version);
moel@378
   190
        r.Append("Processor Core Count: ");
moel@378
   191
        r.AppendLine(Processor.CoreCount.ToString());
moel@378
   192
        r.Append("Processor Core Enabled: ");
moel@378
   193
        r.AppendLine(Processor.CoreEnabled.ToString());
moel@378
   194
        r.Append("Processor Thread Count: ");
moel@378
   195
        r.AppendLine(Processor.ThreadCount.ToString());
moel@378
   196
        r.Append("Processor External Clock: ");
moel@378
   197
        r.Append(Processor.ExternalClock);
moel@378
   198
        r.AppendLine(" Mhz");
moel@378
   199
        r.AppendLine();
moel@378
   200
      }
moel@378
   201
moel@370
   202
      for (int i = 0; i < MemoryDevices.Length; i++) {        
moel@370
   203
        r.Append("Memory Device [" + i + "] Manufacturer: ");
moel@370
   204
        r.AppendLine(MemoryDevices[i].ManufacturerName);
moel@370
   205
        r.Append("Memory Device [" + i + "] Part Number: ");
moel@370
   206
        r.AppendLine(MemoryDevices[i].PartNumber);
moel@373
   207
        r.Append("Memory Device [" + i + "] Device Locator: ");
moel@373
   208
        r.AppendLine(MemoryDevices[i].DeviceLocator);
moel@373
   209
        r.Append("Memory Device [" + i + "] Bank Locator: ");
moel@373
   210
        r.AppendLine(MemoryDevices[i].BankLocator);
moel@378
   211
        r.Append("Memory Device [" + i + "] Speed: ");
moel@378
   212
        r.Append(MemoryDevices[i].Speed);
moel@378
   213
        r.AppendLine(" MHz");
moel@370
   214
        r.AppendLine();
moel@370
   215
      }
moel@370
   216
moel@370
   217
      if (raw != null) {
moel@370
   218
        string base64 = Convert.ToBase64String(raw);
moel@370
   219
        r.AppendLine("SMBIOS Table");
moel@370
   220
        r.AppendLine();
moel@370
   221
moel@370
   222
        for (int i = 0; i < Math.Ceiling(base64.Length / 64.0); i++) {
moel@370
   223
          r.Append(" ");
moel@370
   224
          for (int j = 0; j < 0x40; j++) {
moel@370
   225
            int index = (i << 6) | j;
moel@370
   226
            if (index < base64.Length) {              
moel@370
   227
              r.Append(base64[index]);
moel@370
   228
            }
moel@370
   229
          }
moel@370
   230
          r.AppendLine();
moel@370
   231
        }
moel@370
   232
        r.AppendLine();
moel@370
   233
      }
moel@370
   234
moel@370
   235
      return r.ToString();
moel@370
   236
    }
moel@370
   237
moel@370
   238
    public BIOSInformation BIOS {
moel@370
   239
      get { return biosInformation; }
moel@370
   240
    }
moel@370
   241
moel@370
   242
    public SystemInformation System {
moel@370
   243
      get { return systemInformation; }
moel@370
   244
    }
moel@370
   245
moel@370
   246
    public BaseBoardInformation Board {
moel@370
   247
      get { return baseBoardInformation; }
moel@370
   248
    }
moel@370
   249
moel@378
   250
moel@378
   251
    public ProcessorInformation Processor {
moel@378
   252
      get { return processorInformation; }
moel@378
   253
    }
moel@378
   254
moel@370
   255
    public MemoryDevice[] MemoryDevices {
moel@370
   256
      get { return memoryDevices; }
moel@370
   257
    }
moel@370
   258
moel@370
   259
    public class Structure {
moel@370
   260
      private readonly byte type;
moel@370
   261
      private readonly ushort handle;
moel@370
   262
moel@370
   263
      private readonly byte[] data;
moel@370
   264
      private readonly string[] strings;
moel@370
   265
moel@378
   266
      protected int GetByte(int offset) {
moel@378
   267
        if (offset < data.Length && offset >= 0)
moel@378
   268
          return data[offset];
moel@378
   269
        else
moel@378
   270
          return 0;
moel@378
   271
      }
moel@378
   272
moel@378
   273
      protected int GetWord(int offset) {
moel@378
   274
        if (offset + 1 < data.Length && offset >= 0)
moel@378
   275
          return (data[offset + 1] << 8) | data[offset];
moel@378
   276
        else
moel@378
   277
          return 0;
moel@378
   278
      }
moel@378
   279
moel@370
   280
      protected string GetString(int offset) {
moel@370
   281
        if (offset < data.Length && data[offset] > 0 &&
moel@370
   282
         data[offset] <= strings.Length)
moel@370
   283
          return strings[data[offset] - 1];
moel@370
   284
        else
moel@370
   285
          return "";
moel@370
   286
      }
moel@370
   287
moel@370
   288
      public Structure(byte type, ushort handle, byte[] data, string[] strings) 
moel@370
   289
      {
moel@370
   290
        this.type = type;
moel@370
   291
        this.handle = handle;
moel@370
   292
        this.data = data;
moel@370
   293
        this.strings = strings;
moel@370
   294
      }
moel@370
   295
moel@370
   296
      public byte Type { get { return type; } }
moel@370
   297
moel@370
   298
      public ushort Handle { get { return handle; } }
moel@370
   299
    }
moel@370
   300
      
moel@370
   301
    public class BIOSInformation : Structure {
moel@370
   302
moel@370
   303
      private readonly string vendor;
moel@370
   304
      private readonly string version;
moel@370
   305
      
moel@370
   306
      public BIOSInformation(string vendor, string version) 
moel@370
   307
        : base (0x00, 0, null, null) 
moel@370
   308
      {
moel@370
   309
        this.vendor = vendor;
moel@370
   310
        this.version = version;
moel@370
   311
      }
moel@370
   312
      
moel@370
   313
      public BIOSInformation(byte type, ushort handle, byte[] data,
moel@370
   314
        string[] strings)
moel@370
   315
        : base(type, handle, data, strings) 
moel@370
   316
      {
moel@370
   317
        this.vendor = GetString(0x04);
moel@370
   318
        this.version = GetString(0x05);
moel@370
   319
      }
moel@370
   320
moel@370
   321
      public string Vendor { get { return vendor; } }
moel@370
   322
moel@370
   323
      public string Version { get { return version; } }
moel@370
   324
    }
moel@370
   325
moel@370
   326
    public class SystemInformation : Structure {
moel@370
   327
moel@370
   328
      private readonly string manufacturerName;
moel@370
   329
      private readonly string productName;
moel@370
   330
      private readonly string version;
moel@370
   331
      private readonly string serialNumber;
moel@370
   332
      private readonly string family;
moel@370
   333
moel@370
   334
      public SystemInformation(string manufacturerName, string productName, 
moel@370
   335
        string version, string serialNumber, string family) 
moel@370
   336
        : base (0x01, 0, null, null) 
moel@370
   337
      {
moel@370
   338
        this.manufacturerName = manufacturerName;
moel@370
   339
        this.productName = productName;
moel@370
   340
        this.version = version;
moel@370
   341
        this.serialNumber = serialNumber;
moel@370
   342
        this.family = family;
moel@370
   343
      }
moel@370
   344
moel@370
   345
      public SystemInformation(byte type, ushort handle, byte[] data,
moel@370
   346
        string[] strings)
moel@370
   347
        : base(type, handle, data, strings) 
moel@370
   348
      {
moel@370
   349
        this.manufacturerName = GetString(0x04);
moel@370
   350
        this.productName = GetString(0x05);
moel@370
   351
        this.version = GetString(0x06);
moel@370
   352
        this.serialNumber = GetString(0x07);
moel@370
   353
        this.family = GetString(0x1A);
moel@370
   354
      }
moel@370
   355
moel@370
   356
      public string ManufacturerName { get { return manufacturerName; } }
moel@370
   357
moel@370
   358
      public string ProductName { get { return productName; } }
moel@370
   359
moel@370
   360
      public string Version { get { return version; } }
moel@370
   361
moel@370
   362
      public string SerialNumber { get { return serialNumber; } }
moel@370
   363
moel@370
   364
      public string Family { get { return family; } }
moel@370
   365
moel@370
   366
    }
moel@370
   367
moel@370
   368
    public class BaseBoardInformation : Structure {
moel@370
   369
moel@370
   370
      private readonly string manufacturerName;
moel@370
   371
      private readonly string productName;
moel@370
   372
      private readonly string version;
moel@370
   373
      private readonly string serialNumber;
moel@370
   374
      
moel@370
   375
      public BaseBoardInformation(string manufacturerName, string productName, 
moel@370
   376
        string version, string serialNumber) 
moel@370
   377
        : base(0x02, 0, null, null) 
moel@370
   378
      {
moel@370
   379
        this.manufacturerName = manufacturerName;
moel@370
   380
        this.productName = productName;
moel@370
   381
        this.version = version;
moel@370
   382
        this.serialNumber = serialNumber;
moel@370
   383
      }
moel@370
   384
      
moel@370
   385
      public BaseBoardInformation(byte type, ushort handle, byte[] data,
moel@370
   386
        string[] strings)
moel@370
   387
        : base(type, handle, data, strings) {
moel@370
   388
moel@370
   389
        this.manufacturerName = GetString(0x04).Trim();
moel@370
   390
        this.productName = GetString(0x05).Trim();
moel@370
   391
        this.version = GetString(0x06).Trim();
moel@370
   392
        this.serialNumber = GetString(0x07).Trim();               
moel@370
   393
      }
moel@370
   394
      
moel@370
   395
      public string ManufacturerName { get { return manufacturerName; } }
moel@370
   396
moel@370
   397
      public string ProductName { get { return productName; } }
moel@370
   398
moel@370
   399
      public string Version { get { return version; } }
moel@370
   400
moel@370
   401
      public string SerialNumber { get { return serialNumber; } }
moel@370
   402
moel@370
   403
    }
moel@370
   404
moel@378
   405
    public class ProcessorInformation : Structure {
moel@378
   406
moel@378
   407
      public ProcessorInformation(byte type, ushort handle, byte[] data,
moel@378
   408
        string[] strings)
moel@378
   409
        : base(type, handle, data, strings) 
moel@378
   410
      {
moel@378
   411
        this.ManufacturerName = GetString(0x07).Trim();
moel@378
   412
        this.Version = GetString(0x10).Trim();
moel@378
   413
        this.CoreCount = GetByte(0x23);
moel@378
   414
        this.CoreEnabled = GetByte(0x24);
moel@378
   415
        this.ThreadCount = GetByte(0x25);
moel@378
   416
        this.ExternalClock = GetWord(0x12);
moel@378
   417
      }
moel@378
   418
moel@378
   419
      public string ManufacturerName { get; private set; }
moel@378
   420
moel@378
   421
      public string Version { get; private set; }
moel@378
   422
moel@378
   423
      public int CoreCount { get; private set; }
moel@378
   424
moel@378
   425
      public int CoreEnabled { get; private set; }
moel@378
   426
moel@378
   427
      public int ThreadCount { get; private set; }
moel@378
   428
     
moel@378
   429
      public int ExternalClock { get; private set; }
moel@378
   430
    }
moel@378
   431
moel@370
   432
    public class MemoryDevice : Structure {
moel@370
   433
moel@373
   434
      private readonly string deviceLocator;
moel@373
   435
      private readonly string bankLocator;
moel@370
   436
      private readonly string manufacturerName;
moel@370
   437
      private readonly string serialNumber;
moel@378
   438
      private readonly string partNumber;
moel@378
   439
      private readonly int speed;
moel@370
   440
moel@370
   441
      public MemoryDevice(byte type, ushort handle, byte[] data,
moel@370
   442
        string[] strings)
moel@373
   443
        : base(type, handle, data, strings) 
moel@373
   444
      {
moel@373
   445
        this.deviceLocator = GetString(0x10).Trim();
moel@373
   446
        this.bankLocator = GetString(0x11).Trim();
moel@370
   447
        this.manufacturerName = GetString(0x17).Trim();
moel@370
   448
        this.serialNumber = GetString(0x18).Trim();
moel@370
   449
        this.partNumber = GetString(0x1A).Trim();
moel@378
   450
        this.speed = GetWord(0x15);
moel@370
   451
      }
moel@370
   452
moel@373
   453
      public string DeviceLocator { get { return deviceLocator; } }
moel@373
   454
moel@373
   455
      public string BankLocator { get { return bankLocator; } }
moel@373
   456
moel@370
   457
      public string ManufacturerName { get { return manufacturerName; } }
moel@370
   458
moel@370
   459
      public string SerialNumber { get { return serialNumber; } }
moel@370
   460
moel@370
   461
      public string PartNumber { get { return partNumber; } }
moel@370
   462
moel@378
   463
      public int Speed { get { return speed; } }
moel@373
   464
moel@370
   465
    }
moel@370
   466
  }
moel@370
   467
}