2018-03-12 21:16:06 -04:00
|
|
|
/*
|
2019-02-04 21:06:01 -05:00
|
|
|
Copyright 2018 Intel Corporation
|
2018-03-12 21:16:06 -04:00
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
try { Object.defineProperty(Array.prototype, "peek", { value: function () { return (this.length > 0 ? this[this.length - 1] : undefined); } }); } catch (e) { }
|
|
|
|
try { Object.defineProperty(String.prototype, "replaceAll", { value: function replaceAll(oldVal, newVal) { return (this.split(oldVal).join(newVal)); } }); } catch (e) { }
|
|
|
|
|
|
|
|
var RSMB = 1381190978;
|
|
|
|
var memoryLocation = { 0x1: 'Other', 0x2: 'Unknown', 0x3: 'System Board', 0x4: 'ISA', 0x5: 'EISA', 0x6: 'PCI', 0x7: 'MCA', 0x8: 'PCMCIA', 0x9: 'Proprietary', 0xA: 'NuBus', 0xA0: 'PC-98/C20', 0xA1: 'PC-98/C24', 0xA2: 'PC-98/E', 0xA3: 'PC-98/LB' };
|
|
|
|
var wakeReason = ['Reserved', 'Other', 'Unknown', 'APM Timer', 'Modem Ring', 'LAN', 'Power Switch', 'PCI', 'AC Power'];
|
|
|
|
|
2018-09-18 22:41:59 -04:00
|
|
|
// Fill the left with zeros until the string is of a given length
|
|
|
|
function zeroLeftPad(str, len)
|
|
|
|
{
|
|
|
|
if ((len == null) && (typeof (len) != 'number')) { return null; }
|
|
|
|
if (str == null) str = ''; // If null, this is to generate zero leftpad string
|
|
|
|
var zlp = '';
|
|
|
|
for (var i = 0; i < len - str.length; i++) { zlp += '0'; }
|
|
|
|
return zlp + str;
|
|
|
|
}
|
|
|
|
|
|
|
|
function SMBiosTables()
|
|
|
|
{
|
2018-03-12 21:16:06 -04:00
|
|
|
this._ObjectID = 'SMBiosTable';
|
|
|
|
if (process.platform == 'win32') {
|
|
|
|
this._marshal = require('_GenericMarshal');
|
|
|
|
this._native = this._marshal.CreateNativeProxy("Kernel32.dll");
|
|
|
|
|
|
|
|
this._native.CreateMethod('EnumSystemFirmwareTables');
|
|
|
|
this._native.CreateMethod('GetSystemFirmwareTable');
|
|
|
|
}
|
|
|
|
if (process.platform == 'linux') {
|
|
|
|
this._canonicalizeData = function _canonicalizeData(data) {
|
|
|
|
var lines = data.toString().split('Header and Data:\x0A');
|
|
|
|
var MemoryStream = require('MemoryStream');
|
|
|
|
var ms = new MemoryStream();
|
|
|
|
|
|
|
|
for (var i = 1; i < lines.length; ++i) {
|
|
|
|
var tokens = lines[i].split('Strings:\x0A');
|
|
|
|
var header = tokens[0].split('\x0A\x0A')[0].replaceAll('\x0A', '').trim().replaceAll(' ', '').replaceAll('\x09', '');
|
|
|
|
ms.write(Buffer.from(header, 'hex'));
|
|
|
|
if (tokens.length > 1) {
|
|
|
|
var strings = tokens[1].split('\x0A\x0A')[0].split('\x0A');
|
|
|
|
var stringsFinal = [];
|
|
|
|
for (var strx in strings) {
|
|
|
|
var tmp = strings[strx].trim().replaceAll(' ', '').replaceAll('\x09', '');
|
|
|
|
if (!(tmp[0] == '"')) { stringsFinal.push(tmp); }
|
|
|
|
}
|
|
|
|
ms.write(Buffer.from(stringsFinal.join(''), 'hex'));
|
|
|
|
ms.write(Buffer.from('00', 'hex'));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ms.write(Buffer.from('0000', 'hex'));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var retVal = ms.buffer;
|
|
|
|
retVal.ms = ms;
|
|
|
|
return (retVal);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
this._parse = function _parse(SMData) {
|
|
|
|
var ret = {};
|
|
|
|
var pbyte;
|
|
|
|
var i = 0
|
|
|
|
var SMData;
|
|
|
|
var structcount = 0;
|
|
|
|
|
2019-02-04 21:06:01 -05:00
|
|
|
while (SMData && i < SMData.length)
|
|
|
|
{
|
2018-03-12 21:16:06 -04:00
|
|
|
var SMtype = SMData[i];
|
|
|
|
var SMlength = SMData[i + 1];
|
|
|
|
|
|
|
|
if (!ret[SMtype]) { ret[SMtype] = []; }
|
|
|
|
ret[SMtype].push(SMData.slice(i + 4, i + SMlength));
|
|
|
|
if (process.platform == 'win32') { ret[SMtype].peek()._ext = pbyte; }
|
|
|
|
i += SMlength;
|
|
|
|
|
|
|
|
ret[SMtype].peek()._strings = [];
|
|
|
|
|
2019-02-04 21:06:01 -05:00
|
|
|
while (SMData[i] != 0 && i <= SMData.length)
|
|
|
|
{
|
2018-03-12 21:16:06 -04:00
|
|
|
var strstart = i;
|
|
|
|
|
|
|
|
// Start of String, find end of string
|
2019-02-04 21:06:01 -05:00
|
|
|
while (SMData[i++] != 0 && i <= SMData.length);
|
|
|
|
try
|
|
|
|
{
|
|
|
|
ret[SMtype].peek()._strings.push(SMData.slice(strstart, i).toString().trim());
|
|
|
|
}
|
|
|
|
catch (ee)
|
|
|
|
{
|
|
|
|
}
|
2018-03-12 21:16:06 -04:00
|
|
|
}
|
|
|
|
i += (ret[SMtype].peek()._strings.length == 0) ? 2 : 1;
|
|
|
|
++structcount;
|
|
|
|
//console.log('End of Table[' + SMtype + ']: ' + i);
|
|
|
|
}
|
|
|
|
//console.log('Struct Count = ' + structcount);
|
|
|
|
return (ret);
|
|
|
|
};
|
|
|
|
this.get = function get(callback) {
|
|
|
|
if (process.platform == 'win32') {
|
|
|
|
var size = this._native.GetSystemFirmwareTable(RSMB, 0, 0, 0).Val;
|
|
|
|
//console.log('Table Size: ' + size);
|
|
|
|
|
|
|
|
var PtrSize = this._marshal.CreatePointer()._size;
|
|
|
|
var buffer = this._marshal.CreateVariable(size);
|
|
|
|
var written = this._native.GetSystemFirmwareTable(RSMB, 0, buffer, size).Val;
|
|
|
|
//console.log('Written Size: ' + written);
|
|
|
|
|
|
|
|
var rawBuffer = buffer.toBuffer();
|
|
|
|
var length = buffer.Deref(4, 4).toBuffer().readUInt32LE(0);
|
|
|
|
|
|
|
|
pbyte = buffer.Deref(8, length);
|
|
|
|
SMData = pbyte.toBuffer();
|
|
|
|
|
|
|
|
if (callback) { callback.apply(this, [this._parse(SMData)]); return; } else { return (this._parse(SMData)); }
|
|
|
|
}
|
|
|
|
if (process.platform == 'linux') {
|
|
|
|
var MemoryStream = require('MemoryStream');
|
|
|
|
this.child = require('child_process').execFile('/usr/sbin/dmidecode', ['dmidecode', '-u']);
|
|
|
|
this.child.SMBiosTable = this;
|
|
|
|
this.child.ms = new MemoryStream();
|
2018-09-18 22:41:59 -04:00
|
|
|
this.child.ms.callback = callback;
|
2018-03-12 21:16:06 -04:00
|
|
|
this.child.ms.child = this.child;
|
|
|
|
this.child.stdout.on('data', function (buffer) { this.parent.ms.write(buffer); });
|
|
|
|
this.child.on('exit', function () { this.ms.end(); });
|
|
|
|
this.child.ms.on('end', function () {
|
|
|
|
//console.log('read ' + this.buffer.length + ' bytes');
|
2018-09-18 22:41:59 -04:00
|
|
|
if (this.buffer.length < 300) {
|
|
|
|
//console.log('Not enough permission to read SMBiosTable');
|
2018-03-12 21:16:06 -04:00
|
|
|
if (this.callback) { this.callback.apply(this.child.SMBiosTable, []); }
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var SMData = this.child.SMBiosTable._canonicalizeData(this.buffer);
|
|
|
|
var j = this.child.SMBiosTable._parse(SMData);
|
|
|
|
if (this.callback) { this.callback.apply(this.child.SMBiosTable, [j]); }
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2018-10-30 16:01:44 -04:00
|
|
|
if (callback) { callback.apply(this, [null]); return; } else { return (null); }
|
2018-03-12 21:16:06 -04:00
|
|
|
};
|
|
|
|
this.parse = function parse(data) {
|
|
|
|
var r = {};
|
2018-10-30 16:01:44 -04:00
|
|
|
try
|
|
|
|
{
|
|
|
|
r.processorInfo = this.processorInfo(data);
|
|
|
|
}
|
|
|
|
catch(e)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
r.memoryInfo = this.memoryInfo(data);
|
|
|
|
}
|
|
|
|
catch(e)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
r.systemInfo = this.systemInfo(data);
|
|
|
|
}
|
|
|
|
catch(e)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
r.systemSlots = this.systemInfo(data);
|
|
|
|
}
|
|
|
|
catch(e)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
|
|
|
r.amtInfo = this.amtInfo(data);
|
|
|
|
}
|
|
|
|
catch(e)
|
|
|
|
{
|
|
|
|
}
|
2020-04-06 20:21:19 -04:00
|
|
|
try
|
|
|
|
{
|
|
|
|
if (JSON.stringify(r).length > 65535) { r = {}; }
|
|
|
|
}
|
|
|
|
catch(ee)
|
|
|
|
{}
|
2018-03-12 21:16:06 -04:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
this.processorInfo = function processorInfo(data) {
|
|
|
|
if (!data) { throw ('no data'); }
|
|
|
|
var ret = [];
|
|
|
|
var ptype = ['ERROR', 'Other', 'Unknown', 'CPU', 'ALU', 'DSP', 'GPU'];
|
|
|
|
var statusString = ['Unknown', 'Enabled', 'Disabled by user', 'Disabled by BIOS', 'Idle', 'Reserved', 'Reserved', 'Other'];
|
|
|
|
var cpuid = 0;
|
|
|
|
while (data[4] && data[4].length > 0) {
|
|
|
|
var p = data[4].pop();
|
|
|
|
var populated = p[20] & 0x40;
|
|
|
|
var status = p[20] & 0x07
|
|
|
|
if (populated) {
|
|
|
|
var j = { _ObjectID: 'SMBiosTables.processorInfo' };
|
|
|
|
j.Processor = ptype[p[1]];
|
|
|
|
j.MaxSpeed = p.readUInt16LE(16) + ' Mhz';
|
|
|
|
if (p[31]) { j.Cores = p[31]; }
|
|
|
|
if (p[33]) { j.Threads = p[33]; }
|
|
|
|
j.Populated = 1;
|
|
|
|
j.Status = statusString[status];
|
|
|
|
j.Socket = p._strings[p[0] - 1];
|
|
|
|
j.Manufacturer = p._strings[p[3] - 1];
|
|
|
|
j.Version = p._strings[p[12] - 1];
|
|
|
|
ret.push(j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (ret);
|
|
|
|
};
|
|
|
|
this.memoryInfo = function memoryInfo(data) {
|
|
|
|
if (!data) { throw ('no data'); }
|
|
|
|
var retVal = { _ObjectID: 'SMBiosTables.memoryInfo' };
|
|
|
|
if (data[16]) {
|
|
|
|
var m = data[16].peek();
|
|
|
|
retVal.location = memoryLocation[m[0]];
|
|
|
|
if ((retVal.maxCapacityKb = m.readUInt32LE(3)) == 0x80000000) {
|
|
|
|
retVal.maxCapacityKb = 'A really big number';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (retVal);
|
|
|
|
};
|
2018-09-18 22:41:59 -04:00
|
|
|
this.systemInfo = function systemInfo(data)
|
|
|
|
{
|
2018-03-12 21:16:06 -04:00
|
|
|
if (!data) { throw ('no data'); }
|
|
|
|
var retVal = { _ObjectID: 'SMBiosTables.systemInfo' };
|
2018-09-18 22:41:59 -04:00
|
|
|
if (data[1])
|
|
|
|
{
|
2018-03-12 21:16:06 -04:00
|
|
|
var si = data[1].peek();
|
2018-09-18 22:41:59 -04:00
|
|
|
var uuid = si.slice(4, 20);
|
|
|
|
|
|
|
|
retVal.uuid = [zeroLeftPad(uuid.readUInt32LE(0).toString(16), 8),
|
|
|
|
zeroLeftPad(uuid.readUInt16LE(4).toString(16), 4),
|
|
|
|
zeroLeftPad(uuid.readUInt16LE(6).toString(16), 4),
|
|
|
|
zeroLeftPad(uuid.readUInt16BE(8).toString(16), 4),
|
|
|
|
zeroLeftPad(uuid.slice(10).toString('hex').toLowerCase(), 12)].join('-');
|
|
|
|
|
2018-03-12 21:16:06 -04:00
|
|
|
retVal.wakeReason = wakeReason[si[20]];
|
|
|
|
}
|
|
|
|
return (retVal);
|
|
|
|
};
|
|
|
|
this.systemSlots = function systemSlots(data) {
|
|
|
|
if (!data) { throw ('no data'); }
|
|
|
|
var retVal = [];
|
|
|
|
if (data[9]) {
|
|
|
|
while (data[9].length > 0) {
|
|
|
|
var ss = data[9].pop();
|
|
|
|
retVal.push({ name: ss._strings[ss[0] - 1] });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (retVal);
|
|
|
|
};
|
|
|
|
this.amtInfo = function amtInfo(data) {
|
|
|
|
if (!data) { throw ('no data'); }
|
|
|
|
var retVal = { AMT: false };
|
|
|
|
if (data[130] && data[130].peek().slice(0, 4).toString() == '$AMT') {
|
|
|
|
var amt = data[130].peek();
|
|
|
|
retVal.AMT = amt[4] ? true : false;
|
|
|
|
if (retVal.AMT) {
|
|
|
|
retVal.enabled = amt[5] ? true : false;
|
|
|
|
retVal.storageRedirection = amt[6] ? true : false;
|
|
|
|
retVal.serialOverLan = amt[7] ? true : false;
|
|
|
|
retVal.kvm = amt[14] ? true : false;
|
|
|
|
if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro') {
|
|
|
|
var settings = data[131].peek();
|
|
|
|
if (settings[0] & 0x04) { retVal.TXT = (settings[0] & 0x08) ? true : false; }
|
|
|
|
if (settings[0] & 0x10) { retVal.VMX = (settings[0] & 0x20) ? true : false; }
|
2019-09-23 15:59:41 -04:00
|
|
|
retVal.MEBX = settings.readUInt16LE(4).toString() + '.' + settings.readUInt16LE(6).toString() + '.' + settings.readUInt16LE(8).toString() + '.' + settings.readUInt16LE(10).toString();
|
2018-03-12 21:16:06 -04:00
|
|
|
|
|
|
|
var mecap = settings.slice(20, 32);
|
2019-09-23 15:59:41 -04:00
|
|
|
retVal.ManagementEngine = mecap.readUInt16LE(6).toString() + '.' + mecap.readUInt16LE(4).toString() + '.' + mecap.readUInt16LE(10).toString() + '.' + mecap.readUInt16LE(8).toString();
|
2018-03-12 21:16:06 -04:00
|
|
|
|
|
|
|
//var lan = settings.slice(36, 48);
|
|
|
|
//console.log(lan.toString('hex'));
|
|
|
|
//retVal.LAN = (lan.readUInt16LE(10) & 0x03).toString() + '/' + ((lan.readUInt16LE(10) & 0xF8) >> 3).toString();
|
|
|
|
|
|
|
|
//console.log(lan.readUInt16LE(3));
|
|
|
|
//retVal.WLAN = (lan.readUInt16LE(3) & 0x07).toString() + '/' + ((lan.readUInt16LE(3) & 0xF8) >> 3).toString() + '/' + (lan.readUInt16LE(3) >> 8).toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (retVal);
|
|
|
|
};
|
|
|
|
this.smTableTypes = {
|
|
|
|
0: 'BIOS information',
|
|
|
|
1: 'System information',
|
|
|
|
2: 'Baseboard (or Module) information',
|
|
|
|
4: 'Processor information',
|
|
|
|
5: 'memory controller information',
|
|
|
|
6: 'Memory module information',
|
|
|
|
7: 'Cache information',
|
|
|
|
8: 'Port connector information',
|
|
|
|
9: 'System slots',
|
|
|
|
10: 'On board devices information',
|
|
|
|
11: 'OEM strings',
|
|
|
|
12: 'System configuration options',
|
|
|
|
13: 'BIOS language information',
|
|
|
|
14: 'Group associations',
|
|
|
|
15: 'System event log',
|
|
|
|
16: 'Physical memory array',
|
|
|
|
17: 'Memory device',
|
|
|
|
18: '32bit memory error information',
|
|
|
|
19: 'Memory array mapped address',
|
|
|
|
20: 'Memory device mapped address',
|
|
|
|
21: 'Built-in pointing device',
|
|
|
|
22: 'Portable battery',
|
|
|
|
23: 'System reset',
|
|
|
|
24: 'Hardware security',
|
|
|
|
25: 'System power controls',
|
|
|
|
26: 'Voltage probe',
|
|
|
|
27: 'Cooling device',
|
|
|
|
28: 'Temperature probe',
|
|
|
|
29: 'Electrical current probe',
|
|
|
|
30: 'Out-of-band remote access',
|
|
|
|
31: 'Boot integrity services (BIS) entry point',
|
|
|
|
32: 'System boot information',
|
|
|
|
33: '64bit memory error information',
|
|
|
|
34: 'Management device',
|
|
|
|
35: 'Management device component',
|
|
|
|
36: 'Management device threshold data',
|
|
|
|
37: 'Memory channel',
|
|
|
|
38: 'IPMI device information',
|
|
|
|
39: 'System power supply',
|
|
|
|
40: 'Additional information',
|
|
|
|
41: 'Onboard devices extended information',
|
|
|
|
42: 'Management controller host interface',
|
|
|
|
126: 'Inactive',
|
|
|
|
127: 'End-of-table'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = new SMBiosTables();
|