Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

RbuHdr.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 #include "smbios/compat.h"
00021 
00022 #include <errno.h>
00023 #include <string.h>  // strerror()
00024 #include <iostream>
00025 #include <sstream>
00026 #include <iomanip>
00027 
00028 #include "RbuImpl.h"
00029 #include "smbios/IToken.h"
00030 #include "smbios/SystemInfo.h"
00031 
00032 // always include last if included.
00033 #include "smbios/message.h"  // not needed outside of this lib. (mainly for gettext i18n)
00034 
00035 using namespace std;
00036 
00037 namespace rbu
00038 {
00039 
00040     RbuFactory::~RbuFactory() throw() {}
00041     RbuFactory::RbuFactory() {}
00042 
00043     RbuFactory *RbuFactory::getFactory()
00044     {
00045         // reinterpret_cast<...>(0) to ensure template parameter is correct
00046         // this is a workaround for VC6 which cannot use explicit member template
00047         // funciton initialization.
00048         return RbuFactoryImpl::getFactory(reinterpret_cast<RbuFactoryImpl *>(0));
00049     }
00050 
00051     RbuFactoryImpl::~RbuFactoryImpl() throw() { }
00052     RbuFactoryImpl::RbuFactoryImpl() { }
00053     IRbuHdr *RbuFactoryImpl::makeNew(std::string filename)
00054     {
00055         return new RbuHdr( filename );
00056     }
00057 
00058     IRbuHdr::IRbuHdr() {}
00059     IRbuHdr::~IRbuHdr() {}
00060 
00061 
00062     RbuHdr::RbuHdr( string filename ) : hdrFh(fopen(filename.c_str(), "rb"))
00063     {
00064         if(!hdrFh)
00065         {
00066             string errmsg = strerror(errno);
00067             throw HdrFileIOErrorImpl(errmsg);
00068         }
00069 
00070         memset(&header, 0, sizeof(header));
00071         size_t bytesRead = fread(&header, 1, sizeof(header), hdrFh);  // short read handled
00072         if (bytesRead != sizeof(header))
00073         {
00074             fclose(hdrFh);
00075             hdrFh=0;
00076             throw InvalidHdrFileImpl("Couldnt read full header.");
00077         }
00078         fseek(hdrFh, 0, 0);
00079         if (
00080                 header.headerId[0] == '$' &&
00081                 header.headerId[1] == 'R' &&
00082                 header.headerId[2] == 'B' &&
00083                 header.headerId[3] == 'U'
00084            )
00085         {
00086         }
00087         else 
00088         {
00089             fclose(hdrFh);
00090             hdrFh=0;
00091             throw InvalidHdrFileImpl("Did not pass header $RBU check.");
00092         }
00093 
00094         // initialize system id list
00095         memset(sysIdList, 0, sizeof(sysIdList));
00096         for( unsigned int i=0; i < (sizeof(header.systemIdList)/sizeof(header.systemIdList[0])); ++i)
00097         {
00098             if(i >= static_cast<unsigned int>(NUM_SYS_ID_IN_HDR)) break;  // safety... 
00099 
00100             // bits 8:10 are hw rev id, extract them and paste the rest together
00101             u32 val = header.systemIdList[i];
00102             u32 id = (val & 0xFF) | ((val & 0xF800) >> 3);
00103 
00104             if(!id) break;
00105 
00106             sysIdList[i] = id;
00107         }
00108     }
00109 
00110     RbuHdr::~RbuHdr() 
00111     {
00112         if(hdrFh)
00113             fclose(hdrFh);
00114     }
00115 
00116     string RbuHdr::getBiosVersion() const 
00117     {
00118         string ver("");
00119         if( header.headerMajorVer < 2 )
00120         {
00121             if( isalnum(header.biosVersion[0]) )
00122                 ver = ver + header.biosVersion[0];
00123     
00124             if( isalnum(header.biosVersion[1]) )
00125                 ver = ver + header.biosVersion[1];
00126     
00127             if( isalnum(header.biosVersion[2]) )
00128                 ver = ver + header.biosVersion[2];
00129         } 
00130         else 
00131         {
00132             std::ostringstream rep;
00133             rep << static_cast<int>(header.biosVersion[0]) << "."
00134                 << static_cast<int>(header.biosVersion[1]) << "."
00135                 << static_cast<int>(header.biosVersion[2]);
00136             ver = rep.str();
00137         }
00138         return ver;
00139     }
00140 
00141     void RbuHdr::getHdrVersion(unsigned int &major, unsigned int &minor) const 
00142     { 
00143         major = header.headerMajorVer;
00144         minor = header.headerMinorVer;
00145     }
00146 
00147     const u32 * RbuHdr::getSystemIdList() const {return sysIdList;}
00148 
00149     
00150     void RbuHdr::doUpdate() const {}
00151 
00152     bool checkSystemId(const IRbuHdr &hdr, u16 sysId )
00153     {
00154         const u32 *idList = hdr.getSystemIdList();
00155         for (const u32 *ptr = idList; *ptr; ++ptr)
00156             if( *ptr == sysId )
00157                 return true;
00158 
00159         return false;
00160     }
00161 
00162     FILE *RbuHdr::getFh() const 
00163     { 
00164         return hdrFh;
00165     }
00166 
00167     ostream & operator << (ostream & cout, const IRbuHdr & hdr)
00168     {
00169         return hdr.streamify (cout);
00170     }
00171 
00172     ostream & RbuHdr::streamify( ostream &cout ) const 
00173     {
00174         std::ios::fmtflags old_opts = cout.flags ();
00175         cout << "HeaderId : " 
00176             << header.headerId[0]
00177             << header.headerId[1]
00178             << header.headerId[2]
00179             << header.headerId[3] << endl;
00180 
00181         cout << "Header Length: " << static_cast<int>(header.headerLength) << endl;
00182         cout << "Header Major Ver: " << static_cast<int>(header.headerMajorVer) << endl;
00183         cout << "Header Minor Ver: " << static_cast<int>(header.headerMinorVer) << endl;
00184         cout << "Num Systems: " << static_cast<int>(header.numSystems) << endl;
00185 
00186         cout << "Version: " << getBiosVersion() << endl; 
00187 
00188         char quickCheck[41] = {0};
00189         strncpy(quickCheck, header.quickCheck, 40);
00190         cout << "Quick Check: " << quickCheck << endl;
00191 
00192         cout << "System ID List:" << hex;
00193 
00194         for (const u32 *ptr = sysIdList; *ptr; ++ptr)
00195             cout << " 0x" << setfill ('0') << setw (4) << *ptr;
00196 
00197         cout << endl << dec;
00198         cout.flags (old_opts);
00199 
00200         return cout;
00201     }
00202 
00203     // Helper functions
00204     static string stringToLower(string in)
00205     {
00206         for(unsigned int i=0;i<in.length();i++)
00207             in[i] = tolower(in[i]);
00208 
00209         return in;
00210     }
00211 
00212     static int compareSamePrefixOldBiosVersion(std::string ver1, std::string ver2)
00213     {
00214         if(ver1 > ver2)
00215             return -1;
00216 
00217         if(ver1 < ver2)
00218             return 1;
00219 
00220         // should _NEVER_ get here.
00221         return 0;
00222     }
00223 
00224     static int compareOldBiosVersion(std::string ver1, std::string ver2)
00225     {
00226         if (ver1[0] == ver2[0])
00227             return compareSamePrefixOldBiosVersion(ver1, ver2);
00228 
00229         if (tolower(ver1[0]) == 'a')
00230             return -1;
00231 
00232         if (tolower(ver2[0]) == 'a')
00233             return 1;
00234 
00235         if (tolower(ver1[0]) == 'x')
00236             return -1;
00237 
00238         if (tolower(ver2[0]) == 'x')
00239             return 1;
00240 
00241         if (tolower(ver1[0]) == 'p')
00242             return -1;
00243 
00244         if (tolower(ver2[0]) == 'p')
00245             return 1;
00246 
00247         if (ver1[0] > ver2[0])
00248             return -1;
00249 
00250         return 1;
00251     }
00252 
00253     // should be static, but we want to test this in unit test suite. NOT PART OF PUBLIC API
00254     void splitNewVersion(std::string ver, unsigned int &maj, unsigned int &min, unsigned int &ext)
00255     {
00256         unsigned int verSplit[3] = {0,};
00257 
00258         DCOUT("splitNewVersion( \""<< ver <<"\" )" << endl);
00259 
00260         size_t start=0, end=0;
00261         for(int i=0; i<3; i++)
00262         {
00263             string verPart = "";
00264             end = ver.find('.', start);
00265             verPart.append(ver, start, end - start);
00266 
00267             verSplit[i] = strtoul(verPart.c_str(), 0, 10);
00268             DCOUT("Start(" << start << ") End(" << end << ") verPart(\"" << verPart << "\") verSplit[" << i << "](" << verSplit[i] << ")" << endl);
00269 
00270             if( end == string::npos )
00271                 break;
00272 
00273             start = end + 1;
00274         }
00275 
00276         maj = verSplit[0];
00277         min = verSplit[1];
00278         ext = verSplit[2];
00279 
00280         DCOUT("Return: (" << maj << ", " << min << ", " << ext << ")" << endl);
00281     }
00282     
00283 
00284     static int compareNewBiosVersion(std::string ver1, std::string ver2)
00285     {
00286         unsigned int maj1, min1, ext1;
00287         unsigned int maj2, min2, ext2;
00288         splitNewVersion( ver1, maj1, min1, ext1 );
00289         splitNewVersion( ver2, maj2, min2, ext2 );
00290 
00291         // check for 90-99 major. Should never win against non-90-99 ver:
00292         const unsigned int SPECIAL_VER_START = 90;
00293         if (maj1 >= SPECIAL_VER_START && maj2 < SPECIAL_VER_START)
00294             return 1;
00295         if (maj1 < SPECIAL_VER_START && maj2 >= SPECIAL_VER_START)
00296             return -1;
00297 
00298         if (maj1 > maj2)
00299             return -1;
00300         if (maj1 < maj2)
00301             return  1;
00302  
00303         if (min1 > min2)
00304             return -1;
00305         if (min1 < min2)
00306             return  1;
00307  
00308         if (ext1 > ext2)
00309             return -1;
00310         if (ext1 < ext2)
00311             return  1;
00312         
00313         // should never get here as == versions should already be handled.
00314         return 0;
00315     }
00316 
00317 
00318     int compareBiosVersion(std::string ver1, std::string ver2)
00319     {
00320         ver1 = stringToLower(ver1);
00321         ver2 = stringToLower(ver2);
00322 
00323         // same string
00324         if(ver1 == ver2)
00325             return 0;
00326 
00327         // both old style
00328         if ( isalpha(ver1[0]) && isalpha(ver2[0]) )
00329             return compareOldBiosVersion(ver1, ver2);
00330 
00331         // one new, one old, new wins
00332         if ( ! isalpha(ver1[0]) && isalpha(ver2[0]) )
00333             return -1;
00334 
00335         // one new, one old, new wins
00336         if ( isalpha(ver1[0]) && !isalpha(ver2[0]) )
00337             return 1;
00338 
00339         if ( ! isalpha(ver1[0]) && !isalpha(ver2[0]) )
00340             return compareNewBiosVersion(ver1, ver2);
00341 
00342         // cannot get here...
00343         return 0;
00344     }
00345 
00346 
00347     // private functions
00348 
00349     packet_type getSupportedPacketType(void)
00350     {
00351         packet_type pt = pt_mono;
00352         try
00353         {
00354             smbios::SmbiosFactory *smbiosFactory = smbios::SmbiosFactory::getFactory();
00355             const smbios::ISmbiosTable *table = smbiosFactory->getSingleton();
00356             const smbios::ISmbiosItem &rbuStructure = *((*table)[RBU_SMBIOS_STRUCT]);
00357     
00358             u8 byte = getU8_FromItem(rbuStructure, 0x0F); // Characteristics field
00359             if( byte & 0x01 ) 
00360                 pt = pt_packet;
00361         }
00362         catch(const smbios::DataOutOfBounds &)
00363         {
00364             // only happens when old-style struct present w/o characteristics field
00365             // this means only mono supported.
00366         }
00367         return pt;
00368     }
00369         
00370     void activateRbuToken()
00371     {
00372         smbios::TokenTableFactory *ttFactory = smbios::TokenTableFactory::getFactory() ;
00373         smbios::ITokenTable *tokenTable = ttFactory->getSingleton();
00374         (*tokenTable)[ RBU_ACTIVATE ]->activate();
00375     }
00376     
00377     void cancelRbuToken()
00378     {
00379         smbios::TokenTableFactory *ttFactory = smbios::TokenTableFactory::getFactory() ;
00380         smbios::ITokenTable *tokenTable = ttFactory->getSingleton();
00381         (*tokenTable)[ RBU_CANCEL ]->activate();
00382     }
00383 
00384     void checksumPacket(rbu_packet *pkt, size_t size)
00385     {
00386         u16 *buf = reinterpret_cast<u16 *>(pkt);
00387         pkt->pktChksum = 0;
00388     
00389         u16 csum = 0;
00390         for(size_t i=0; i<size/2; ++i)
00391             csum = csum + buf[i];
00392     
00393         pkt->pktChksum = -csum;
00394     }
00395 
00396     void createPacket(char *buffer, size_t bufSize, size_t imageSize)
00397     {
00398         // set up packet
00399         rbu_packet *pkt = reinterpret_cast<rbu_packet *>(buffer);
00400     
00401         pkt->pktId = 0x4B505224;  //2452504B;   // must be '$RPK'
00402         pkt->pktSize = bufSize / 1024;    // size of packet in KB
00403         pkt->reserved1 = 0;  //
00404         pkt->hdrSize = 2;    // size of packet header in paragraphs (16 byte chunks)
00405         int datasize = bufSize - (16 * pkt->hdrSize);
00406 
00407         pkt->reserved2 = 0;  //
00408         pkt->pktSetId = 0x12345678;   // unique id for packet set, can be anything
00409         pkt->pktNum = 0;     // sequential pkt number (only thing that changes)
00410         pkt->totPkts = (imageSize/datasize) + ((imageSize % datasize) ? 1:0) + 1;// total number of packets
00411         pkt->pktVer = 1;     // version == 1 for now
00412         pkt->pktChksum = 0;  // sum all bytes in pkt must be zero
00413     
00414         checksumPacket(pkt, bufSize);
00415     }
00416 }

Generated on Tue Feb 26 14:39:00 2008 for SMBIOS Library by  doxygen 1.3.9.1