EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
smbios.js
Go to the documentation of this file.
1/*
2Copyright 2018 Intel Corporation
3
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
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
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.
15*/
16
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) { }
19
20var RSMB = 1381190978;
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'];
23
24// Fill the left with zeros until the string is of a given length
25function zeroLeftPad(str, len)
26{
27 if ((len == null) && (typeof (len) != 'number')) { return null; }
28 if (str == null) str = ''; // If null, this is to generate zero leftpad string
29 var zlp = '';
30 for (var i = 0; i < len - str.length; i++) { zlp += '0'; }
31 return zlp + str;
32}
33
34function SMBiosTables()
35{
36 this._ObjectID = 'SMBiosTable';
37 if (process.platform == 'win32') {
38 this._marshal = require('_GenericMarshal');
39 this._native = this._marshal.CreateNativeProxy("Kernel32.dll");
40
41 this._native.CreateMethod('EnumSystemFirmwareTables');
42 this._native.CreateMethod('GetSystemFirmwareTable');
43 }
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();
49
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); }
60 }
61 ms.write(Buffer.from(stringsFinal.join(''), 'hex'));
62 ms.write(Buffer.from('00', 'hex'));
63 }
64 else {
65 ms.write(Buffer.from('0000', 'hex'));
66 }
67 }
68 var retVal = ms.buffer;
69 retVal.ms = ms;
70 return (retVal);
71 };
72 }
73 this._parse = function _parse(SMData) {
74 var ret = {};
75 var pbyte;
76 var i = 0
77 var SMData;
78 var structcount = 0;
79
80 while (SMData && i < SMData.length)
81 {
82 var SMtype = SMData[i];
83 var SMlength = SMData[i + 1];
84
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; }
88 i += SMlength;
89
90 ret[SMtype].peek()._strings = [];
91
92 while (SMData[i] != 0 && i <= SMData.length)
93 {
94 var strstart = i;
95
96 // Start of String, find end of string
97 while (SMData[i++] != 0 && i <= SMData.length);
98 try
99 {
100 ret[SMtype].peek()._strings.push(SMData.slice(strstart, i).toString().trim());
101 }
102 catch (ee)
103 {
104 }
105 }
106 i += (ret[SMtype].peek()._strings.length == 0) ? 2 : 1;
107 ++structcount;
108 //console.log('End of Table[' + SMtype + ']: ' + i);
109 }
110 //console.log('Struct Count = ' + structcount);
111 return (ret);
112 };
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);
117
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);
122
123 var rawBuffer = buffer.toBuffer();
124 var length = buffer.Deref(4, 4).toBuffer().readUInt32LE(0);
125
126 pbyte = buffer.Deref(8, length);
127 SMData = pbyte.toBuffer();
128
129 if (callback) { callback.apply(this, [this._parse(SMData)]); return; } else { return (this._parse(SMData)); }
130 }
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, []); }
145 }
146 else {
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]); }
150 }
151 });
152 return;
153 }
154 if (callback) { callback.apply(this, [null]); return; } else { return (null); }
155 };
156 this.parse = function parse(data) {
157 var r = {};
158 try
159 {
160 r.processorInfo = this.processorInfo(data);
161 }
162 catch(e)
163 {
164 }
165 try
166 {
167 r.memoryInfo = this.memoryInfo(data);
168 }
169 catch(e)
170 {
171 }
172 try
173 {
174 r.systemInfo = this.systemInfo(data);
175 }
176 catch(e)
177 {
178 }
179 try
180 {
181 r.systemSlots = this.systemSlots(data);
182 }
183 catch(e)
184 {
185 }
186 try
187 {
188 r.amtInfo = this.amtInfo(data);
189 }
190 catch(e)
191 {
192 }
193 try
194 {
195 if (JSON.stringify(r).length > 65535) { r = {}; }
196 }
197 catch(ee)
198 {}
199 return r;
200 }
201 this.processorInfo = function processorInfo(data) {
202 if (!data) { throw ('no data'); }
203 var ret = [];
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'];
206 var cpuid = 0;
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
211 if (populated) {
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]; }
217 j.Populated = 1;
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];
222 ret.push(j);
223 }
224 }
225 return (ret);
226 };
227 this.memoryInfo = function memoryInfo(data) {
228 if (!data) { throw ('no data'); }
229 var retVal = { _ObjectID: 'SMBiosTables.memoryInfo' };
230 if (data[16]) {
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';
235 }
236 }
237 return (retVal);
238 };
239 this.systemInfo = function systemInfo(data)
240 {
241 if (!data) { throw ('no data'); }
242 var retVal = { _ObjectID: 'SMBiosTables.systemInfo' };
243 if (data[1])
244 {
245 var si = data[1].peek();
246 var uuid = si.slice(4, 20);
247
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('-');
253
254 retVal.wakeReason = wakeReason[si[20]];
255 }
256 return (retVal);
257 };
258 this.systemSlots = function systemSlots(data) {
259 if (!data) { throw ('no data'); }
260 var retVal = [];
261 if (data[9]) {
262 while (data[9].length > 0) {
263 var ss = data[9].pop();
264 retVal.push({ name: ss._strings[ss[0] - 1] });
265 }
266 }
267 return (retVal);
268 };
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')
273 {
274 var amt = data[130].peek();
275 retVal.AMT = amt[4] ? true : false;
276 if (retVal.AMT)
277 {
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')
283 {
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();
288
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();
291
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();
295
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();
298 }
299 }
300 }
301 if (!retVal.AMT)
302 {
303 if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
304 {
305 var settings = data[131].peek();
306 if ((settings[20] & 0x08) == 0x08) { retVal.AMT = true; }
307 }
308 }
309 return (retVal);
310 };
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',
320 9: 'System slots',
321 10: 'On board devices information',
322 11: 'OEM strings',
323 12: 'System configuration options',
324 13: 'BIOS language information',
325 14: 'Group associations',
326 15: 'System event log',
327 16: 'Physical memory array',
328 17: 'Memory device',
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',
334 23: 'System reset',
335 24: 'Hardware security',
336 25: 'System power controls',
337 26: 'Voltage probe',
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',
354 126: 'Inactive',
355 127: 'End-of-table'
356 }
357}
358
359module.exports = new SMBiosTables();