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

Generated on Sat Apr 21 11:36:09 2007 for SMBIOS Library by  doxygen 1.5.2