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

Generated on Wed Apr 11 16:25:10 2007 for SMBIOS Library by doxygen 1.3.5