smbios.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. Copyright 2018 Intel Corporation
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. try { Object.defineProperty(Array.prototype, "peek", { value: function () { return (this.length > 0 ? this[this.length - 1] : undefined); } }); } catch (e) { }
  14. try { Object.defineProperty(String.prototype, "replaceAll", { value: function replaceAll(oldVal, newVal) { return (this.split(oldVal).join(newVal)); } }); } catch (e) { }
  15. var RSMB = 1381190978;
  16. 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' };
  17. var wakeReason = ['Reserved', 'Other', 'Unknown', 'APM Timer', 'Modem Ring', 'LAN', 'Power Switch', 'PCI', 'AC Power'];
  18. // Fill the left with zeros until the string is of a given length
  19. function zeroLeftPad(str, len)
  20. {
  21. if ((len == null) && (typeof (len) != 'number')) { return null; }
  22. if (str == null) str = ''; // If null, this is to generate zero leftpad string
  23. var zlp = '';
  24. for (var i = 0; i < len - str.length; i++) { zlp += '0'; }
  25. return zlp + str;
  26. }
  27. function SMBiosTables()
  28. {
  29. this._ObjectID = 'SMBiosTable';
  30. if (process.platform == 'win32') {
  31. this._marshal = require('_GenericMarshal');
  32. this._native = this._marshal.CreateNativeProxy("Kernel32.dll");
  33. this._native.CreateMethod('EnumSystemFirmwareTables');
  34. this._native.CreateMethod('GetSystemFirmwareTable');
  35. }
  36. if (process.platform == 'linux') {
  37. this._canonicalizeData = function _canonicalizeData(data) {
  38. var lines = data.toString().split('Header and Data:\x0A');
  39. var MemoryStream = require('MemoryStream');
  40. var ms = new MemoryStream();
  41. for (var i = 1; i < lines.length; ++i) {
  42. var tokens = lines[i].split('Strings:\x0A');
  43. var header = tokens[0].split('\x0A\x0A')[0].replaceAll('\x0A', '').trim().replaceAll(' ', '').replaceAll('\x09', '');
  44. ms.write(Buffer.from(header, 'hex'));
  45. if (tokens.length > 1) {
  46. var strings = tokens[1].split('\x0A\x0A')[0].split('\x0A');
  47. var stringsFinal = [];
  48. for (var strx in strings) {
  49. var tmp = strings[strx].trim().replaceAll(' ', '').replaceAll('\x09', '');
  50. if (tmp && tmp[0] !== '"' && /^[0-9a-fA-F]+$/.test(tmp)) { stringsFinal.push(tmp); }
  51. }
  52. ms.write(Buffer.from(stringsFinal.join(''), 'hex'));
  53. ms.write(Buffer.from('00', 'hex'));
  54. }
  55. else {
  56. ms.write(Buffer.from('0000', 'hex'));
  57. }
  58. }
  59. var retVal = ms.buffer;
  60. retVal.ms = ms;
  61. return (retVal);
  62. };
  63. }
  64. this._parse = function _parse(SMData) {
  65. var ret = {};
  66. var pbyte;
  67. var i = 0
  68. var SMData;
  69. var structcount = 0;
  70. while (SMData && i < SMData.length)
  71. {
  72. var SMtype = SMData[i];
  73. var SMlength = SMData[i + 1];
  74. if (!ret[SMtype]) { ret[SMtype] = []; }
  75. ret[SMtype].push(SMData.slice(i + 4, i + SMlength));
  76. if (process.platform == 'win32') { ret[SMtype].peek()._ext = pbyte; }
  77. i += SMlength;
  78. ret[SMtype].peek()._strings = [];
  79. while (SMData[i] != 0 && i <= SMData.length)
  80. {
  81. var strstart = i;
  82. // Start of String, find end of string
  83. while (SMData[i++] != 0 && i <= SMData.length);
  84. try
  85. {
  86. ret[SMtype].peek()._strings.push(SMData.slice(strstart, i).toString().trim());
  87. }
  88. catch (ee)
  89. {
  90. }
  91. }
  92. i += (ret[SMtype].peek()._strings.length == 0) ? 2 : 1;
  93. ++structcount;
  94. //console.log('End of Table[' + SMtype + ']: ' + i);
  95. }
  96. //console.log('Struct Count = ' + structcount);
  97. return (ret);
  98. };
  99. this.get = function get(callback) {
  100. if (process.platform == 'win32') {
  101. var size = this._native.GetSystemFirmwareTable(RSMB, 0, 0, 0).Val;
  102. //console.log('Table Size: ' + size);
  103. var PtrSize = this._marshal.CreatePointer()._size;
  104. var buffer = this._marshal.CreateVariable(size);
  105. var written = this._native.GetSystemFirmwareTable(RSMB, 0, buffer, size).Val;
  106. //console.log('Written Size: ' + written);
  107. var rawBuffer = buffer.toBuffer();
  108. var length = buffer.Deref(4, 4).toBuffer().readUInt32LE(0);
  109. pbyte = buffer.Deref(8, length);
  110. SMData = pbyte.toBuffer();
  111. if (callback) { callback.apply(this, [this._parse(SMData)]); return; } else { return (this._parse(SMData)); }
  112. }
  113. if (process.platform == 'linux') {
  114. var MemoryStream = require('MemoryStream');
  115. this.child = require('child_process').execFile('/usr/sbin/dmidecode', ['dmidecode', '-u']);
  116. this.child.SMBiosTable = this;
  117. this.child.ms = new MemoryStream();
  118. this.child.ms.callback = callback;
  119. this.child.ms.child = this.child;
  120. this.child.stdout.on('data', function (buffer) { this.parent.ms.write(buffer); });
  121. this.child.on('exit', function () { this.ms.end(); });
  122. this.child.ms.on('end', function () {
  123. //console.log('read ' + this.buffer.length + ' bytes');
  124. if (this.buffer.length < 300) {
  125. //console.log('Not enough permission to read SMBiosTable');
  126. if (this.callback) { this.callback.apply(this.child.SMBiosTable, []); }
  127. }
  128. else {
  129. var SMData = this.child.SMBiosTable._canonicalizeData(this.buffer);
  130. var j = this.child.SMBiosTable._parse(SMData);
  131. if (this.callback) { this.callback.apply(this.child.SMBiosTable, [j]); }
  132. }
  133. });
  134. return;
  135. }
  136. if (callback) { callback.apply(this, [null]); return; } else { return (null); }
  137. };
  138. this.parse = function parse(data) {
  139. var r = {};
  140. try
  141. {
  142. r.processorInfo = this.processorInfo(data);
  143. }
  144. catch(e)
  145. {
  146. }
  147. try
  148. {
  149. r.memoryInfo = this.memoryInfo(data);
  150. }
  151. catch(e)
  152. {
  153. }
  154. try
  155. {
  156. r.systemInfo = this.systemInfo(data);
  157. }
  158. catch(e)
  159. {
  160. }
  161. try
  162. {
  163. r.systemSlots = this.systemSlots(data);
  164. }
  165. catch(e)
  166. {
  167. }
  168. try
  169. {
  170. r.amtInfo = this.amtInfo(data);
  171. }
  172. catch(e)
  173. {
  174. }
  175. try
  176. {
  177. if (JSON.stringify(r).length > 65535) { r = {}; }
  178. }
  179. catch(ee)
  180. {}
  181. return r;
  182. }
  183. this.processorInfo = function processorInfo(data) {
  184. if (!data) { throw ('no data'); }
  185. var ret = [];
  186. var ptype = ['ERROR', 'Other', 'Unknown', 'CPU', 'ALU', 'DSP', 'GPU'];
  187. var statusString = ['Unknown', 'Enabled', 'Disabled by user', 'Disabled by BIOS', 'Idle', 'Reserved', 'Reserved', 'Other'];
  188. var cpuid = 0;
  189. while (data[4] && data[4].length > 0) {
  190. var p = data[4].pop();
  191. var populated = p[20] & 0x40;
  192. var status = p[20] & 0x07
  193. if (populated) {
  194. var j = { _ObjectID: 'SMBiosTables.processorInfo' };
  195. j.Processor = ptype[p[1]];
  196. j.MaxSpeed = p.readUInt16LE(16) + ' Mhz';
  197. if (p[31]) { j.Cores = p[31]; }
  198. if (p[33]) { j.Threads = p[33]; }
  199. j.Populated = 1;
  200. j.Status = statusString[status];
  201. j.Socket = p._strings[p[0] - 1];
  202. j.Manufacturer = p._strings[p[3] - 1];
  203. j.Version = p._strings[p[12] - 1];
  204. ret.push(j);
  205. }
  206. }
  207. return (ret);
  208. };
  209. this.memoryInfo = function memoryInfo(data) {
  210. if (!data) { throw ('no data'); }
  211. var retVal = { _ObjectID: 'SMBiosTables.memoryInfo' };
  212. if (data[16]) {
  213. var m = data[16].peek();
  214. retVal.location = memoryLocation[m[0]];
  215. if ((retVal.maxCapacityKb = m.readUInt32LE(3)) == 0x80000000) {
  216. retVal.maxCapacityKb = 'A really big number';
  217. }
  218. }
  219. return (retVal);
  220. };
  221. this.systemInfo = function systemInfo(data)
  222. {
  223. if (!data) { throw ('no data'); }
  224. var retVal = { _ObjectID: 'SMBiosTables.systemInfo' };
  225. if (data[1])
  226. {
  227. var si = data[1].peek();
  228. var uuid = si.slice(4, 20);
  229. retVal.uuid = [zeroLeftPad(uuid.readUInt32LE(0).toString(16), 8),
  230. zeroLeftPad(uuid.readUInt16LE(4).toString(16), 4),
  231. zeroLeftPad(uuid.readUInt16LE(6).toString(16), 4),
  232. zeroLeftPad(uuid.readUInt16BE(8).toString(16), 4),
  233. zeroLeftPad(uuid.slice(10).toString('hex').toLowerCase(), 12)].join('-');
  234. retVal.wakeReason = wakeReason[si[20]];
  235. }
  236. return (retVal);
  237. };
  238. this.systemSlots = function systemSlots(data) {
  239. if (!data) { throw ('no data'); }
  240. var retVal = [];
  241. if (data[9]) {
  242. while (data[9].length > 0) {
  243. var ss = data[9].pop();
  244. retVal.push({ name: ss._strings[ss[0] - 1] });
  245. }
  246. }
  247. return (retVal);
  248. };
  249. this.amtInfo = function amtInfo(data) {
  250. if (!data) { throw ('no data'); }
  251. var retVal = { AMT: false };
  252. if (data[130] && data[130].peek().slice(0, 4).toString() == '$AMT')
  253. {
  254. var amt = data[130].peek();
  255. retVal.AMT = amt[4] ? true : false;
  256. if (retVal.AMT)
  257. {
  258. retVal.enabled = amt[5] ? true : false;
  259. retVal.storageRedirection = amt[6] ? true : false;
  260. retVal.serialOverLan = amt[7] ? true : false;
  261. retVal.kvm = amt[14] ? true : false;
  262. if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
  263. {
  264. var settings = data[131].peek();
  265. if (settings[0] & 0x04) { retVal.TXT = (settings[0] & 0x08) ? true : false; }
  266. if (settings[0] & 0x10) { retVal.VMX = (settings[0] & 0x20) ? true : false; }
  267. retVal.MEBX = settings.readUInt16LE(4).toString() + '.' + settings.readUInt16LE(6).toString() + '.' + settings.readUInt16LE(8).toString() + '.' + settings.readUInt16LE(10).toString();
  268. var mecap = settings.slice(20, 32);
  269. retVal.ManagementEngine = mecap.readUInt16LE(6).toString() + '.' + mecap.readUInt16LE(4).toString() + '.' + mecap.readUInt16LE(10).toString() + '.' + mecap.readUInt16LE(8).toString();
  270. //var lan = settings.slice(36, 48);
  271. //console.log(lan.toString('hex'));
  272. //retVal.LAN = (lan.readUInt16LE(10) & 0x03).toString() + '/' + ((lan.readUInt16LE(10) & 0xF8) >> 3).toString();
  273. //console.log(lan.readUInt16LE(3));
  274. //retVal.WLAN = (lan.readUInt16LE(3) & 0x07).toString() + '/' + ((lan.readUInt16LE(3) & 0xF8) >> 3).toString() + '/' + (lan.readUInt16LE(3) >> 8).toString();
  275. }
  276. }
  277. }
  278. if (!retVal.AMT)
  279. {
  280. if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
  281. {
  282. var settings = data[131].peek();
  283. if ((settings[20] & 0x08) == 0x08) { retVal.AMT = true; }
  284. }
  285. }
  286. return (retVal);
  287. };
  288. this.smTableTypes = {
  289. 0: 'BIOS information',
  290. 1: 'System information',
  291. 2: 'Baseboard (or Module) information',
  292. 4: 'Processor information',
  293. 5: 'memory controller information',
  294. 6: 'Memory module information',
  295. 7: 'Cache information',
  296. 8: 'Port connector information',
  297. 9: 'System slots',
  298. 10: 'On board devices information',
  299. 11: 'OEM strings',
  300. 12: 'System configuration options',
  301. 13: 'BIOS language information',
  302. 14: 'Group associations',
  303. 15: 'System event log',
  304. 16: 'Physical memory array',
  305. 17: 'Memory device',
  306. 18: '32bit memory error information',
  307. 19: 'Memory array mapped address',
  308. 20: 'Memory device mapped address',
  309. 21: 'Built-in pointing device',
  310. 22: 'Portable battery',
  311. 23: 'System reset',
  312. 24: 'Hardware security',
  313. 25: 'System power controls',
  314. 26: 'Voltage probe',
  315. 27: 'Cooling device',
  316. 28: 'Temperature probe',
  317. 29: 'Electrical current probe',
  318. 30: 'Out-of-band remote access',
  319. 31: 'Boot integrity services (BIS) entry point',
  320. 32: 'System boot information',
  321. 33: '64bit memory error information',
  322. 34: 'Management device',
  323. 35: 'Management device component',
  324. 36: 'Management device threshold data',
  325. 37: 'Memory channel',
  326. 38: 'IPMI device information',
  327. 39: 'System power supply',
  328. 40: 'Additional information',
  329. 41: 'Onboard devices extended information',
  330. 42: 'Management controller host interface',
  331. 126: 'Inactive',
  332. 127: 'End-of-table'
  333. }
  334. }
  335. module.exports = new SMBiosTables();