2Copyright 2018 Intel Corporation
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
17try { Object.defineProperty(Array.prototype, "peek", { value: function () { return (this.length > 0 ? this[this.length - 1] : undefined); } }); } catch (e) { }
18try { Object.defineProperty(String.prototype, "replaceAll", { value: function replaceAll(oldVal, newVal) { return (this.split(oldVal).join(newVal)); } }); } catch (e) { }
21var 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' };
22var wakeReason = ['Reserved', 'Other', 'Unknown', 'APM Timer', 'Modem Ring', 'LAN', 'Power Switch', 'PCI', 'AC Power'];
24// Fill the left with zeros until the string is of a given length
25function zeroLeftPad(str, len)
27 if ((len == null) && (typeof (len) != 'number')) { return null; }
28 if (str == null) str = ''; // If null, this is to generate zero leftpad string
30 for (var i = 0; i < len - str.length; i++) { zlp += '0'; }
34function SMBiosTables()
36 this._ObjectID = 'SMBiosTable';
37 if (process.platform == 'win32') {
38 this._marshal = require('_GenericMarshal');
39 this._native = this._marshal.CreateNativeProxy("Kernel32.dll");
41 this._native.CreateMethod('EnumSystemFirmwareTables');
42 this._native.CreateMethod('GetSystemFirmwareTable');
44 if (process.platform == 'linux') {
45 this._canonicalizeData = function _canonicalizeData(data) {
46 var lines = data.toString().split('Header and Data:\x0A');
47 var MemoryStream = require('MemoryStream');
48 var ms = new MemoryStream();
50 for (var i = 1; i < lines.length; ++i) {
51 var tokens = lines[i].split('Strings:\x0A');
52 var header = tokens[0].split('\x0A\x0A')[0].replaceAll('\x0A', '').trim().replaceAll(' ', '').replaceAll('\x09', '');
53 ms.write(Buffer.from(header, 'hex'));
54 if (tokens.length > 1) {
55 var strings = tokens[1].split('\x0A\x0A')[0].split('\x0A');
56 var stringsFinal = [];
57 for (var strx in strings) {
58 var tmp = strings[strx].trim().replaceAll(' ', '').replaceAll('\x09', '');
59 if (tmp && tmp[0] !== '"' && /^[0-9a-fA-F]+$/.test(tmp)) { stringsFinal.push(tmp); }
61 ms.write(Buffer.from(stringsFinal.join(''), 'hex'));
62 ms.write(Buffer.from('00', 'hex'));
65 ms.write(Buffer.from('0000', 'hex'));
68 var retVal = ms.buffer;
73 this._parse = function _parse(SMData) {
80 while (SMData && i < SMData.length)
82 var SMtype = SMData[i];
83 var SMlength = SMData[i + 1];
85 if (!ret[SMtype]) { ret[SMtype] = []; }
86 ret[SMtype].push(SMData.slice(i + 4, i + SMlength));
87 if (process.platform == 'win32') { ret[SMtype].peek()._ext = pbyte; }
90 ret[SMtype].peek()._strings = [];
92 while (SMData[i] != 0 && i <= SMData.length)
96 // Start of String, find end of string
97 while (SMData[i++] != 0 && i <= SMData.length);
100 ret[SMtype].peek()._strings.push(SMData.slice(strstart, i).toString().trim());
106 i += (ret[SMtype].peek()._strings.length == 0) ? 2 : 1;
108 //console.log('End of Table[' + SMtype + ']: ' + i);
110 //console.log('Struct Count = ' + structcount);
113 this.get = function get(callback) {
114 if (process.platform == 'win32') {
115 var size = this._native.GetSystemFirmwareTable(RSMB, 0, 0, 0).Val;
116 //console.log('Table Size: ' + size);
118 var PtrSize = this._marshal.CreatePointer()._size;
119 var buffer = this._marshal.CreateVariable(size);
120 var written = this._native.GetSystemFirmwareTable(RSMB, 0, buffer, size).Val;
121 //console.log('Written Size: ' + written);
123 var rawBuffer = buffer.toBuffer();
124 var length = buffer.Deref(4, 4).toBuffer().readUInt32LE(0);
126 pbyte = buffer.Deref(8, length);
127 SMData = pbyte.toBuffer();
129 if (callback) { callback.apply(this, [this._parse(SMData)]); return; } else { return (this._parse(SMData)); }
131 if (process.platform == 'linux') {
132 var MemoryStream = require('MemoryStream');
133 this.child = require('child_process').execFile('/usr/sbin/dmidecode', ['dmidecode', '-u']);
134 this.child.SMBiosTable = this;
135 this.child.ms = new MemoryStream();
136 this.child.ms.callback = callback;
137 this.child.ms.child = this.child;
138 this.child.stdout.on('data', function (buffer) { this.parent.ms.write(buffer); });
139 this.child.on('exit', function () { this.ms.end(); });
140 this.child.ms.on('end', function () {
141 //console.log('read ' + this.buffer.length + ' bytes');
142 if (this.buffer.length < 300) {
143 //console.log('Not enough permission to read SMBiosTable');
144 if (this.callback) { this.callback.apply(this.child.SMBiosTable, []); }
147 var SMData = this.child.SMBiosTable._canonicalizeData(this.buffer);
148 var j = this.child.SMBiosTable._parse(SMData);
149 if (this.callback) { this.callback.apply(this.child.SMBiosTable, [j]); }
154 if (callback) { callback.apply(this, [null]); return; } else { return (null); }
156 this.parse = function parse(data) {
160 r.processorInfo = this.processorInfo(data);
167 r.memoryInfo = this.memoryInfo(data);
174 r.systemInfo = this.systemInfo(data);
181 r.systemSlots = this.systemSlots(data);
188 r.amtInfo = this.amtInfo(data);
195 if (JSON.stringify(r).length > 65535) { r = {}; }
201 this.processorInfo = function processorInfo(data) {
202 if (!data) { throw ('no data'); }
204 var ptype = ['ERROR', 'Other', 'Unknown', 'CPU', 'ALU', 'DSP', 'GPU'];
205 var statusString = ['Unknown', 'Enabled', 'Disabled by user', 'Disabled by BIOS', 'Idle', 'Reserved', 'Reserved', 'Other'];
207 while (data[4] && data[4].length > 0) {
208 var p = data[4].pop();
209 var populated = p[20] & 0x40;
210 var status = p[20] & 0x07
212 var j = { _ObjectID: 'SMBiosTables.processorInfo' };
213 j.Processor = ptype[p[1]];
214 j.MaxSpeed = p.readUInt16LE(16) + ' Mhz';
215 if (p[31]) { j.Cores = p[31]; }
216 if (p[33]) { j.Threads = p[33]; }
218 j.Status = statusString[status];
219 j.Socket = p._strings[p[0] - 1];
220 j.Manufacturer = p._strings[p[3] - 1];
221 j.Version = p._strings[p[12] - 1];
227 this.memoryInfo = function memoryInfo(data) {
228 if (!data) { throw ('no data'); }
229 var retVal = { _ObjectID: 'SMBiosTables.memoryInfo' };
231 var m = data[16].peek();
232 retVal.location = memoryLocation[m[0]];
233 if ((retVal.maxCapacityKb = m.readUInt32LE(3)) == 0x80000000) {
234 retVal.maxCapacityKb = 'A really big number';
239 this.systemInfo = function systemInfo(data)
241 if (!data) { throw ('no data'); }
242 var retVal = { _ObjectID: 'SMBiosTables.systemInfo' };
245 var si = data[1].peek();
246 var uuid = si.slice(4, 20);
248 retVal.uuid = [zeroLeftPad(uuid.readUInt32LE(0).toString(16), 8),
249 zeroLeftPad(uuid.readUInt16LE(4).toString(16), 4),
250 zeroLeftPad(uuid.readUInt16LE(6).toString(16), 4),
251 zeroLeftPad(uuid.readUInt16BE(8).toString(16), 4),
252 zeroLeftPad(uuid.slice(10).toString('hex').toLowerCase(), 12)].join('-');
254 retVal.wakeReason = wakeReason[si[20]];
258 this.systemSlots = function systemSlots(data) {
259 if (!data) { throw ('no data'); }
262 while (data[9].length > 0) {
263 var ss = data[9].pop();
264 retVal.push({ name: ss._strings[ss[0] - 1] });
269 this.amtInfo = function amtInfo(data) {
270 if (!data) { throw ('no data'); }
271 var retVal = { AMT: false };
272 if (data[130] && data[130].peek().slice(0, 4).toString() == '$AMT')
274 var amt = data[130].peek();
275 retVal.AMT = amt[4] ? true : false;
278 retVal.enabled = amt[5] ? true : false;
279 retVal.storageRedirection = amt[6] ? true : false;
280 retVal.serialOverLan = amt[7] ? true : false;
281 retVal.kvm = amt[14] ? true : false;
282 if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
284 var settings = data[131].peek();
285 if (settings[0] & 0x04) { retVal.TXT = (settings[0] & 0x08) ? true : false; }
286 if (settings[0] & 0x10) { retVal.VMX = (settings[0] & 0x20) ? true : false; }
287 retVal.MEBX = settings.readUInt16LE(4).toString() + '.' + settings.readUInt16LE(6).toString() + '.' + settings.readUInt16LE(8).toString() + '.' + settings.readUInt16LE(10).toString();
289 var mecap = settings.slice(20, 32);
290 retVal.ManagementEngine = mecap.readUInt16LE(6).toString() + '.' + mecap.readUInt16LE(4).toString() + '.' + mecap.readUInt16LE(10).toString() + '.' + mecap.readUInt16LE(8).toString();
292 //var lan = settings.slice(36, 48);
293 //console.log(lan.toString('hex'));
294 //retVal.LAN = (lan.readUInt16LE(10) & 0x03).toString() + '/' + ((lan.readUInt16LE(10) & 0xF8) >> 3).toString();
296 //console.log(lan.readUInt16LE(3));
297 //retVal.WLAN = (lan.readUInt16LE(3) & 0x07).toString() + '/' + ((lan.readUInt16LE(3) & 0xF8) >> 3).toString() + '/' + (lan.readUInt16LE(3) >> 8).toString();
303 if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
305 var settings = data[131].peek();
306 if ((settings[20] & 0x08) == 0x08) { retVal.AMT = true; }
311 this.smTableTypes = {
312 0: 'BIOS information',
313 1: 'System information',
314 2: 'Baseboard (or Module) information',
315 4: 'Processor information',
316 5: 'memory controller information',
317 6: 'Memory module information',
318 7: 'Cache information',
319 8: 'Port connector information',
321 10: 'On board devices information',
323 12: 'System configuration options',
324 13: 'BIOS language information',
325 14: 'Group associations',
326 15: 'System event log',
327 16: 'Physical memory array',
329 18: '32bit memory error information',
330 19: 'Memory array mapped address',
331 20: 'Memory device mapped address',
332 21: 'Built-in pointing device',
333 22: 'Portable battery',
335 24: 'Hardware security',
336 25: 'System power controls',
338 27: 'Cooling device',
339 28: 'Temperature probe',
340 29: 'Electrical current probe',
341 30: 'Out-of-band remote access',
342 31: 'Boot integrity services (BIS) entry point',
343 32: 'System boot information',
344 33: '64bit memory error information',
345 34: 'Management device',
346 35: 'Management device component',
347 36: 'Management device threshold data',
348 37: 'Memory channel',
349 38: 'IPMI device information',
350 39: 'System power supply',
351 40: 'Additional information',
352 41: 'Onboard devices extended information',
353 42: 'Management controller host interface',
359module.exports = new SMBiosTables();