SmbiosStrategy.cpp

Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=c:cindent:textwidth=0:
00003  *
00004  * Copyright (C) 2005 Dell Inc.
00005  *  by Michael Brown <Michael_E_Brown@dell.com>
00006  * Licensed under the Open Software License version 2.1
00007  *
00008  * Alternatively, you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published
00010  * by the Free Software Foundation; either version 2 of the License,
00011  * or (at your option) any later version.
00012 
00013  * This program is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016  * See the GNU General Public License for more details.
00017  */
00018 
00019 // compat header should always be first header if including system headers
00020 #define LIBSMBIOS_SOURCE
00021 #include "smbios/compat.h"
00022 
00023 #include <sstream>
00024 #include <string.h>
00025 
00026 #include "smbios/IMemory.h"
00027 #include "SmbiosImpl.h"
00028 
00029 // message.h should be included last.
00030 #include "smbios/message.h"
00031 
00032 using namespace smbiosLowlevel;
00033 using namespace std;
00034 
00035 #if defined(DEBUG_SMBIOS_STRATEGY)
00036 #   define DCOUT(line) do { cout << line; } while(0)
00037 #   define DCERR(line) do { cerr << line; } while(0)
00038 #else
00039 #   define DCOUT(line) do {} while(0)
00040 #   define DCERR(line) do {} while(0)
00041 #endif
00042 
00043 namespace smbios
00044 {
00045 
00046     // validate the smbios table entry point
00047     bool validateDMITableEntryPoint(
00048         const smbiosLowlevel::dmi_table_entry_point *tempTEP,
00049         bool strict,
00050         ParseExceptionImpl &parseException
00051         )
00052     {
00053         // This code checks for the following:
00054         //       entry point structure checksum : As per the specs
00055         //       anchor string : As per the specs
00056         //
00057         bool retval = true;
00058 
00059         u8 checksum = 0;
00060         const u8 *ptr = reinterpret_cast<const u8*>(tempTEP);
00061         // don't overrun tempTEP if BIOS is buggy... (note sizeof() test here)
00062         //      added especially to deal with buggy Intel BIOS.
00063         for( unsigned int i = 0; i < sizeof(*tempTEP); ++i )
00064         {
00065             // stupid stuff to avoid MVC++ .NET runtime exception check for cast to different size
00066             checksum = (checksum + ptr[i]) & 0xFF;
00067         }
00068 
00069         ostringstream oss;
00070 
00071         DCERR("_DMI_ anchor: " << tempTEP->anchor[0] << tempTEP->anchor[1] << tempTEP->anchor[2] << tempTEP->anchor[3] << tempTEP->anchor[4] << tempTEP->anchor[5] << endl);
00072         if(memcmp(tempTEP->anchor,"_DMI_",5)!=0) // Checking intermediate anchor string
00073         {
00074             oss << _("Intermediate anchor string does not match. anchor string: %(dmi_anchor)s") << endl;
00075             retval = false;  // validation failed
00076         }
00077 
00078         DCERR("_DMI_ checksum: " << (int)checksum << endl);
00079         if(checksum) // Checking entry point structure checksum
00080         {
00081             oss << _("Checksum check for table entry point should be zero. checksum: %(dmi_checksum)i ") << endl;
00082             retval = false;  // validation failed
00083         }
00084 
00085         parseException.setParameter("dmi_anchor", reinterpret_cast<const char *>(tempTEP->anchor));
00086         parseException.setParameter("dmi_checksum", static_cast<int>(checksum));
00087 
00088         return retval;
00089     }
00090 
00091 
00092 
00093 
00094     // validate the smbios table entry point
00095     bool validateSmbiosTableEntryPoint(
00096         const smbiosLowlevel::smbios_table_entry_point *tempTEP,
00097         bool strict,
00098         ParseExceptionImpl &parseException
00099         )
00100     {
00101         // This code checks for the following:
00102         //       entry point structure checksum : As per the specs
00103         //       smbios major version : As per the specs
00104         //       Intermediate anchor string : As per the specs
00105         //
00106         // This code does not check the following:
00107         //      intermediate checksum: the main checksum covers the
00108         //      entire area
00109         //          and should be sufficient, plus there is a
00110         //          possibility for
00111         //          BIOS bugs in this area.
00112         //
00113         //      minor version: according to the spec, this parser should
00114         //      work
00115         //          with any change in minor version. The spec says this
00116         //          parser
00117         //          will break if major version changes, so we check
00118         //          that.
00119         //
00120 
00121         bool retval = true;
00122 
00123         u8 checksum = 0;
00124         const u8 *ptr = reinterpret_cast<const u8*>(tempTEP);
00125         // don't overrun tempTEP if BIOS is buggy... (note sizeof() test here)
00126         //      added especially to deal with buggy Intel BIOS.
00127         for( unsigned int i = 0; (i < static_cast<unsigned int>(tempTEP->eps_length)) && (i < sizeof(*tempTEP)); ++i )
00128         {
00129             // stupid stuff to avoid MVC++ .NET runtime exception check for cast to different size
00130             checksum = (checksum + ptr[i]) & 0xFF;
00131         }
00132 
00133         ostringstream oss;
00134         oss << _("validation of table entry point failed") << endl;
00135 
00136         validateDMITableEntryPoint( &(tempTEP->dmi), strict, parseException );
00137 
00138         DCERR("strict table checking: " << strict << endl);
00139 
00140 
00141         DCERR("_SM_ checksum: " << (int)checksum << endl);
00142 
00143         if(checksum) // Checking entry point structure checksum
00144         {
00145             oss << _("Checksum check for table entry point should be zero. checksum: %(checksum)i ") << endl;
00146             retval = false;  // validation failed
00147         }
00148 
00149         DCERR("major_ver: " << (int)tempTEP->major_ver << endl);
00150         if(tempTEP->major_ver!=0x02)     // Checking smbios major version
00151         {
00152             oss << _("Major version of table entry point should be 2: %(major_version)i") << endl;
00153             retval = false;  // validation failed
00154         }
00155 
00156         // Entry Point Length field is at least 0x1f.
00157         DCERR("eps_length: " << (int)tempTEP->eps_length << endl);
00158         if(tempTEP->eps_length < 0x0f)
00159         {
00160             oss << _("Entry Point Length field is at least 0x1f : %(eps_length)i") << endl;
00161             retval = false;  // validation failed
00162         }
00163 
00164         parseException.setParameter("checksum", static_cast<int>(checksum));
00165         parseException.setParameter("major_version", static_cast<int>(tempTEP->major_ver));
00166         parseException.setParameter("eps_length", static_cast<int>(tempTEP->eps_length));
00167         parseException.setMessageString(oss.str());
00168 
00169         return retval;
00170     }
00171 
00172 
00173 
00174 
00175 
00176     bool SmbiosMemoryStrategy::getSmbiosTable(const u8 **smbiosBuffer, smbiosLowlevel::smbios_table_entry_point *table_header, bool strict)
00177     {
00178         bool ret = false;
00179         try
00180         {
00181             // allocates no mem
00182             DCERR("trying SmbiosMemoryStrategy" << endl);
00183             getSmbiosTableHeader(table_header, strict);
00184 
00185             // allocates mem, but frees on exception
00186             getSmbiosTableBuf(smbiosBuffer, *table_header);
00187             if(smbiosBuffer)
00188                     ret = true;
00189         }
00190         catch(const exception &e)
00191         {
00192             UNREFERENCED_PARAMETER(e); // avoid unused var warning when !DEBUG
00193             DCERR("got Exception: " << e.what() << endl);
00194         }
00195 
00196         DCERR("  ret for SmbiosMemoryStrategy is: " << ret << endl);
00197         return ret;
00198     }
00199 
00200     void SmbiosMemoryStrategy::getSmbiosTableBuf(const u8 **smbiosBuffer, smbiosLowlevel::smbios_table_entry_point table_header)
00201     {
00202         memory::IMemory *mem = memory::MemoryFactory::getFactory()->getSingleton();
00203 
00204         // new throws exception, no need to test.
00205         u8 *newSmbiosBuffer = new u8[table_header.dmi.table_length];
00206         try
00207         {
00208             mem->fillBuffer( newSmbiosBuffer, table_header.dmi.table_address, table_header.dmi.table_length );
00209 
00210             //delete old one, if necessary
00211             if( 0 != *smbiosBuffer )
00212             {
00213                 memset (const_cast<u8 *>(*smbiosBuffer), 0, sizeof (**smbiosBuffer));
00214                 delete [] const_cast<u8 *>(*smbiosBuffer);
00215                 *smbiosBuffer = 0;
00216             }
00217         }
00218         catch(...)
00219         {
00220             delete [] newSmbiosBuffer;
00221             newSmbiosBuffer = 0;
00222             throw;
00223         }
00224 
00225         *smbiosBuffer = reinterpret_cast<const u8 *>(newSmbiosBuffer);
00226     }
00227 
00228     // allocates no memory, constructs no objects.
00229     // can raise an exception
00230     void SmbiosMemoryStrategy::getSmbiosTableHeader(smbiosLowlevel::smbios_table_entry_point *table_header, bool strict)
00231     {
00232         memory::IMemory *mem = memory::MemoryFactory::getFactory()->getSingleton();
00233 
00234         unsigned long fp = E_BLOCK_START;
00235         if( offset )
00236             fp = offset;
00237 
00238         ParseExceptionImpl parseException;
00239         if( offset )
00240         {
00241             DCERR("SmbiosMemoryStrategy::getSmbiosTableHeader() using hardcoded offset: " << hex << offset << endl);
00242             parseException.setMessageString(_("SMBIOS Header not found at offset: %(offsetValue)i"));
00243             parseException.setParameter("offsetValue",offset);
00244         }
00245         else
00246         {
00247             DCERR("SmbiosMemoryStrategy::getSmbiosTableHeader() Memory scan for smbios table." << endl);
00248             parseException.setMessageString(_("SMBIOS Header not found in search."));
00249         }
00250 
00251         // tell the memory subsystem that it can optimize here and 
00252         // keep memory open while we scan rather than open/close/open/close/... 
00253         // for each fillBuffer() call
00254         // 
00255         // this would be safer if we used spiffy c++ raii technique here
00256         mem->decReopenHint();
00257 
00258         smbios_table_entry_point tempTEP;
00259         memset(&tempTEP, 0, sizeof(tempTEP));
00260         while ( (fp + sizeof(tempTEP)) < F_BLOCK_END)
00261         {
00262             mem->fillBuffer(
00263                 reinterpret_cast<u8 *>(&tempTEP),
00264                 fp,
00265                 sizeof(tempTEP)
00266             );
00267 
00268             // search for promising looking headers
00269             // first, look for old-style DMI header
00270             if (memcmp (&tempTEP, "_DMI_", 5) == 0)
00271             {
00272                 DCERR("Found _DMI_ anchor. Trying to parse legacy DMI structure." << endl);
00273                 dmi_table_entry_point *dmiTEP = reinterpret_cast<dmi_table_entry_point *>(&tempTEP);
00274                 memmove(&(tempTEP.dmi), &dmiTEP, sizeof(dmi_table_entry_point));
00275                 // fake the rest of the smbios table entry point...
00276                 tempTEP.major_ver=2;
00277                 tempTEP.minor_ver=0;
00278                 if(validateDMITableEntryPoint(dmiTEP, strict, parseException))
00279                 {
00280                     DCERR("Found valid _DMI_ entry point at offset: " << fp << endl);
00281                     break;
00282                 }
00283             }
00284 
00285             // then, look for new-style smbios header. This will always
00286             // occur before _DMI_ in memory
00287             if (offset || (memcmp (&tempTEP, "_SM_", 4) == 0))
00288             {
00289                 // if we are passed a hardcoded offset (EFI?), it is possible
00290                 // that machine doesnt have _SM_ anchor, but still has valid
00291                 // table. Just try validating the table and skip _SM_ check.
00292                 DCERR("Found _SM_ anchor or using hardcoded offset. Trying to parse Smbios Entry Point." << endl);
00293                 if(validateSmbiosTableEntryPoint(&tempTEP, strict, parseException))
00294                 {
00295                     DCERR("Found valid _SM_ entry point at offset: " << fp << endl);
00296                     break;
00297                 }
00298             }
00299 
00300             // previous if() would have broken out if we have a valid
00301             // table header. if offset is set, then we are not supposed
00302             // to be scanning through memory. We didn't find a table,
00303             // so there is nothing to do but raise an exception.
00304             if (offset)
00305             {
00306                 // dont need memory optimization anymore
00307                 mem->incReopenHint();
00308                 throw parseException; // previously set up.
00309             }
00310 
00311             fp += 16;
00312         }
00313 
00314         // dont need memory optimization anymore
00315         mem->incReopenHint();
00316 
00317         // bad stuff happened if we got to here and fp > 0xFFFFFL
00318         if ((fp + sizeof(tempTEP)) >= F_BLOCK_END)
00319             throw parseException; // previously set up.
00320 
00321         // found it. set offset for future reference (no need to search.)
00322         offset = fp;
00323         memcpy( const_cast<smbios_table_entry_point *>(table_header), &tempTEP, sizeof(*table_header) );
00324     }
00325 }

Generated on Tue Feb 26 14:51:55 2008 for SMBIOS Library by  doxygen 1.4.7