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

Rbu_Linux.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 <iostream>
00023 #include <sstream>
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <time.h>
00027 #include <string.h>
00028 #include <errno.h>
00029 
00030 #include <sys/types.h>
00031 #include <unistd.h>
00032 
00033 #include "RbuImpl.h"
00034 
00035 // always include last if included.
00036 #include "smbios/message.h"  // not needed outside of this lib. (mainly for gettext i18n)
00037 
00038 using namespace std;
00039 
00040 namespace rbu
00041 {
00042 const char *rbu_v0_type_file = "/proc/dell/rbu/image_type";
00043 const char *rbu_v0_data_file = "/proc/dell/rbu/rbudata";
00044 const char *rbu_v0_size_file = "/proc/dell/rbu/rbudatasize";
00045     
00046 const char *rbu_v1_mono_data_file = "/sys/firmware/rbu/rbudata";
00047 const char *rbu_v1_mono_size_file = "/sys/firmware/rbu/rbudatasize";
00048 const char *rbu_v1_pkt_data_file = "/sys/firmware/rbu/packetdata";
00049 const char *rbu_v1_pkt_size_file = "/sys/firmware/rbu/packetdatasize";
00050 
00051 const char *rbu_v2_fw_data_file = "/sys/class/firmware/dell_rbu/data";
00052 const char *rbu_v2_fw_load_file = "/sys/class/firmware/dell_rbu/loading";
00053 const char *rbu_v2_drv_data_file = "";
00054 const char *rbu_v2_img_type_file = "/sys/devices/platform/dell_rbu/image_type";
00055 const char *rbu_v2_pkt_size_file = "/sys/devices/platform/dell_rbu/packet_size";
00056 
00057 const int RBU_PACKET_SIZE = 4096;
00058 
00059     driver_type getDriverType()
00060     {
00061         if (!access(rbu_v1_mono_data_file, F_OK))
00062             return rbu_linux_v1;
00063         else if (!access(rbu_v2_img_type_file, F_OK))
00064             return rbu_linux_v2;
00065         else if (!access(rbu_v0_data_file, F_OK))
00066             return rbu_linux_v0;
00067         else
00068             return rbu_unsupported;
00069     }
00070 
00071     static FILE * writePacket(const char *fn, const char *buffer, size_t bufSize, bool openclose)
00072     {
00073         static FILE *data_fh = 0;
00074         if(!data_fh)
00075             data_fh = fopen(fn, "wb");
00076 
00077         if (!data_fh)
00078             throw RbuDriverIOErrorImpl(strerror(errno));
00079     
00080         try
00081         {
00082             fwrite(buffer, 1, bufSize, data_fh);
00083             if (ferror(data_fh))
00084                 throw RbuDriverIOErrorImpl(strerror(errno));
00085     
00086             if(openclose)
00087             {
00088                 fclose(data_fh);
00089                 data_fh = 0;
00090             }
00091         }
00092         catch(...)
00093         {
00094             fclose(data_fh);
00095             throw;
00096         }
00097 
00098         fflush(NULL);
00099         return data_fh;
00100     }
00101 
00102     static void pktUpdateLoop(FILE *hdr_fh, const char *packetFilename, char *buffer, size_t bufSize, bool openclose)
00103     {
00104         cout << "Writing RBU data (" << bufSize << "bytes/dot): ";
00105 
00106         fseek(hdr_fh, 0, SEEK_END);
00107         size_t totalSizeBytes = ftell(hdr_fh);
00108 
00109         fseek(hdr_fh, 0, 0);
00110         // set up packet
00111         rbu_packet *pkt = reinterpret_cast<rbu_packet *>(buffer);
00112         createPacket(buffer, bufSize, totalSizeBytes);
00113     
00114         // TODO: password support.
00115         FILE *data_fh = writePacket(packetFilename, buffer, bufSize, openclose);
00116         cout << ".";
00117     
00118         while(!feof(hdr_fh))
00119         {
00120             ++pkt->pktNum;
00121             memset(&(pkt->pktData), 0, bufSize - sizeof(rbu_packet));
00122             fread(&(pkt->pktData), 1, bufSize - sizeof(rbu_packet), hdr_fh);
00123             if (ferror(hdr_fh))
00124                 throw HdrFileIOErrorImpl(strerror(errno));
00125     
00126             checksumPacket(pkt, bufSize);
00127             writePacket(packetFilename, buffer, bufSize, openclose);
00128     
00129             cout << ".";
00130         }
00131         cout << endl;
00132     
00133         // close data file if it is still open
00134         if(data_fh)
00135         {
00136             fflush(NULL);
00137             fclose(data_fh);
00138         }
00139         cout << "Done writing packet data." << endl;
00140     }
00141 
00142     static void monoUpdateLoop(FILE *hdr_fh, FILE *data_fh)
00143     {
00144         fseek(hdr_fh, 0, 0);
00145         const int bufSize = 4096;
00146         char *buffer[bufSize];
00147         cout << "Writing RBU data (" << bufSize << "bytes/dot): ";
00148         while(!feof(hdr_fh))
00149         {
00150             memset(buffer, 0, bufSize);
00151             size_t readSz = fread(buffer, 1, bufSize, hdr_fh);
00152             if (ferror(hdr_fh))
00153                 throw HdrFileIOErrorImpl(strerror(errno));
00154     
00155             fwrite(buffer, 1, readSz, data_fh);
00156             if (ferror(data_fh))
00157                 throw RbuDriverIOErrorImpl(strerror(errno));
00158             cout << "." << flush;
00159         }
00160         cout << endl;
00161     }
00162 
00163 
00164 /****************************************
00165    RBU Linux v1 functions (older driver)
00166 ****************************************/
00167     static void setSize(const char *fn, size_t sz)
00168     {
00169         FILE *size_fh = fopen(fn, "wb");
00170         if (!size_fh)
00171             throw RbuDriverIOErrorImpl(strerror(errno));
00172 
00173         ostringstream ost("");
00174         ost << sz;
00175         cout << "writing (" << sz << ") to file: " << fn << endl;
00176         fwrite(ost.str().c_str(), 1, ost.str().length(), size_fh);
00177         if (ferror(size_fh))
00178             throw RbuDriverIOErrorImpl(strerror(errno));
00179         fclose(size_fh);
00180         size_fh = 0;
00181     }
00182 
00183     static void doPacketUpdate_v1(FILE *hdr_fh) 
00184     {
00185         const size_t bufSize = RBU_PACKET_SIZE;
00186         char buffer[bufSize] = {0};
00187     
00188         // set packet size, reset mono handler
00189         setSize(rbu_v1_mono_size_file, 0);
00190         setSize(rbu_v1_pkt_size_file, bufSize);
00191 
00192         pktUpdateLoop(hdr_fh, rbu_v1_pkt_data_file, buffer, bufSize, true);
00193     }
00194     
00195     static void doMonoUpdate_v1(FILE *hdr_fh) 
00196     {
00197         cout << "Prep driver for data load." << endl;
00198     
00199         FILE *data_fh = fopen(rbu_v1_mono_data_file, "wb");
00200         if (!data_fh)
00201             throw RbuDriverIOErrorImpl(strerror(errno));
00202     
00203         fseek(hdr_fh, 0, SEEK_END);
00204         size_t totalSizeBytes = ftell(hdr_fh);
00205 
00206         // set mono data size, reset pkt handler
00207         setSize(rbu_v1_pkt_size_file, 0);
00208         setSize(rbu_v1_mono_size_file, totalSizeBytes);
00209 
00210         monoUpdateLoop(hdr_fh, data_fh);
00211         
00212         fclose(data_fh);
00213         data_fh = 0;
00214         fflush(NULL);
00215     
00216         cout << "BIOS staging is complete." << endl;
00217     }
00218 
00219 /****************************************
00220    RBU Linux v0 functions (2.4)
00221 ****************************************/
00222 
00223     static void doPacketUpdate_v0(FILE *hdr_fh) 
00224     {
00225         const size_t bufSize = RBU_PACKET_SIZE;
00226         char buffer[bufSize] = {0};
00227     
00228         // set packet size, reset mono handler
00229         setSize(rbu_v0_size_file, 0);
00230         setSize(rbu_v0_size_file, bufSize);
00231 
00232         pktUpdateLoop(hdr_fh, rbu_v0_data_file, buffer, bufSize, false);
00233     }
00234 
00235     static void doMonoUpdate_v0(FILE *hdr_fh) 
00236     {
00237         cout << "Prep driver for data load." << endl;
00238     
00239         FILE *data_fh = fopen(rbu_v0_data_file, "wb");
00240         if (!data_fh)
00241             throw RbuDriverIOErrorImpl(strerror(errno));
00242     
00243         fseek(hdr_fh, 0, SEEK_END);
00244         size_t totalSizeBytes = ftell(hdr_fh);
00245 
00246         // set mono data size, reset pkt handler
00247         setSize(rbu_v0_size_file, 0);
00248         setSize(rbu_v0_size_file, totalSizeBytes);
00249 
00250         monoUpdateLoop(hdr_fh, data_fh);
00251         
00252         fclose(data_fh);
00253         data_fh = 0;
00254         fflush(NULL);
00255     
00256         cout << "BIOS staging is complete." << endl;
00257     }
00258 
00259 
00260 
00261 /****************************************
00262    RBU Linux v2 functions (newer, included in 2.6.14+)
00263 ****************************************/
00264 
00265     static void setPacketType(packet_type type, const char *fn=rbu_v2_img_type_file)
00266     {
00267         FILE *type_fh = 0;
00268         type_fh = fopen(fn, "wb");
00269         if (!type_fh)
00270             throw RbuDriverIOErrorImpl(strerror(errno));
00271     
00272         switch(type)
00273         {
00274         case pt_mono:
00275             fwrite("mono\0", 1, 5, type_fh);
00276             break;
00277         case pt_packet:
00278             fwrite("packet\0", 1, 7, type_fh);
00279             break;
00280         case pt_any:  /*fall thru*/
00281         case pt_init:  /*fall thru*/
00282         default:
00283             // not really a packet type, but causes driver to free its memory
00284             fwrite("init\0", 1, 7, type_fh);
00285             break;
00286         }
00287     
00288         if (ferror(type_fh))
00289             throw RbuDriverIOErrorImpl(strerror(errno));
00290 
00291         fclose(type_fh);
00292     }        // Step 5: set rbu cmos token
00293     
00294     
00295     static void waitForFile(const char *fn, time_t wait)
00296     {
00297         time_t start = time(NULL);
00298         while( access(fn, F_OK) && (time(NULL) - start < wait))
00299             /*nothing*/;
00300     }
00301     
00302     static void setLoadValue(char val)
00303     {
00304         FILE *load_fh = 0;
00305     
00306         waitForFile(rbu_v2_fw_load_file, 10);
00307     
00308         load_fh = fopen(rbu_v2_fw_load_file, "wb");
00309         if (!load_fh)
00310             throw RbuDriverIOErrorImpl(strerror(errno));
00311     
00312         fwrite(&val, 1, 1, load_fh);
00313         if (ferror(load_fh))
00314             throw RbuDriverIOErrorImpl(strerror(errno));
00315         fclose(load_fh);
00316         fflush(NULL);
00317     }
00318     
00319     static void doPacketUpdate_v2(FILE *hdr_fh) 
00320     {
00321         const size_t bufSize = RBU_PACKET_SIZE;
00322         char buffer[bufSize] = {0};
00323 
00324         setSize(rbu_v2_pkt_size_file, bufSize);
00325         setLoadValue('1');
00326         pktUpdateLoop(hdr_fh, rbu_v2_fw_data_file, buffer, bufSize, false);
00327         setLoadValue('0');
00328     }
00329     
00330     static void doMonoUpdate_v2(FILE *hdr_fh) 
00331     {
00332         cout << "Prep driver for data load." << endl;
00333         setLoadValue('1');
00334     
00335         FILE *data_fh = fopen(rbu_v2_fw_data_file, "wb");
00336         if (!data_fh)
00337             throw RbuDriverIOErrorImpl(strerror(errno));
00338     
00339         monoUpdateLoop(hdr_fh, data_fh);
00340        
00341         fclose(data_fh);
00342         data_fh = 0;
00343         fflush(NULL);
00344     
00345         cout << "Notify driver data is finished." << endl;
00346         setLoadValue('0');
00347     }
00348 
00349 
00350 
00351 /*****************************************************************************
00352 ******************************************************************************
00353 
00354 main entry points for this module.
00355 
00356 ******************************************************************************
00357 *****************************************************************************/
00358     
00359     void dellBiosUpdate(const IRbuHdr &hdr, packet_type force_type)
00360     {
00361         FILE *hdr_fh = hdr.getFh();
00362         fseek(hdr_fh, 0, 0);
00363 
00364         bool forced=false;
00365         
00366         // TODO: verify that it is a HDR file
00367         // TODO: checksum HDR file
00368 
00369         packet_type supported_pt = getSupportedPacketType();
00370         cout << "Supported RBU type for this system: (MONOLITHIC"
00371             << (supported_pt == pt_packet ? ", PACKET"   : "")
00372             << ")"
00373             << endl;
00374     
00375         if( force_type != pt_any )
00376         {
00377             supported_pt = force_type;
00378             forced = true;
00379         }
00380     
00381         driver_type dt = getDriverType();
00382 
00383         if (dt == rbu_linux_v2)
00384         {
00385             // initialize RBU driver.
00386             cout << "Using RBU v2 driver. Initializing Driver. " << endl;
00387             setPacketType(pt_init, rbu_v2_img_type_file);
00388         
00389             // set packet/mono type
00390             cout << "Setting RBU type in v2 driver to: " 
00391                 << (supported_pt == pt_packet ? "PACKET" : "")
00392                 << (supported_pt == pt_mono   ? "MONOLITHIC" : "")
00393                 << (forced ? " (FORCED) ": "" )
00394                 << endl;
00395             setPacketType(supported_pt, rbu_v2_img_type_file);
00396         
00397             switch(supported_pt)
00398             {
00399             case pt_packet:
00400                 doPacketUpdate_v2(hdr_fh);
00401                 break;
00402             case pt_mono:
00403                 doMonoUpdate_v2(hdr_fh);
00404                 break;
00405             default:
00406                 break;
00407             }
00408         } 
00409         else if(dt == rbu_linux_v1)
00410         {
00411             cout << "Using RBU v1 method: " 
00412                 << (supported_pt == pt_packet ? "PACKET" : "")
00413                 << (supported_pt == pt_mono   ? "MONOLITHIC" : "")
00414                 << (forced ? " (FORCED) ": "" )
00415                 << endl;
00416  
00417             switch(supported_pt)
00418             {
00419             case pt_packet:
00420                 doPacketUpdate_v1(hdr_fh);
00421                 break;
00422             case pt_mono:
00423                 doMonoUpdate_v1(hdr_fh);
00424                 break;
00425             default:
00426                 break;
00427             }
00428         }
00429         else if(dt == rbu_linux_v0)
00430         {
00431             cout << "Using RBU v0 driver. Initializing Driver. " << endl;
00432             setPacketType(pt_init, rbu_v0_type_file);
00433 
00434             cout << "Setting RBU type in v0 driver to: "
00435                 << (supported_pt == pt_packet ? "PACKET" : "")
00436                 << (supported_pt == pt_mono   ? "MONOLITHIC" : "")
00437                 << (forced ? " (FORCED) ": "" )
00438                 << endl;
00439             setPacketType(supported_pt, rbu_v0_type_file);
00440 
00441             switch(supported_pt)
00442             {
00443             case pt_packet:
00444                 doPacketUpdate_v0(hdr_fh);
00445                 break;
00446             case pt_mono:
00447                 doMonoUpdate_v0(hdr_fh);
00448                 break;
00449             default:
00450                 break;
00451             }
00452         }
00453         else
00454         {
00455             throw RbuNotSupportedImpl("Could not open Dell RBU driver.");
00456         }
00457     
00458         cout << "Activate CMOS bit to notify BIOS that update is ready on next boot." << endl;
00459         activateRbuToken();
00460     
00461         cout << "Update staged sucessfully. BIOS update will occur on next reboot." << endl;
00462     }
00463     
00464     void cancelDellBiosUpdate()
00465     {
00466         // FOR LOAD CANCEL:
00467         // Step 1: always unset CMOS first
00468         cout << "Cancel BIOS CMOS notification bit." << endl;
00469         cancelRbuToken();
00470 
00471         driver_type dt = getDriverType();
00472         switch(dt)
00473         {
00474         case rbu_linux_v2:
00475             // Step 2: make sure firmware class doesn't think we are loading
00476             cout << "Free kernel driver memory." << endl;
00477             setLoadValue('0');
00478 
00479             // Step 3: tell the dell_rbu driver to free its allocated memory
00480             cout << "Re-initialize driver for next user." << endl;
00481             setPacketType(pt_init, rbu_v2_img_type_file);
00482             break;
00483 
00484         case rbu_linux_v1:
00485             // Step 2: Free monolithic, if present
00486             cout << "Re-initialize driver for next user." << endl;
00487             setSize(rbu_v1_mono_size_file, 0);
00488             setSize(rbu_v1_pkt_size_file, 0);
00489             fflush(NULL);
00490             break;
00491 
00492         case rbu_linux_v0:
00493             // Step 2: Free monolithic, if present
00494             cout << "Re-initialize driver for next user." << endl;
00495             setSize(rbu_v0_size_file, 0);
00496             setPacketType(pt_init, rbu_v0_type_file);
00497             fflush(NULL);
00498             break;
00499 
00500 
00501         default:
00502             cout << "Could not determine RBU driver present, skipping." << endl;
00503             break;
00504         }
00505     }
00506 }
00507 

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