Back to index

lshw  02.16
dmi.cc
Go to the documentation of this file.
00001 /*
00002  * dmi.cc
00003  *
00004  * This file is based on Alan Cox's excellent DMI decoder rev 1.7
00005  * it has endured severe modifications so don't blame Alan for the
00006  * bugs, they're probably mine.
00007  *
00008  * This scan searches the BIOS memory for SMBIOS (DMI) extensions and reports
00009  * DMI information like CPU type, memory banks and size, serial numbers, BIOS
00010  * capabilities, etc.
00011  * As the BIOS is supposed to be the most authoritative source of information,
00012  * this scan should be executed first.
00013  *
00014  * Original credits for dmidecode.c:
00015  *
00016  * DMI decode rev 1.7
00017  *
00018  *     (C) 2000-2002 Alan Cox <alan@redhat.com>
00019  *
00020  *      2-July-2001 Matt Domsch <Matt_Domsch@dell.com>
00021  *      Additional structures displayed per SMBIOS 2.3.1 spec
00022  *
00023  *      13-December-2001 Arjan van de Ven <arjanv@redhat.com>
00024  *      Fix memory bank type (DMI case 6)
00025  *
00026  *      3-August-2002 Mark D. Studebaker <mds@paradyne.com>
00027  *      Better indent in dump_raw_data
00028  *      Fix return value in dmi_bus_name
00029  *      Additional sensor fields decoded
00030  *      Fix compilation warnings
00031  *
00032  *      6-August-2002 Jean Delvare <khali@linux-fr.org>
00033  *      Reposition file pointer after DMI table display
00034  *      Disable first RSD PTR checksum (was not correct anyway)
00035  *      Show actual DMI struct count and occupied size
00036  *      Check for NULL after malloc
00037  *      Use SEEK_* constants instead of numeric values
00038  *      Code optimization (and warning fix) in DMI cases 10 and 14
00039  *      Add else's to avoid unneeded cascaded if's in main loop
00040  *      Code optimization in DMI information display
00041  *      Fix all compilation warnings
00042  *
00043  *      9-August-2002 Jean Delvare <khali@linux-fr.org>
00044  *      Better DMI struct count/size error display
00045  *      More careful memory access in dmi_table
00046  *      DMI case 13 (Language) decoded
00047  *      C++ style comments removed
00048  *      Commented out code removed
00049  *      DMI 0.0 case handled
00050  *      Fix return value of dmi_port_type and dmi_port_connector_type
00051  *
00052  *      23-August-2002 Alan Cox <alan@redhat.com>
00053  *      Make the code pass -Wall -pedantic by fixing a few harmless sign of
00054  *        pointer mismatches
00055  *      Correct main prototype
00056  *      Check for compiles with wrong type sizes
00057  *
00058  *      17-Sep-2002 Larry Lile <llile@dreamworks.com>
00059  *      Type 16 & 17 structures displayed per SMBIOS 2.3.1 spec
00060  *
00061  *      20-September-2002 Dave Johnson <ddj@cascv.brown.edu>
00062  *      Fix comparisons in dmi_bus_name
00063  *      Fix comparison in dmi_processor_type
00064  *      Fix bitmasking in dmi_onboard_type
00065  *      Fix return value of dmi_temp_loc
00066  *
00067  *      28-September-2002 Jean Delvare <khali@linux-fr.org>
00068  *      Fix missing coma in dmi_bus_name
00069  *      Remove unwanted bitmaskings in dmi_mgmt_dev_type, dmi_mgmt_addr_type,
00070  *        dmi_fan_type, dmi_volt_loc, dmi_temp_loc and dmi_status
00071  *      Fix DMI table read bug ("dmi: read: Success")
00072  *      Make the code pass -W again
00073  *      Fix return value of dmi_card_size
00074  *
00075  */
00076 
00077 #include "version.h"
00078 #include "config.h"
00079 #include "options.h"
00080 #include "dmi.h"
00081 #include "osutils.h"
00082 
00083 #include <map>
00084 #include <vector>
00085 
00086 #include <stdio.h>
00087 #include <unistd.h>
00088 #include <fcntl.h>
00089 #include <string.h>
00090 #include <stdlib.h>
00091 #include <sys/mman.h>
00092 
00093 __ID("@(#) $Id: dmi.cc 2433 2012-01-10 22:01:30Z lyonel $");
00094 
00095 static int currentcpu = 0;
00096 
00097 typedef unsigned char u8;
00098 typedef unsigned short u16;
00099 typedef unsigned int u32;
00100 
00101 struct dmi_header
00102 {
00103   u8 type;
00104   u8 length;
00105   u16 handle;
00106 };
00107 
00108 static const char *dmi_hardware_security_status(u8 code)
00109 {
00110   static const char *status[]=
00111   {
00112     "disabled",                                   /* 0x00 */
00113     "enabled",
00114     "",                                           // not implemented
00115     "unknown"                                     /* 0x03 */
00116   };
00117 
00118   return status[code & 0x03];
00119 }
00120 
00121 static int checksum(const u8 *buf, size_t len)
00122 {
00123   u8 sum = 0;
00124   size_t a;
00125 
00126   for (a = 0; a < len; a++)
00127     sum += buf[a];
00128   return (sum == 0);
00129 }
00130 
00131 static string dmi_battery_voltage(u16 code)
00132 {
00133   char buffer[20];
00134   if(code==0) return "";
00135 
00136   snprintf(buffer, sizeof(buffer), "%.1fV", ((float)code/1000.0));
00137   return buffer;
00138 }
00139 
00140 
00141 static unsigned long long dmi_battery_capacity(u16 code, u8 multiplier)
00142 {
00143   return (unsigned long long)code * (unsigned long long)multiplier;
00144 }
00145 
00146 
00147 static const char *dmi_battery_chemistry(u8 code)
00148 {
00149   static const char *chemistry[]=
00150   {
00151     N_("Other"),                                      /* 0x01 */
00152     N_("Unknown"),
00153     N_("Lead Acid"),
00154     N_("Nickel Cadmium"),
00155     N_("Nickel Metal Hydride"),
00156     N_("Lithium Ion"),
00157     N_("Zinc Air"),
00158     N_("Lithium Polymer")                             /* 0x08 */
00159   };
00160 
00161   if(code>=0x01 && code<=0x08)
00162     return _(chemistry[code-0x01]);
00163   return "";
00164 }
00165 
00166 
00167 static string cpubusinfo(int cpu)
00168 {
00169   char buffer[20];
00170 
00171   snprintf(buffer, sizeof(buffer), "cpu@%d", cpu);
00172 
00173   return string(buffer);
00174 }
00175 
00176 
00177 static string dmi_uuid(u8 * p)
00178 {
00179   unsigned int i = 0;
00180   bool valid = false;
00181   char buffer[60];
00182 
00183   for (i = 0; i < 16; i++)
00184     if (p[i] != p[0])
00185       valid = true;
00186 
00187   if (!valid)
00188     return "";
00189 
00190   if(::enabled("output:sanitize"))
00191     return string(REMOVED);
00192 
00193   snprintf(buffer, sizeof(buffer),
00194     "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
00195     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10],
00196     p[11], p[12], p[13], p[14], p[15]);
00197 
00198   return hw::strip(string(buffer));
00199 }
00200 
00201 
00202 static string dmi_bootinfo(u8 code)
00203 {
00204   static const char *status[] =
00205   {
00206     "normal",                                     /* 0 */
00207     "no-bootable-media",
00208     "os-error",
00209     "hardware-failure-fw",
00210     "hardware-failure-os",
00211     "user-requested",
00212     "security-violation",
00213     "image",
00214     "watchdog"                                    /* 8 */
00215   };
00216   if (code <= 8)
00217     return string(status[code]);
00218   else
00219     return "oem-specific";
00220 }
00221 
00222 
00223 static string dmi_string(struct dmi_header *dm,
00224 u8 s)
00225 {
00226   char *bp = (char *) dm;
00227   if (!s)
00228     return "";
00229 
00230   bp += dm->length;
00231   while (s > 1)
00232   {
00233     bp += strlen(bp);
00234     bp++;
00235     s--;
00236   }
00237   return hw::strip(bp);
00238 }
00239 
00240 
00241 static string dmi_decode_ram(u16 data)
00242 {
00243   string result = "";
00244 
00245   if (data & (1 << 2))
00246     result += "Standard ";
00247   if (data & (1 << 3))
00248     result += "FPM ";
00249   if (data & (1 << 4))
00250     result += "EDO ";
00251   if (data & (1 << 5))
00252     result += "PARITY ";
00253   if (data & (1 << 6))
00254     result += "ECC ";
00255   if (data & (1 << 7))
00256     result += "SIMM ";
00257   if (data & (1 << 8))
00258     result += "DIMM ";
00259   if (data & (1 << 9))
00260     result += "Burst EDO ";
00261   if (data & (1 << 10))
00262     result += "SDRAM ";
00263 
00264   return hw::strip(result);
00265 }
00266 
00267 
00268 static const char *dmi_board_type(u8 data)
00269 {
00270   static const char *boardtypes[] =
00271   {
00272     "",
00273     "",
00274     "",
00275     N_("Server Blade"),
00276     N_("Connectivitiy Switch"),
00277     N_("System Management Module"),
00278     N_("Processor Module"),
00279     N_("I/O Module"),
00280     N_("Memory Module"),
00281     N_("Daughter Board"),
00282     N_("Motherboard"),
00283     N_("Processor/Memory Module"),
00284     N_("Processor/IO Module "),
00285     N_("Interconnect Board"),
00286   };
00287   if (data > 0x0D)
00288     return "";
00289   else
00290     return _(boardtypes[data]);
00291 }
00292 
00293 
00294 static void dmi_bios_features(u32 data1,
00295 u32 data2,
00296 hwNode & bios)
00297 {
00298   if (data1 & (1 << 3))                           // BIOS characteristics not supported
00299     return;
00300 
00301   if (data1 & (1 << 4))                           // ISA
00302     bios.addCapability("ISA", _("ISA bus"));
00303   if (data1 & (1 << 5))                           // MCA
00304     bios.addCapability("MCA", _("MCA bus"));
00305   if (data1 & (1 << 6))                           // EISA
00306     bios.addCapability("EISA", _("EISA bus"));
00307   if (data1 & (1 << 7))                           // PCI
00308     bios.addCapability("PCI", _("PCI bus"));
00309   if (data1 & (1 << 8))                           // PCMCIA
00310     bios.addCapability("PCMCIA", _("PCMCIA/PCCard"));
00311   if (data1 & (1 << 9))                           // PNP
00312     bios.addCapability("PNP", _("Plug-and-Play"));
00313   if (data1 & (1 << 10))                          // APM
00314     bios.addCapability("APM", _("Advanced Power Management"));
00315   if (data1 & (1 << 11))                          // flashable BIOS
00316     bios.addCapability("upgrade", _("BIOS EEPROM can be upgraded"));
00317   if (data1 & (1 << 12))                          // BIOS shadowing
00318     bios.addCapability("shadowing", _("BIOS shadowing"));
00319   if (data1 & (1 << 13))                          // VL-VESA
00320     bios.addCapability("VESA", _("VESA video extensions"));
00321   if (data1 & (1 << 14))                          // ESCD
00322     bios.addCapability("ESCD", _("ESCD"));
00323   if (data1 & (1 << 15))                          // boot from CD
00324     bios.addCapability("cdboot", _("Booting from CD-ROM/DVD"));
00325   if (data1 & (1 << 16))                          // selectable boot
00326     bios.addCapability("bootselect", _("Selectable boot path"));
00327   if (data1 & (1 << 17))                          // BIOS ROM is socketed
00328     bios.addCapability("socketedrom", _("BIOS ROM is socketed"));
00329   if (data1 & (1 << 18))                          // PCMCIA boot
00330     bios.addCapability("pcmciaboot", _("Booting from PCMCIA"));
00331   if (data1 & (1 << 19))                          // Enhanced Disk Drive
00332     bios.addCapability("EDD", _("Enhanced Disk Drive extensions"));
00333   if (data1 & (1 << 20))                          // NEC 9800 floppy
00334     bios.addCapability("int13floppynec", _("NEC 9800 floppy"));
00335   if (data1 & (1 << 21))                          // Toshiba floppy
00336     bios.addCapability("int13floppytoshiba", _("Toshiba floppy"));
00337   if (data1 & (1 << 22))                          // 5.25" 360KB floppy
00338     bios.addCapability("int13floppy360", _("5.25\" 360KB floppy"));
00339   if (data1 & (1 << 23))                          // 5.25" 1.2MB floppy
00340     bios.addCapability("int13floppy1200", _("5.25\" 1.2MB floppy"));
00341   if (data1 & (1 << 24))                          // 3.5" 720KB floppy
00342     bios.addCapability("int13floppy720", _("3.5\" 720KB floppy"));
00343   if (data1 & (1 << 25))                          // 3.5" 2.88MB floppy
00344     bios.addCapability("int13floppy2880", _("3.5\" 2.88MB floppy"));
00345   if (data1 & (1 << 26))                          // print screen key
00346     bios.addCapability("int5printscreen", _("Print Screen key"));
00347   if (data1 & (1 << 27))                          // 8042 kbd controller
00348     bios.addCapability("int9keyboard", _("i8042 keyboard controller"));
00349   if (data1 & (1 << 28))                          // serial line control
00350     bios.addCapability("int14serial", _("INT14 serial line control"));
00351   if (data1 & (1 << 29))                          // printer
00352     bios.addCapability("int17printer", _("INT17 printer control"));
00353   if (data1 & (1 << 30))                          // CGA/Mono video
00354     bios.addCapability("int10video", _("INT10 CGA/Mono video"));
00355   if (data1 & (1 << 31))                          // NEC PC-98
00356     bios.addCapability("pc98", _("NEC PC-98"));
00357 }
00358 
00359 
00360 static void dmi_bios_features_ext(u8 * data,
00361 int len,
00362 hwNode & bios)
00363 {
00364   if (len < 1)
00365     return;
00366 
00367   if (data[0] & (1 << 0))                         // ACPI
00368     bios.addCapability("ACPI", _("ACPI"));
00369   if (data[0] & (1 << 1))                         // USB
00370     bios.addCapability("USB", _("USB legacy emulation"));
00371   if (data[0] & (1 << 2))                         // AGP
00372     bios.addCapability("AGP", _("AGP"));
00373   if (data[0] & (1 << 3))                         // I2O boot
00374     bios.addCapability("I2Oboot", _("I2O booting"));
00375   if (data[0] & (1 << 4))                         // LS-120 boot
00376     bios.addCapability("LS120boot", _("Booting from LS-120"));
00377   if (data[0] & (1 << 5))                         // ATAPI ZIP boot
00378     bios.addCapability("ZIPboot", _("Booting from ATAPI ZIP"));
00379   if (data[0] & (1 << 6))                         // 1394 boot
00380     bios.addCapability("IEEE1394boot", _("Booting from IEEE1394 (Firewire)"));
00381   if (data[0] & (1 << 7))                         // smart battery
00382     bios.addCapability("smartbattery", _("Smart battery"));
00383 
00384   if (len < 1)
00385     return;
00386 
00387   if (data[1] & (1 << 0))                         // BIOS boot specification
00388     bios.addCapability("biosbootspecification", _("BIOS boot specification"));
00389   if (data[1] & (1 << 1))                         // function-key initiated network service boot
00390     bios.addCapability("netboot",
00391       _("Function-key initiated network service boot"));
00392   if (data[1] & (1 << 3))
00393     bios.addCapability("uefi", _("UEFI specification is supported"));
00394   if (data[1] & (1 << 4))
00395     bios.addCapability("virtualmachine", _("This machine is a virtual machine"));
00396 }
00397 
00398 
00399 static unsigned long dmi_cache_size(u16 n)
00400 {
00401   if (n & (1 << 15))
00402     return (n & 0x7FFF) * 64 * 1024;              // value is in 64K blocks
00403   else
00404     return (n & 0x7FFF) * 1024;                   // value is in 1K blocks
00405 }
00406 
00407 
00408 static void dmi_cache_sramtype(u16 c,
00409 hwNode & n)
00410 {
00411   string result = "";
00412 
00413 //if (c & (1 << 0))
00414 //result += "";
00415 //if (c & (1 << 1))
00416 //result += "";
00417   if (c & (1 << 2))
00418     n.addCapability("non-burst", _("Non-burst"));
00419   if (c & (1 << 3))
00420     n.addCapability("burst", _("Burst"));
00421   if (c & (1 << 4))
00422     n.addCapability("pipeline-burst", _("Pipeline burst"));
00423   if (c & (1 << 5))
00424     n.addCapability("synchronous", _("Synchronous"));
00425   if (c & (1 << 6))
00426     n.addCapability("asynchronous", _("Asynchronous"));
00427 }
00428 
00429 
00430 static void dmi_cache_describe(hwNode & n,
00431 u16 config,
00432 u16 sramtype = 0,
00433 u8 cachetype = 0)
00434 {
00435   string result = "";
00436   char buffer[10];
00437 
00438   dmi_cache_sramtype(sramtype, n);
00439   switch ((config >> 5) & 3)
00440   {
00441     case 0:
00442       n.addCapability("internal", _("Internal"));
00443       break;
00444     case 1:
00445       n.addCapability("external", _("External"));
00446       break;
00447   }
00448   snprintf(buffer, sizeof(buffer), "L%d ", (config & 7) + 1);
00449   result += " " + string(buffer);
00450 
00451   switch ((config >> 8) & 3)
00452   {
00453     case 0:
00454       n.addCapability("write-through", _("Write-trough"));
00455       break;
00456     case 1:
00457       n.addCapability("write-back", _("Write-back"));
00458       break;
00459     case 2:
00460       n.addCapability("varies", _("Varies With Memory Address"));
00461       break;
00462   }
00463 
00464   result += _("cache");
00465 
00466   switch (cachetype)
00467   {
00468     case 3:
00469       n.addCapability("instruction", _("Instruction cache"));
00470       break;
00471     case 4:
00472       n.addCapability("data", _("Data cache"));
00473       break;
00474     case 5:
00475       n.addCapability("unified", _("Unified cache"));
00476       break;
00477   }
00478 
00479   n.setDescription(hw::strip(result));
00480 }
00481 
00482 
00483 static const char *dmi_memory_array_location(u8 num)
00484 {
00485   static const char *memory_array_location[] =
00486   {
00487     "",                                           /* 0x00 */
00488     "",
00489     "",
00490     N_("System board or motherboard"),
00491     N_("ISA add-on card"),
00492     N_("EISA add-on card"),
00493     N_("PCI add-on card"),
00494     N_("MCA add-on card"),
00495     N_("PCMCIA add-on card"),
00496     N_("Proprietary add-on card"),
00497     N_("NuBus"),                                      /* 0x0A , master.mif says 16 */
00498   };
00499   static const char *jp_memory_array_location[] =
00500   {
00501     N_("PC-98/C20 add-on card"),                      /* 0xA0 */
00502     N_("PC-98/C24 add-on card"),
00503     N_("PC-98/E add-on card"),
00504     N_("PC-98/Local bus add-on card"),
00505     N_("PC-98/Card slot add-on card"),                /* 0xA4, from master.mif */
00506   };
00507   if (num <= 0x0A)
00508     return _(memory_array_location[num]);
00509   if (num >= 0xA0 && num < 0xA4)
00510     return _(jp_memory_array_location[num]);
00511   return "";
00512 }
00513 
00514 
00515 static const char *dmi_memory_device_form_factor(u8 num)
00516 {
00517   static const char *memory_device_form_factor[] =
00518   {
00519     "",
00520     "",
00521     "",
00522     N_(" SIMM"),
00523     N_(" SIP"),
00524     N_(" Chip"),
00525     N_(" DIP"),
00526     N_(" ZIP"),
00527     N_(" Proprietary Card"),
00528     N_(" DIMM"),
00529     N_(" TSOP"),
00530     N_(" Row of chips"),
00531     N_(" RIMM"),
00532     N_(" SODIMM"),
00533     N_(" SRIMM"),
00534     N_(" FB-DIMM"),
00535   };
00536   if (num > 0x0F)
00537     return "";
00538   return _(memory_device_form_factor[num]);
00539 }
00540 
00541 
00542 static const char *dmi_memory_device_type(u8 num)
00543 {
00544   static const char *memory_device_type[] =
00545   {
00546     "",                                           /* 0x00 */
00547     "",
00548     "",
00549     N_(" DRAM"),
00550     N_(" EDRAM"),
00551     N_(" VRAM"),
00552     N_(" SRAM"),
00553     N_(" RAM"),
00554     N_(" ROM"),
00555     N_(" FLASH"),
00556     N_(" EEPROM"),
00557     N_(" FEPROM"),
00558     N_(" EPROM"),
00559     N_(" CDRAM"),
00560     N_(" 3DRAM"),
00561     N_(" SDRAM"),
00562     N_(" SGRAM"),
00563     N_(" RDRAM"),
00564     N_(" DDR"),                                       /* 0x12 */
00565     N_(" DDR2"),                                      /* 0x13 */
00566     N_(" DDR2 FB-DIMM"),                              /* 0x14 */
00567     "",
00568     "",
00569     "",
00570     " DDR3",
00571     " FBD2",                              /* 0x19 */
00572   };
00573   if (num > 0x19)
00574     return "";
00575   return _(memory_device_type[num]);
00576 }
00577 
00578 
00579 static string dmi_memory_device_detail(u16 v)
00580 {
00581   string result = "";
00582 
00583   if (v & (1 << 3))
00584     result += " " + string(_("Fast-paged"));
00585   if (v & (1 << 4))
00586     result += " " + string(_("Static column"));
00587   if (v & (1 << 5))
00588     result += " " + string(_("Pseudo-static"));
00589   if (v & (1 << 6))
00590     result += " " + string(_("RAMBUS"));
00591   if (v & (1 << 7))
00592     result += " " + string(_("Synchronous"));
00593   if (v & (1 << 8))
00594     result += " " + string(_("CMOS"));
00595   if (v & (1 << 9))
00596     result += " " + string(_("EDO"));
00597   if (v & (1 << 10))
00598     result += " " + string(_("Window DRAM"));
00599   if (v & (1 << 11))
00600     result += " " + string(_("Cache DRAM"));
00601   if (v & (1 << 12))
00602     result += " " + string(_("Non-volatile"));
00603 
00604   return result;
00605 }
00606 
00607 
00608 void dmi_chassis(u8 code, hwNode & n)
00609 {
00610   static const char *chassis_type[] =
00611   {
00612     "", "", NULL,                                 /* 0x00 */
00613     "", "", NULL,
00614     "", "", NULL,
00615     "desktop", N_("Desktop Computer"), "desktopcomputer",
00616     "low-profile", N_("Low Profile Desktop Computer"), "desktopcomputer",
00617     "pizzabox", N_("Pizza Box Computer"), "pizzabox",
00618     "mini-tower", N_("Mini Tower Computer"), "towercomputer",
00619     "tower", N_("Tower Computer"), "towercomputer",
00620     "portable", N_("Portable Computer"), "laptop",
00621     "laptop", N_("Laptop"), "laptop",
00622     "notebook", N_("Notebook"), "laptop",
00623     "handheld", N_("Hand Held Computer"), "pda",
00624     "docking", N_("Docking Station"), NULL,
00625     "all-in-one", N_("All In One"), NULL,
00626     "sub-notebook", N_("Sub Notebook"), "laptop",
00627     "space-saving", N_("Space-saving Computer"), NULL,
00628     "lunchbox", N_("Lunch Box Computer"), NULL,
00629     "server", N_("System"), "server",
00630     "expansion", N_("Expansion Chassis"), NULL,
00631     "sub", N_("Sub Chassis"), NULL,
00632     "bus-expansion", N_("Bus Expansion Chassis"), NULL,
00633     "peripheral", N_("Peripheral Chassis"), NULL,
00634     "raid", N_("RAID Chassis"), "md",
00635     "rackmount", N_("Rack Mount Chassis"), "rackmount",
00636     "sealed", N_("Sealed-case PC"), NULL,
00637     "multi-system", N_("Multi-system"), "cluster",     /* 0x19 */
00638     "pci", N_("Compact PCI"), NULL,
00639     "tca", N_("Advanced TCA"), NULL,
00640     "blade", N_("Blade"), NULL,           /* 0x1C */
00641     "enclosure", N_("Blade enclosure"), NULL,           /* 0x1D */
00642   };
00643 
00644   if(code <= 0x1D)
00645   {
00646     if(n.getDescription()=="") n.setDescription(_(chassis_type[1+3*code]));
00647 
00648     if(code >= 3)
00649     {
00650       n.setConfig("chassis", chassis_type[3*code] );
00651       if(chassis_type[2+3*code])
00652         n.addHint("icon", string(chassis_type[2+3*code]));
00653     }
00654   }
00655 };
00656 static const char *dmi_processor_family(u8 code)
00657 {
00658   static const char *processor_family[] =
00659   {
00660     "",                                           /* 0x00 */
00661     "",
00662     "",
00663     "8086",
00664     "80286",
00665     "i386",
00666     "i486",
00667     "8087",
00668     "80287",
00669     "80387",
00670     "80487",
00671     "Pentium",
00672     "Pentium Pro",
00673     "Pentium II",
00674     "Pentium MMX",
00675     "Celeron",
00676     "Pentium II Xeon",
00677     "Pentium III",
00678     "M1",
00679     "M2",
00680     "Celeron M",                                           /* 0x14 */
00681     "Pentium 4 HT",
00682     "",
00683     "",
00684     "Duron",
00685     "K5",
00686     "K6",
00687     "K6-2",
00688     "K6-3",
00689     "Athlon",
00690     "AMD2900",
00691     "K6-2+",
00692     "Power PC",
00693     "Power PC 601",
00694     "Power PC 603",
00695     "Power PC 603+",
00696     "Power PC 604",
00697     "Power PC 620",
00698     "Power PC x704",
00699     "Power PC 750",
00700     "Core Duo",                                           /* 0x28 */
00701     "Core Duo mobile",
00702     "Core Solo mobile",
00703     "Atom",
00704     "",
00705     "",
00706     "",
00707     "",
00708     "Alpha",                                      /* 0x30 */
00709     "Alpha 21064",
00710     "Alpha 21066",
00711     "Alpha 21164",
00712     "Alpha 21164PC",
00713     "Alpha 21164a",
00714     "Alpha 21264",
00715     "Alpha 21364",
00716     "",                                           /* 0x38 */
00717     "",
00718     "",
00719     "",
00720     "",
00721     "",
00722     "",
00723     "",
00724     "MIPS",                                       /* 0x40 */
00725     "MIPS R4000",
00726     "MIPS R4200",
00727     "MIPS R4400",
00728     "MIPS R4600",
00729     "MIPS R10000",
00730     "",                                           /* 0x46 */
00731     "",
00732     "",
00733     "",
00734     "",
00735     "",
00736     "",
00737     "",
00738     "",
00739     "",
00740     "SPARC",
00741     "SuperSPARC",
00742     "MicroSPARC II",
00743     "MicroSPARC IIep",
00744     "UltraSPARC",
00745     "UltraSPARC II",
00746     "UltraSPARC IIi",
00747     "UltraSPARC III",
00748     "UltraSPARC IIIi",
00749     "",                                           /* 0x59 */
00750     "",
00751     "",
00752     "",
00753     "",
00754     "",
00755     "",                                           /* 0x5F */
00756     "68040",
00757     "68xxx",
00758     "68000",
00759     "68010",
00760     "68020",
00761     "68030",
00762     "",                                           /* 0x66 */
00763     "",
00764     "",
00765     "",
00766     "",
00767     "",
00768     "",
00769     "",
00770     "",
00771     "",                                           /* 0x6F */
00772     "Hobbit",
00773     "",                                           /* 0x71 */
00774     "",
00775     "",
00776     "",
00777     "",
00778     "",
00779     "",                                           /* 0x77 */
00780     "Crusoe TM5000",
00781     "Crusoe TM3000",
00782     "Efficeon TM8000",                                           /* 0x7A */
00783     "",
00784     "",
00785     "",
00786     "",
00787     "",                                           /* 0x7F */
00788     "Weitek",
00789     "",                                           /* 0x81 */
00790     "Itanium",
00791     "Athlon 64",
00792     "Opteron",
00793     "Sempron",                                           /* 0x85 */
00794     "Turion 64 Mobile",
00795     "Dual-Core Opteron",
00796     "Athlon 64 X2 Dual-Core",
00797     "Turion 64 X2 Mobile",
00798     "Quad-Core Opteron",
00799     "3rd-generation Opteron",
00800     "Phenom FX Quad-Core",
00801     "Phenom X4 Quad-Core",
00802     "Phenom X2 Dual-Core",
00803     "Athlon X2 Dual-Core",                                           /* 0x8F */
00804     "PA-RISC",
00805     "PA-RISC 8500",
00806     "PA-RISC 8000",
00807     "PA-RISC 7300LC",
00808     "PA-RISC 7200",
00809     "PA-RISC 7100LC",
00810     "PA-RISC 7100",
00811     "",                                           /* 0x97 */
00812     "",
00813     "",
00814     "",
00815     "",
00816     "",
00817     "",
00818     "",
00819     "",                                           /* 0x9F */
00820     "V30",
00821     "",                                           /* 0xA1 */
00822     "",
00823     "",
00824     "",
00825     "",
00826     "",
00827     "",
00828     "",
00829     "",
00830     "",
00831     "",
00832     "",
00833     "",
00834     "",
00835     "",                                           /* 0xAF */
00836     "Pentium III Xeon",
00837     "Pentium III Speedstep",
00838     "Pentium 4",
00839     "Xeon",
00840     "AS400",
00841     "Xeon MP",
00842     "Athlon XP",
00843     "Athlon MP",
00844     "Itanium 2",
00845     "Pentium M",
00846     "Celeron D",                                           /* 0xBA */
00847     "Pentium D",
00848     "Pentium Extreme Edition",
00849     "Core Solo",
00850     "",
00851     "Core 2 Duo",
00852     "Core 2 Solo",
00853     "Core 2 Extreme",
00854     "Core 2 Quad",
00855     "Core 2 Extreme mobile",
00856     "Core 2 Duo mobile",
00857     "Core 2 Solo mobile",
00858     "Core i7",
00859     "Dual-Core Celeron",                                           /* 0xC7 */
00860     "IBM390",
00861     "G4",
00862     "G5",
00863     "ESA/390 G6",                                           /* 0xCB */
00864     "z/Architectur base",
00865     "Core i5",
00866     "Core i3",
00867     "",
00868     "",
00869     "",
00870     "VIA C7-M",
00871     "VIA C7-D",
00872     "VIA C7",
00873     "VIA Eden",
00874     "Multi-Core Xeon",
00875     "Dual-Core Xeon 3xxx",
00876     "Quad-Core Xeon 3xxx",
00877     "VIA Nano",
00878     "Dual-Core Xeon 5xxx",
00879     "Quad-Core Xeon 5xxx",  /* 0xDB */
00880     "",
00881     "Dual-Core Xeon 7xxx",
00882     "Quad-Core Xeon 7xxx",
00883     "Multi-Core Xeon 7xxx",
00884     "Multi-Core Xeon 3400",
00885     "",
00886     "",
00887     "",
00888     "",
00889     "",
00890     "Embedded Opteron Quad-Core",
00891     "Phenom Triple-Core",
00892     "Turion Ultra Dual-Core Mobile",
00893     "Turion Dual-Core Mobile",
00894     "Athlon Dual-Core",
00895     "Sempron SI",
00896     "Phenom II",
00897     "Athlon II",
00898     "Six-Core Opteron",
00899     "Sempron M",
00900     "",
00901     "",
00902     "",
00903     "",
00904     "",
00905     "",
00906     "",
00907     "",
00908     "",
00909     "",                                           /* 0xF9 */
00910     "i860",
00911     "i960",
00912     "",                                           /* 0xFC */
00913     "",
00914     "",
00915     ""                                            /* 0xFF */
00916 /* master.mif has values beyond that, but they can't be used for DMI */
00917   };
00918 
00919   if (code >= 0xFF)
00920     return "";
00921 
00922   return processor_family[code];
00923 }
00924 
00925 
00926 static string dmi_handle(u16 handle)
00927 {
00928   char buffer[10];
00929   snprintf(buffer, sizeof(buffer), "DMI:%04X", handle);
00930 
00931   return string(buffer);
00932 }
00933 
00934 
00935 static void dmi_table(int fd,
00936 u32 base,
00937 int len,
00938 int num,
00939 hwNode & node,
00940 int dmiversionmaj,
00941 int dmiversionmin)
00942 {
00943   unsigned char *buf = (unsigned char *) malloc(len);
00944   struct dmi_header *dm;
00945   hwNode *hardwarenode = NULL;
00946   u8 *data;
00947   int i = 0;
00948   string handle;
00949   u32 mmoffset = 0;
00950   void *mmp = NULL;
00951 
00952   if (len == 0)
00953 // no data
00954     return;
00955 
00956   if (buf == NULL)
00957 // memory exhausted
00958     return;
00959 
00960   mmoffset = base % getpagesize();
00961 
00962   mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset);
00963   if (mmp == MAP_FAILED)
00964   {
00965     free(buf);
00966     return;
00967   }
00968   memcpy(buf, (u8 *) mmp + mmoffset, len);
00969 
00970   munmap(mmp, mmoffset + len);
00971 
00972   data = buf;
00973   while (data + sizeof(struct dmi_header) <= (u8 *) buf + len)
00974   {
00975     u32 u, u2;
00976     dm = (struct dmi_header *) data;
00977 
00978 /*
00979  * we won't read beyond allocated memory
00980  */
00981     if (data + dm->length > (u8 *) buf + len)
00982 // incomplete structure, abort decoding
00983       break;
00984 
00985     handle = dmi_handle(dm->handle);
00986 
00987     hardwarenode = node.getChild("core");
00988     if (!hardwarenode)
00989     {
00990       node.addChild(hwNode("core", hw::bus));
00991       hardwarenode = node.getChild("core");
00992     }
00993     if (!hardwarenode)
00994       hardwarenode = &node;
00995 
00996     switch (dm->type)
00997     {
00998       case 0:
00999 // BIOS Information Block
01000         {
01001           string release(dmi_string(dm,
01002             data[8]));
01003           hwNode newnode("firmware",
01004             hw::memory,
01005             dmi_string(dm,
01006             data[4]));
01007           newnode.setVersion(dmi_string(dm, data[5]));
01008           newnode.setCapacity(64 * data[9] * 1024);
01009           newnode.setSize(16 * (0x10000 - (data[7] << 8 | data[6])));
01010 //newnode.setPhysId(16 * (data[7] << 8 | data[6]));
01011           newnode.setPhysId(dm->handle);
01012           newnode.setDescription(_("BIOS"));
01013           newnode.addHint("icon", string("chip"));
01014           newnode.claim();
01015 
01016           dmi_bios_features(data[13] << 24 | data[12] << 16 | data[11] << 8 |
01017             data[10],
01018             data[17] << 24 | data[16] << 16 | data[15] << 8 |
01019             data[14], newnode);
01020 
01021           if (dm->length > 0x12)
01022             dmi_bios_features_ext(&data[0x12], dm->length - 0x12, newnode);
01023 
01024           if (release != "")
01025             newnode.setDate(release);
01026           hardwarenode->addChild(newnode);
01027         }
01028         break;
01029 
01030       case 1:
01031 // System Information Block
01032         node.setHandle(handle);
01033         node.setVendor(dmi_string(dm, data[4]));
01034         node.setProduct(dmi_string(dm, data[5]));
01035         node.setVersion(dmi_string(dm, data[6]));
01036         node.setSerial(dmi_string(dm, data[7]));
01037         if (dm->length >= 0x19)
01038           node.setConfig("uuid", dmi_uuid(data + 8));
01039         if (dm->length >= 0x1B)
01040         {
01041           node.setConfig("sku", dmi_string(dm, data[0x19]));
01042          node.setProduct(node.getProduct() + " (" + dmi_string(dm, data[0x19]) + ")");
01043           node.setConfig("family", dmi_string(dm, data[0x1A]));
01044         }
01045         break;
01046 
01047       case 2:
01048 // Board Information Block
01049         {
01050 
01051                                                   // we are the only system board on the computer so connect everything to us
01052           if ((dm->length <= 0x0E) || (data[0x0E] == 0))
01053           {
01054             hardwarenode->setVendor(dmi_string(dm, data[4]));
01055             hardwarenode->setProduct(dmi_string(dm, data[5]));
01056             hardwarenode->setVersion(dmi_string(dm, data[6]));
01057             hardwarenode->setSerial(dmi_string(dm, data[7]));
01058             if(dm->length >= 0x0a)
01059               hardwarenode->setSlot(dmi_string(dm, data[0x0A]));
01060             hardwarenode->setHandle(handle);
01061             hardwarenode->setDescription(_("Motherboard"));
01062             hardwarenode->addHint("icon", string("motherboard"));
01063           }
01064           else
01065           {
01066             hwNode newnode("board",
01067               hw::bus);
01068 
01069             if (dm->length >= 0x0E)
01070               for (int i = 0; i < data[0x0E]; i++)
01071                 newnode.
01072                   attractHandle(dmi_handle
01073                   (data[0x0F + 2 * i + 1] << 8 |
01074                   data[0x0F + 2 * i]));
01075 
01076             newnode.setVendor(dmi_string(dm, data[4]));
01077             newnode.setProduct(dmi_string(dm, data[5]));
01078             newnode.setVersion(dmi_string(dm, data[6]));
01079             newnode.setSerial(dmi_string(dm, data[7]));
01080             newnode.setSlot(dmi_string(dm, data[0x0A]));
01081             newnode.setHandle(handle);
01082             newnode.setPhysId(dm->handle);
01083             newnode.setDescription(dmi_board_type(data[0x0D]));
01084             hardwarenode->addChild(newnode);
01085           }
01086         }
01087         break;
01088 
01089       case 3:
01090 // Chassis Information Block
01091 //
01092 // special case: if the system characteristics are still unknown,
01093 // use values from the chassis
01094         if (node.getVendor() == "")
01095           node.setVendor(dmi_string(dm, data[4]));
01096         if (node.getProduct() == "")
01097           node.setProduct(dmi_string(dm, data[5]));
01098         if (node.getVersion() == "")
01099           node.setVersion(dmi_string(dm, data[6]));
01100         if (node.getSerial() == "")
01101           node.setSerial(dmi_string(dm, data[7]));
01102         dmi_chassis(data[5] & 0x7F, node);
01103         break;
01104 
01105       case 4:
01106 // Processor
01107         {
01108           hwNode newnode("cpu",
01109             hw::processor);
01110 
01111           newnode.claim();
01112           newnode.setBusInfo(cpubusinfo(currentcpu++));
01113           newnode.setSlot(dmi_string(dm, data[4]));
01114           newnode.setDescription(_("CPU"));
01115           newnode.addHint("icon", string("cpu"));
01116           newnode.setProduct(dmi_processor_family(data[6]));
01117           newnode.setVersion(dmi_string(dm, data[0x10]));
01118           newnode.setVendor(dmi_string(dm, data[7]));
01119           newnode.setPhysId(dm->handle);
01120           if (dm->length > 0x1A)
01121           {
01122 // L1 cache
01123             newnode.attractHandle(dmi_handle(data[0x1B] << 8 | data[0x1A]));
01124 // L2 cache
01125             newnode.attractHandle(dmi_handle(data[0x1D] << 8 | data[0x1C]));
01126 // L3 cache
01127             newnode.attractHandle(dmi_handle(data[0x1F] << 8 | data[0x1E]));
01128           }
01129           if (dm->length > 0x20)
01130           {
01131             newnode.setSerial(dmi_string(dm, data[0x20]));
01132             if (dmi_string(dm, data[0x22]) != "")
01133               newnode.setProduct(newnode.getProduct() + " (" +
01134                 string(dmi_string(dm, data[0x22])) + ")");
01135           }
01136 
01137 // CPU socket populated ?
01138           if (data[0x18] & 0x40)
01139           {
01140        // external clock
01141               u = data[0x13] << 8 | data[0x12];
01142               newnode.setClock(u * 1000000);
01143        // maximum speed
01144               u = data[0x15] << 8 | data[0x14];
01145               newnode.setCapacity(u * 1000000);
01146        // current speed
01147               u = data[0x17] << 8 | data[0x16];
01148               newnode.setSize(u * 1000000);
01149 
01150               if (newnode.getCapacity() < newnode.getSize())
01151               newnode.setCapacity(0);
01152 
01153        // CPU enabled/disabled by BIOS?
01154               u = data[0x18] & 0x07;
01155               if ((u == 2) || (u == 3) || (u == 4))
01156               newnode.disable();
01157           }
01158           else
01159           {
01160             newnode.setBusInfo("");       // blank businfo to make sure further detections can't confuse this empty CPU slot with a real CPU
01161             newnode.setDescription(newnode.getDescription() + " " + _("[empty]"));
01162             newnode.disable();
01163           }
01164 
01165           if (dm->length >= 0x28)
01166           { 
01167             if (data[0x23] != 0)
01168               newnode.setConfig("cores", data[0x23]);
01169             if (data[0x24] != 0)
01170               newnode.setConfig("enabledcores", data[0x24]);
01171             if (data[0x25] != 0)
01172               newnode.setConfig("threads", data[0x25]);
01173             if (data[0x26] & 0x4)
01174               newnode.addCapability("x86-64", "64bits extensions (x86-64)");
01175           }
01176 
01177           newnode.setHandle(handle);
01178 
01179           hardwarenode->addChild(newnode);
01180         }
01181         break;
01182 
01183       case 5:
01184 // Memory Controller (obsolete in DMI 2.1+)
01185 // therefore ignore the entry if the DMI version is recent enough
01186         if ((dmiversionmaj < 2)
01187           || ((dmiversionmaj == 2) && (dmiversionmin < 1)))
01188         {
01189           unsigned long long size = 0;
01190           hwNode newnode("memory",
01191             hw::memory);
01192 
01193           newnode.setHandle(handle);
01194           newnode.setPhysId(dm->handle);
01195 
01196           size = data[0x0E] * (1 << data[8]) * 1024 * 1024;
01197           newnode.setCapacity(size);
01198 
01199 // loop through the controller's slots and link them to us
01200           for (i = 0; i < data[0x0E]; i++)
01201           {
01202             u16 slothandle = data[0x0F + 2 * i + 1] << 8 | data[0x0F + 2 * i];
01203             newnode.attractHandle(dmi_handle(slothandle));
01204           }
01205 
01206           newnode.setProduct(dmi_decode_ram(data[0x0C] << 8 | data[0x0B]) +
01207             _(" Memory Controller"));
01208 
01209           hardwarenode->addChild(newnode);
01210         }
01211         break;
01212 
01213       case 6:
01214 // Memory Bank (obsolete in DMI 2.1+)
01215 // therefore ignore the entry if the DMI version is recent enough
01216         if ((dmiversionmaj < 2)
01217           || ((dmiversionmaj == 2) && (dmiversionmin < 1)))
01218         {
01219           hwNode newnode("bank",
01220             hw::memory);
01221           unsigned long long clock = 0;
01222           unsigned long long capacity = 0;
01223           unsigned long long size = 0;
01224 
01225           newnode.setDescription(_("empty memory bank"));
01226           newnode.setSlot(dmi_string(dm, data[4]).c_str());
01227           if (data[6])
01228             clock = 1000000000 / data[6];         // convert value from ns to Hz
01229           newnode.setClock(clock);
01230           newnode.setDescription(dmi_decode_ram(data[8] << 8 | data[7]));
01231           newnode.addHint("icon", string("memory"));
01232 // installed size
01233           switch (data[9] & 0x7F)
01234           {
01235             case 0x7D:
01236             case 0x7E:
01237             case 0x7F:
01238               break;
01239             default:
01240               size = (1 << (data[9] & 0x7F)) << 20;
01241           }
01242           if (data[9] & 0x80)
01243             size *= 2;
01244 // enabled size
01245           switch (data[10] & 0x7F)
01246           {
01247             case 0x7D:
01248             case 0x7E:
01249             case 0x7F:
01250               break;
01251             default:
01252               capacity = (1 << (data[10] & 0x7F)) << 20;
01253           }
01254           if (data[10] & 0x80)
01255             capacity *= 2;
01256 
01257           newnode.setCapacity(capacity);
01258           newnode.setSize(size);
01259           if(newnode.getSize()==0)
01260             newnode.setDescription(newnode.getDescription() + " " + _("[empty]"));
01261           if ((data[11] & 4) == 0)
01262           {
01263             if (data[11] & (1 << 0))
01264 // bank has uncorrectable errors (BIOS disabled)
01265               newnode.disable();
01266           }
01267 
01268           newnode.setHandle(handle);
01269 
01270           hardwarenode->addChild(newnode);
01271         }
01272         break;
01273       case 7:
01274 // Cache
01275         {
01276           hwNode newnode("cache",
01277             hw::memory);
01278           int level;
01279 
01280           newnode.setSlot(dmi_string(dm, data[4]));
01281           u = data[6] << 8 | data[5];
01282           level = 1 + (u & 7);
01283 
01284           if (dm->length > 0x11)
01285             dmi_cache_describe(newnode, u, data[0x0E] << 8 | data[0x0D],
01286               data[0x11]);
01287           else
01288             dmi_cache_describe(newnode, u, data[0x0E] << 8 | data[0x0D]);
01289 
01290           if (!(u & (1 << 7)))
01291             newnode.disable();
01292 
01293           newnode.setSize(dmi_cache_size(data[9] | data[10] << 8));
01294           newnode.setCapacity(dmi_cache_size(data[7] | (data[8] << 8)));
01295           if ((dm->length > 0x0F) && (data[0x0F] != 0))
01296           {
01297                                                   // convert from ns to Hz
01298             newnode.setClock(1000000000 / data[0x0F]);
01299           }
01300 
01301           newnode.setHandle(handle);
01302           newnode.setPhysId(dm->handle);
01303           newnode.claim();
01304           if(newnode.getSize()!=0)
01305             hardwarenode->addChild(newnode);
01306         }
01307         break;
01308       case 8:
01309 //printf("\tPort Connector\n");
01310 //printf("\t\tInternal Designator: %s\n",
01311 //dmi_string(dm, data[4]).c_str());
01312 //printf("\t\tInternal Connector Type: %s\n",
01313 //dmi_port_connector_type(data[5]));
01314 //printf("\t\tExternal Designator: %s\n",
01315 //dmi_string(dm, data[6]).c_str());
01316 //printf("\t\tExternal Connector Type: %s\n",
01317 //dmi_port_connector_type(data[7]));
01318 //printf("\t\tPort Type: %s\n", dmi_port_type(data[8]));
01319         break;
01320       case 9:
01321 #if 0
01322         {
01323           hwNode newnode("cardslot",
01324             hw::bus);
01325           newnode.setHandle(handle);
01326           newnode.setSlot(dmi_string(dm, data[4]));
01327           printf("\t\tType: %s%s%s\n",
01328             dmi_bus_width(data[6]),
01329             dmi_card_size(data[8]), dmi_bus_name(data[5]));
01330           if (data[7] == 3)
01331             printf("\t\tStatus: Available.\n");
01332           if (data[7] == 4)
01333             printf("\t\tStatus: In use.\n");
01334           if (data[11] & 0xFE)
01335             dmi_card_props(data[11]);
01336 //hardwarenode->addChild(newnode);
01337         }
01338 #endif
01339         break;
01340       case 10:
01341 #if 0
01342         printf("\tOn Board Devices Information\n");
01343         for (u = 2; u * 2 + 1 < dm->length; u++)
01344         {
01345           printf("\t\tDescription: %s : %s\n",
01346             dmi_string(dm, data[1 + 2 * u]).c_str(),
01347             (data[2 * u]) & 0x80 ? "Enabled" : "Disabled");
01348           printf("\t\tType: %s\n", dmi_onboard_type(data[2 * u]));
01349         }
01350 #endif
01351 
01352         break;
01353       case 11:
01354 // OEM Data
01355         break;
01356       case 12:
01357 // Configuration Information
01358         break;
01359       case 13:
01360 #if 0
01361         printf("\tBIOS Language Information\n");
01362         printf("\t\tInstallable Languages: %u\n", data[4]);
01363         for (u = 1; u <= data[4]; u++)
01364         {
01365           printf("\t\t\t%s\n", dmi_string(dm, u).c_str());
01366         }
01367         printf("\t\tCurrently Installed Language: %s\n",
01368           dmi_string(dm, data[21]).c_str());
01369 #endif
01370         break;
01371       case 14:
01372 // Group Associations
01373         break;
01374       case 15:
01375 // Event Log
01376         break;
01377       case 16:
01378 // Physical Memory Array
01379         {
01380           hwNode newnode("memory",
01381             hw::memory);
01382           string id = "";
01383           string description = "";
01384           switch (data[5])
01385           {
01386             case 0x03:
01387               description = _("System Memory");
01388               newnode.claim();
01389               newnode.addHint("icon", string("memory"));
01390               break;
01391             case 0x04:
01392               description = _("Video Memory");
01393               break;
01394             case 0x05:
01395               description = _("Flash Memory");
01396               break;
01397             case 0x06:
01398               description = _("NVRAM");
01399               break;
01400             case 0x07:
01401               description = _("Cache Memory");
01402               newnode.addHint("icon", string("memory"));
01403               break;
01404             default:
01405               description = _("Generic Memory");
01406               newnode.addHint("icon", string("memory"));
01407           }
01408 
01409           newnode.setHandle(handle);
01410           newnode.setPhysId(dm->handle);
01411           newnode.setDescription(description);
01412           newnode.setSlot(dmi_memory_array_location(data[4]));
01413 //printf("\t\tError Correction Type: %s\n",
01414 //dmi_memory_array_error_correction_type(data[6]));
01415           u2 = data[10] << 24 | data[9] << 16 | data[8] << 8 | data[7];
01416           if (u2 != 0x80000000)                   // magic value for "unknown"
01417             newnode.setCapacity(u2 * 1024);
01418           hardwarenode->addChild(newnode);
01419         }
01420         break;
01421       case 17:
01422 // Memory Device
01423         {
01424           hwNode newnode("bank",
01425             hw::memory);
01426           string slot = "";
01427           string description = "";
01428           unsigned long long size = 0;
01429           unsigned long long clock = 0;
01430           u16 width = 0;
01431           char bits[10];
01432           string arrayhandle;
01433           newnode.setDescription(_("empty memory bank"));
01434           newnode.addHint("icon", string("memory"));
01435           arrayhandle = dmi_handle(data[5] << 8 | data[4]);
01436           strcpy(bits, "");
01437 // total width
01438           u = data[9] << 8 | data[8];
01439           if (u != 0xffff)
01440             width = u;
01441 //data width
01442           u = data[11] << 8 | data[10];
01443           if ((u != 0xffff) && (u != 0))
01444           {
01445             if ((u == width) || (width == 0))
01446             {
01447               snprintf(bits, sizeof(bits), "%d", u);
01448               newnode.setWidth(width);
01449             }
01450             else
01451             {
01452               snprintf(bits, sizeof(bits), "%d/%d", width, u);
01453               newnode.setWidth(u<width?u:width);
01454             }
01455           }
01456           else
01457           {
01458             if (width != 0)
01459             {
01460               snprintf(bits, sizeof(bits), "%d", width);
01461               newnode.setWidth(width);
01462             }
01463           }
01464 
01465 // size
01466           u = data[13] << 8 | data[12];
01467           if (u != 0xffff)
01468             size = (1024ULL * (u & 0x7fff) * ((u & 0x8000) ? 1 : 1024ULL));
01469           description += string(dmi_memory_device_form_factor(data[14]));
01470           slot = dmi_string(dm, data[16]);
01471 //printf("\t\tBank Locator: %s\n", dmi_string(dm, data[17]));
01472           description += string(dmi_memory_device_type(data[18]));
01473           u = data[20] << 8 | data[19];
01474           if (u & 0x1ffe)
01475             description += dmi_memory_device_detail(u);
01476           if (dm->length > 21)
01477           {
01478             char buffer[80];
01479             u = data[22] << 8 | data[21];
01480 // speed
01481             clock = u * 1000000;                  // u is a frequency in MHz
01482             if (u == 0)
01483               strcpy(buffer, "");
01484             else
01485               snprintf(buffer, sizeof(buffer),
01486                 "%u MHz (%.1f ns)", u, (1000.0 / u));
01487             description += " " + string(buffer);
01488           }
01489 
01490           newnode.setHandle(handle);
01491 //newnode.setPhysId(dm->handle);
01492           newnode.setSlot(slot);
01493           if (dm->length > 23)
01494             newnode.setVendor(dmi_string(dm, data[23]));
01495           if (dm->length > 24)
01496             newnode.setSerial(dmi_string(dm, data[24]));
01497           if (dm->length > 26)
01498             newnode.setProduct(dmi_string(dm, data[26]));
01499           newnode.setDescription(description);
01500           newnode.setSize(size);
01501           if(newnode.getSize()==0)
01502             newnode.setDescription(newnode.getDescription() + " " + _("[empty]"));
01503           newnode.setClock(clock);
01504           hwNode *memoryarray = hardwarenode->findChildByHandle(arrayhandle);
01505           if (memoryarray)
01506             memoryarray->addChild(newnode);
01507           else
01508           {
01509             hwNode ramnode("memory",
01510               hw::memory);
01511             ramnode.addChild(newnode);
01512             ramnode.addHint("icon", string("memory"));
01513             hardwarenode->addChild(ramnode);
01514           }
01515         }
01516         break;
01517       case 18:
01518 // 32-bit Memory Error Information
01519         break;
01520       case 19:
01521 // Memory Array Mapped Address
01522         {
01523           hwNode newnode("range",
01524             hw::address);
01525           unsigned long start, end;
01526           string arrayhandle = dmi_handle(data[0x0D] << 8 | data[0x0C]);
01527           start = ((data[4] | data[5] << 8) | (data[6] | data[7] << 8) << 16);
01528           end = ((data[8] | data[9] << 8) | (data[10] | data[11] << 8) << 16);
01529           if (end - start < 512)                  // memory range is smaller thant 512KB
01530           {
01531 // consider that values were expressed in megagytes
01532             start *= 1024;
01533             end *= 1024;
01534           }
01535 
01536           newnode.setStart(start * 1024);         // values are in KB
01537           if (end != start)
01538                                                   // values are in KB
01539               newnode.setSize((end - start + 1) * 1024);
01540           newnode.setHandle(handle);
01541 #if 0
01542           hwNode *memoryarray = hardwarenode->findChildByHandle(arrayhandle);
01543           if (memoryarray)
01544             memoryarray->setPhysId(newnode.getStart());
01545 #endif
01546         }
01547         break;
01548       case 20:
01549 // Memory Device Mapped Address
01550         {
01551           hwNode newnode("range",
01552             hw::address);
01553           unsigned long start, end;
01554           string devicehandle = dmi_handle(data[0x0D] << 8 | data[0x0C]);
01555           start = ((data[4] | data[5] << 8) | (data[6] | data[7] << 8) << 16);
01556           end = ((data[8] | data[9] << 8) | (data[10] | data[11] << 8) << 16);
01557           if (end - start < 512)                  // memory range is smaller than 512KB
01558           {
01559 // consider that values were expressed in megagytes
01560             start *= 1024;
01561             end *= 1024;
01562           }
01563 
01564           newnode.setStart(start * 1024);         // values are in KB
01565           if (end != start)
01566                                                   // values are in KB
01567               newnode.setSize((end - start + 1) * 1024);
01568           newnode.setHandle(handle);
01569 #if 0
01570           hwNode *memorydevice = hardwarenode->findChildByHandle(devicehandle);
01571           if (memorydevice && (newnode.getSize() != 0)
01572             && (newnode.getSize() <= memorydevice->getSize()))
01573             memorydevice->setPhysId(newnode.getStart());
01574 #endif
01575         }
01576         break;
01577       case 21:
01578 // Built-In Pointing Device
01579         break;
01580       case 22:
01581 // Portable Battery
01582         if (dm->length < 0x10)
01583           break;
01584         else
01585         {
01586           hwNode batt("battery", hw::power);
01587 
01588           batt.addHint("icon", string("battery"));
01589           batt.claim();
01590           batt.setHandle(handle);
01591           batt.setVendor(dmi_string(dm, data[0x05]));
01592                                                   // name
01593           batt.setProduct(dmi_string(dm, data[0x08]));
01594                                                   // location
01595           batt.setSlot(dmi_string(dm, data[0x04]));
01596           if(data[0x06] || dm->length<0x1A)       // manufacture date
01597             batt.setVersion(dmi_string(dm, data[0x06]));
01598           if(data[0x07] || dm->length<0x1A)
01599             batt.setSerial(dmi_string(dm, data[0x07]));
01600           batt.setConfig("voltage", dmi_battery_voltage(data[0x0c] + 256*data[0x0d]));
01601           if(dm->length<0x1A)
01602             batt.setCapacity(dmi_battery_capacity(data[0x0a] + 256*data[0x0b], 1));
01603           else
01604             batt.setCapacity(dmi_battery_capacity(data[0x0a] + 256*data[0x0b], data[0x15]));
01605           if(data[0x09]!=0x02 || dm->length<0x1A)
01606             batt.setDescription(hw::strip(string(dmi_battery_chemistry(data[0x09])) + " Battery"));
01607 
01608           node.addChild(batt);
01609         }
01610         break;
01611       case 23:
01612 // System Reset
01613         break;
01614       case 24:
01615 // Hardware Security
01616         if (dm->length < 0x05)
01617           break;
01618         node.setConfig("power-on_password",
01619           dmi_hardware_security_status(data[0x04]>>6));
01620         node.setConfig("keyboard_password",
01621           dmi_hardware_security_status((data[0x04]>>4)&0x3));
01622         node.setConfig("administrator_password",
01623           dmi_hardware_security_status((data[0x04]>>2)&0x3));
01624         node.setConfig("frontpanel_password",
01625           dmi_hardware_security_status(data[0x04]&0x3));
01626         break;
01627       case 25:
01628 // System Power Controls
01629         break;
01630       case 26:
01631 // Voltage Sensor
01632         break;
01633       case 27:
01634 // Cooling Device
01635         break;
01636       case 28:
01637 // Temperature Sensor
01638         break;
01639       case 29:
01640 // Current Sensor
01641         break;
01642       case 30:
01643 // Out-of-Band Remote Access
01644         if (dm->length < 0x06)
01645           break;
01646         else
01647         {
01648           hwNode oob("remoteaccess", hw::system);
01649 
01650           oob.setVendor(dmi_string(dm, data[0x04]));
01651           if(data[0x05] & 0x2) oob.addCapability("outbound", _("make outbound connections"));
01652           if(data[0x05] & 0x1) oob.addCapability("inbound", _("receive inbound connections"));
01653           node.addChild(oob);
01654         }
01655         break;
01656       case 31:
01657 // Boot Integrity Services Entry Point
01658         break;
01659       case 32:
01660 // System Boot Information
01661         if (dm->length < 0x0B)
01662           break;
01663         node.setConfig("boot", dmi_bootinfo(data[0x0a]));
01664         break;
01665       case 33:
01666 // 64-bit Memory Error Information
01667         break;
01668       case 34:
01669 // Management Device
01670         break;
01671       case 35:
01672 // Management Device Component
01673         break;
01674       case 36:
01675 // Management Device Threshold Data
01676         break;
01677       case 37:
01678 // Memory Channel
01679         break;
01680       case 38:
01681 // IPMI Device
01682         break;
01683       case 39:
01684 // Power Supply
01685         if (dm->length < 0x15)
01686           break;
01687         else
01688         {
01689           hwNode power("power", hw::power);
01690 
01691           power.setDescription(dmi_string(dm, data[0x06]));
01692           power.setVendor(dmi_string(dm, data[0x07]));
01693           power.setSerial(dmi_string(dm, data[0x08]));
01694           power.setProduct(dmi_string(dm, data[0x0a]));
01695           power.setVersion(dmi_string(dm, data[0x0b]));
01696           power.setCapacity(data[0x0c] + 256*data[0x0d]);
01697           node.addChild(power);
01698         }
01699         break;
01700       case 126:
01701 // Inactive
01702         break;
01703       case 127:
01704 // End-of-Table
01705         break;
01706       default:
01707         break;
01708     }
01709     data += dm->length;
01710     while (*data || data[1])
01711       data++;
01712     data += 2;
01713     i++;
01714   }
01715   free(buf);
01716 }
01717 
01718 
01719 long get_efi_systab_smbios()
01720 {
01721   long result = 0;
01722   vector < string > sysvars;
01723 
01724   if (loadfile("/sys/firmware/efi/systab", sysvars) || loadfile("/proc/efi/systab", sysvars))
01725     for (unsigned int i = 0; i < sysvars.size(); i++)
01726   {
01727     vector < string > variable;
01728 
01729     splitlines(sysvars[i], variable, '=');
01730 
01731     if ((variable[0] == "SMBIOS") && (variable.size() == 2))
01732     {
01733       sscanf(variable[1].c_str(), "%lx", &result);
01734     }
01735   }
01736 
01737   return result;
01738 }
01739 
01740 
01741 bool scan_dmi(hwNode & n)
01742 {
01743   unsigned char buf[20];
01744   int fd = open("/dev/mem",
01745     O_RDONLY);
01746   long fp = get_efi_systab_smbios();
01747   u32 mmoffset = 0;
01748   void *mmp = NULL;
01749   bool efi = true;
01750   u8 smmajver = 0, smminver = 0;
01751   u16 dmimaj = 0, dmimin = 0;
01752   currentcpu = 0;
01753 
01754 #ifdef __hppa__
01755   return false;             // SMBIOS not supported on PA-RISC machines
01756 #endif
01757 
01758   if (sizeof(u8) != 1 || sizeof(u16) != 2 || sizeof(u32) != 4)
01759 // compiler incompatibility
01760     return false;
01761   if (fd == -1)
01762     return false;
01763 
01764   if (fp <= 0)
01765   {
01766     efi = false;
01767     fp = 0xE0000L;                                /* default value for non-EFI capable platforms */
01768   }
01769 
01770   fp -= 16;
01771   while (efi || (fp < 0xFFFE0))
01772   {
01773     fp += 16;
01774     mmoffset = fp % getpagesize();
01775     mmp = mmap(0, mmoffset + 0x20, PROT_READ, MAP_SHARED, fd, fp - mmoffset);
01776     memset(buf, 0, sizeof(buf));
01777     if (mmp != MAP_FAILED)
01778     {
01779       memcpy(buf, (u8 *) mmp + mmoffset, sizeof(buf));
01780       munmap(mmp, mmoffset + 0x20);
01781     }
01782     if (mmp == MAP_FAILED)
01783     {
01784       close(fd);
01785       return false;
01786     }
01787     else if (memcmp(buf, "_SM_", 4) == 0)
01788     {
01789 // SMBIOS
01790       smmajver = buf[6];
01791       smminver = buf[7];
01792     }
01793     else if (smmajver && (memcmp(buf, "_DMI_", 5) == 0) && checksum(buf, 0x0F))
01794     {
01795       u16 num = buf[13] << 8 | buf[12];
01796       u16 len = buf[7] << 8 | buf[6];
01797       u32 base = buf[11] << 24 | buf[10] << 16 | buf[9] << 8 | buf[8];
01798       dmimaj = buf[14] ? buf[14] >> 4 : smmajver;
01799       dmimin = buf[14] ? buf[14] & 0x0F : smminver;
01800       dmi_table(fd, base, len, num, n, dmimaj, dmimin);
01801 
01802       if (efi)
01803         break;                                    // we don't need to search the memory for EFI systems
01804     }
01805   }
01806   close(fd);
01807   if (smmajver != 0)
01808   {
01809     char buffer[20];
01810     snprintf(buffer, sizeof(buffer), "%d.%d", smmajver, smminver);
01811     n.addCapability("smbios-"+string(buffer), "SMBIOS version "+string(buffer));
01812   }
01813   if (dmimaj != 0)
01814   {
01815     char buffer[20];
01816     snprintf(buffer, sizeof(buffer), "%d.%d", dmimaj, dmimin);
01817     n.addCapability("dmi-"+string(buffer), "DMI version "+string(buffer));
01818   }
01819 
01820   return true;
01821 }