00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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 #include "smbios/IToken.h"
00035 #include "smbios/SystemInfo.h"
00036
00037
00038 #include "smbios/message.h"
00039
00040 using namespace std;
00041
00042 namespace rbu
00043 {
00044 const char *rbu_v1_mono_data_file = "/sys/firmware/rbu/rbudata";
00045 const char *rbu_v1_mono_size_file = "/sys/firmware/rbu/rbudatasize";
00046 const char *rbu_v1_pkt_data_file = "/sys/firmware/rbu/packetdata";
00047 const char *rbu_v1_pkt_size_file = "/sys/firmware/rbu/packetdatasize";
00048
00049 const char *rbu_v2_fw_data_file = "/sys/class/firmware/dell_rbu/data";
00050 const char *rbu_v2_fw_load_file = "/sys/class/firmware/dell_rbu/loading";
00051 const char *rbu_v2_drv_data_file = "";
00052 const char *rbu_v2_img_type_file = "/sys/devices/platform/dell_rbu/image_type";
00053 const char *rbu_v2_pkt_size_file = "/sys/devices/platform/dell_rbu/packet_size";
00054
00055 packet_type getSupportedPacketType(void)
00056 {
00057 packet_type pt = pt_mono;
00058 try
00059 {
00060 smbios::SmbiosFactory *smbiosFactory = smbios::SmbiosFactory::getFactory();
00061 smbios::ISmbiosTable *table = smbiosFactory->getSingleton();
00062 smbios::ISmbiosItem &rbuStructure = *((*table)[RBU_SMBIOS_STRUCT]);
00063
00064 u8 byte = rbuStructure.getU8(0x0F);
00065 if( byte & 0x01 )
00066 pt = pt_packet;
00067 }
00068 catch(const smbios::DataOutOfBounds &)
00069 {
00070
00071
00072 }
00073 return pt;
00074 }
00075
00076 void activateRbuToken()
00077 {
00078 smbios::TokenTableFactory *ttFactory = smbios::TokenTableFactory::getFactory() ;
00079 smbios::ITokenTable *tokenTable = ttFactory->getSingleton();
00080 (*tokenTable)[ RBU_ACTIVATE ]->activate();
00081 }
00082
00083 void cancelRbuToken()
00084 {
00085 smbios::TokenTableFactory *ttFactory = smbios::TokenTableFactory::getFactory() ;
00086 smbios::ITokenTable *tokenTable = ttFactory->getSingleton();
00087 (*tokenTable)[ RBU_CANCEL ]->activate();
00088 }
00089
00090 void checksumPacket(rbu_packet *pkt, size_t size)
00091 {
00092 u16 *buf = reinterpret_cast<u16 *>(pkt);
00093 pkt->pktChksum = 0;
00094
00095 u16 csum = 0;
00096 for(size_t i=0; i<size/2; ++i)
00097 csum = csum + buf[i];
00098
00099 pkt->pktChksum = -csum;
00100 }
00101
00102 driver_type getDriverType()
00103 {
00104 if (!access(rbu_v1_mono_data_file, F_OK))
00105 return rbu_linux_v1;
00106 else if (!access(rbu_v2_fw_data_file, F_OK))
00107 return rbu_linux_v2;
00108 else
00109 return rbu_unsupported;
00110 }
00111
00112 void createPacket(char *buffer, size_t bufSize, size_t imageSize)
00113 {
00114
00115 rbu_packet *pkt = reinterpret_cast<rbu_packet *>(buffer);
00116
00117 pkt->pktId = 0x4B505224;
00118 pkt->pktSize = bufSize / 1024;
00119 pkt->reserved1 = 0;
00120 pkt->hdrSize = 2;
00121 pkt->reserved2 = 0;
00122 pkt->pktSetId = 0x12345678;
00123 pkt->pktNum = 0;
00124 pkt->totPkts = (imageSize/bufSize) + ((imageSize % bufSize) ? 1:0) + 1;
00125 pkt->pktVer = 1;
00126 pkt->pktChksum = 0;
00127
00128 checksumPacket(pkt, bufSize);
00129 }
00130
00131 static void writePacket(const char *fn, const char *buffer, size_t bufSize, bool openclose)
00132 {
00133 static FILE *data_fh = 0;
00134 if(!data_fh)
00135 data_fh = fopen(fn, "wb");
00136
00137 if (!data_fh)
00138 throw RbuDriverIOErrorImpl(strerror(errno));
00139
00140 try
00141 {
00142 fwrite(buffer, 1, bufSize, data_fh);
00143 if (ferror(data_fh))
00144 throw RbuDriverIOErrorImpl(strerror(errno));
00145
00146 if(openclose)
00147 {
00148 fclose(data_fh);
00149 data_fh = 0;
00150 }
00151 }
00152 catch(...)
00153 {
00154 fclose(data_fh);
00155 throw;
00156 }
00157
00158 fflush(NULL);
00159 }
00160
00161 static void pktUpdateLoop(FILE *hdr_fh, const char *packetFilename, char *buffer, size_t bufSize, bool openclose)
00162 {
00163 cout << "Writing RBU data (4096k/dot): ";
00164
00165 fseek(hdr_fh, 0, SEEK_END);
00166 size_t totalSizeBytes = ftell(hdr_fh);
00167
00168 fseek(hdr_fh, 0, 0);
00169
00170 rbu_packet *pkt = reinterpret_cast<rbu_packet *>(buffer);
00171 createPacket(buffer, bufSize, totalSizeBytes);
00172
00173
00174 writePacket(packetFilename, buffer, bufSize, openclose);
00175 cout << ".";
00176
00177 while(!feof(hdr_fh))
00178 {
00179 ++pkt->pktNum;
00180 memset(pkt->pktData, 0, bufSize - sizeof(rbu_packet));
00181 fread(pkt->pktData, 1, bufSize - sizeof(rbu_packet), hdr_fh);
00182 if (ferror(hdr_fh))
00183 throw HdrFileIOErrorImpl(strerror(errno));
00184
00185 checksumPacket(pkt, bufSize);
00186 writePacket(packetFilename, buffer, bufSize, openclose);
00187
00188 cout << ".";
00189 }
00190 cout << endl;
00191
00192 cout << "Done writing packet data." << endl;
00193 }
00194
00195 static void monoUpdateLoop(FILE *hdr_fh, FILE *data_fh)
00196 {
00197 cout << "Writing RBU data (4096k/dot): ";
00198 fseek(hdr_fh, 0, 0);
00199 const int bufSize = 4096;
00200 char *buffer[bufSize];
00201 while(!feof(hdr_fh))
00202 {
00203 memset(buffer, 0, bufSize);
00204 size_t readSz = fread(buffer, 1, bufSize, hdr_fh);
00205 if (ferror(hdr_fh))
00206 throw HdrFileIOErrorImpl(strerror(errno));
00207
00208 fwrite(buffer, 1, readSz, data_fh);
00209 if (ferror(data_fh))
00210 throw RbuDriverIOErrorImpl(strerror(errno));
00211 cout << "." << flush;
00212 }
00213 cout << endl;
00214 }
00215
00216
00217
00218
00219
00220 static void setSize(const char *fn, size_t sz)
00221 {
00222 FILE *size_fh = fopen(fn, "wb");
00223 if (!size_fh)
00224 throw RbuDriverIOErrorImpl(strerror(errno));
00225
00226 ostringstream ost("");
00227 ost << sz;
00228 cout << "writing (" << sz << ") to file: " << fn << endl;
00229 fwrite(ost.str().c_str(), 1, ost.str().length(), size_fh);
00230 if (ferror(size_fh))
00231 throw RbuDriverIOErrorImpl(strerror(errno));
00232 fclose(size_fh);
00233 size_fh = 0;
00234 }
00235
00236 static void doPacketUpdate_v1(FILE *hdr_fh)
00237 {
00238 const size_t bufSize = 4096;
00239 char buffer[bufSize] = {0};
00240
00241
00242 setSize(rbu_v1_mono_size_file, 0);
00243 setSize(rbu_v1_pkt_size_file, bufSize);
00244
00245 pktUpdateLoop(hdr_fh, rbu_v1_pkt_data_file, buffer, bufSize, true);
00246 }
00247
00248 static void doMonoUpdate_v1(FILE *hdr_fh)
00249 {
00250 cout << "Prep driver for data load." << endl;
00251
00252 FILE *data_fh = fopen(rbu_v1_mono_data_file, "wb");
00253 if (!data_fh)
00254 throw RbuDriverIOErrorImpl(strerror(errno));
00255
00256 fseek(hdr_fh, 0, SEEK_END);
00257 size_t totalSizeBytes = ftell(hdr_fh);
00258
00259
00260 setSize(rbu_v1_pkt_size_file, 0);
00261 setSize(rbu_v1_mono_size_file, totalSizeBytes);
00262
00263 monoUpdateLoop(hdr_fh, data_fh);
00264
00265 fclose(data_fh);
00266 data_fh = 0;
00267 fflush(NULL);
00268
00269 cout << "BIOS staging is complete." << endl;
00270 }
00271
00272
00273
00274
00275
00276
00277 static void setPacketType(packet_type type)
00278 {
00279 FILE *type_fh = 0;
00280 type_fh = fopen(rbu_v2_img_type_file, "wb");
00281 if (!type_fh)
00282 throw RbuDriverIOErrorImpl(strerror(errno));
00283
00284 switch(type)
00285 {
00286 case pt_mono:
00287 fwrite("mono\0", 1, 5, type_fh);
00288 break;
00289 case pt_packet:
00290 fwrite("packet\0", 1, 7, type_fh);
00291 break;
00292 case pt_any:
00293 case pt_init:
00294 default:
00295
00296 fwrite("init\0", 1, 7, type_fh);
00297 break;
00298 }
00299
00300 if (ferror(type_fh))
00301 throw RbuDriverIOErrorImpl(strerror(errno));
00302
00303 fclose(type_fh);
00304 }
00305
00306
00307 static void waitForFile(const char *fn, time_t wait)
00308 {
00309 time_t start = time(NULL);
00310 while( access(fn, F_OK) && (time(NULL) - start < wait))
00311 ;
00312 }
00313
00314 static void setLoadValue(char val)
00315 {
00316 FILE *load_fh = 0;
00317
00318 waitForFile(rbu_v2_fw_load_file, 10);
00319
00320 load_fh = fopen(rbu_v2_fw_load_file, "wb");
00321 if (!load_fh)
00322 throw RbuDriverIOErrorImpl(strerror(errno));
00323
00324 fwrite(&val, 1, 1, load_fh);
00325 if (ferror(load_fh))
00326 throw RbuDriverIOErrorImpl(strerror(errno));
00327 fclose(load_fh);
00328 fflush(NULL);
00329 }
00330
00331 static void doPacketUpdate_v2(FILE *hdr_fh)
00332 {
00333 const size_t bufSize = 4096;
00334 char buffer[bufSize] = {0};
00335
00336 setSize(rbu_v2_pkt_size_file, bufSize);
00337 setLoadValue('1');
00338 pktUpdateLoop(hdr_fh, rbu_v2_fw_data_file, buffer, bufSize, false);
00339 setLoadValue('0');
00340 }
00341
00342 static void doMonoUpdate_v2(FILE *hdr_fh)
00343 {
00344 cout << "Prep driver for data load." << endl;
00345 setLoadValue('1');
00346
00347 FILE *data_fh = fopen(rbu_v2_fw_data_file, "wb");
00348 if (!data_fh)
00349 throw RbuDriverIOErrorImpl(strerror(errno));
00350
00351 monoUpdateLoop(hdr_fh, data_fh);
00352
00353 fclose(data_fh);
00354 data_fh = 0;
00355 fflush(NULL);
00356
00357 cout << "Notify driver data is finished." << endl;
00358 setLoadValue('0');
00359 }
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 void dellBiosUpdate(string fileName, packet_type force_type)
00372 {
00373 FILE *hdr_fh = fopen( fileName.c_str(), "rb" );
00374 if (!hdr_fh)
00375 throw InvalidHdrFileImpl(strerror(errno));
00376
00377
00378
00379
00380 packet_type pt = getSupportedPacketType();
00381 cout << "Supported RBU type for this system: "
00382 << (pt == pt_packet ? "MONOLITHIC, PACKET" : "MONOLITHIC")
00383 << endl;
00384
00385 if( force_type != pt_init || force_type != pt_any )
00386 pt = force_type;
00387
00388 driver_type dt = getDriverType();
00389
00390 if (pt == pt_packet)
00391 {
00392 cout << endl;
00393 cout << "WARNING:" << endl;
00394 cout << " Packet support not yet complete/tested." << endl;
00395 cout << " please report ID information for this system so" << endl;
00396 cout << " that packet support can be tested." << endl;
00397 cout << endl;
00398 }
00399
00400 if (dt == rbu_linux_v2)
00401 {
00402
00403 cout << "Using RBU v2 driver. Initializing Driver. ";
00404 setPacketType(pt_init);
00405
00406
00407 cout << "Setting RBU type in v2 driver to: "
00408 << (pt == pt_packet ? "PACKET" : "MONOLITHIC")
00409 << (pt == force_type ? " (FORCED) ": "" )
00410 << endl;
00411 setPacketType(pt);
00412
00413 if (pt == pt_packet)
00414 doPacketUpdate_v2(hdr_fh);
00415 else
00416 doMonoUpdate_v2(hdr_fh);
00417 }
00418 else if(dt == rbu_linux_v1)
00419 {
00420 cout << "Using RBU v1 method: "
00421 << (pt == pt_packet ? "PACKET" : "MONOLITHIC")
00422 << (pt == force_type ? " (FORCED) ": "" )
00423 << endl;
00424 if (pt == pt_packet)
00425 doPacketUpdate_v1(hdr_fh);
00426 else
00427 doMonoUpdate_v1(hdr_fh);
00428 }
00429 else
00430 {
00431 throw RbuNotSupportedImpl("Could not open Dell RBU driver.");
00432 }
00433
00434 fclose(hdr_fh);
00435
00436 cout << "Activate CMOS bit to notify BIOS that update is ready on next boot." << endl;
00437 activateRbuToken();
00438
00439 cout << "Update staged sucessfully. BIOS update will occur on next reboot." << endl;
00440 }
00441
00442 void cancelDellBiosUpdate()
00443 {
00444
00445
00446 cout << "Cancel BIOS CMOS notification bit." << endl;
00447 cancelRbuToken();
00448
00449 driver_type dt = getDriverType();
00450 switch(dt)
00451 {
00452 case rbu_linux_v2:
00453
00454 cout << "Free kernel driver memory." << endl;
00455 setLoadValue('0');
00456
00457
00458 cout << "Re-initialize driver for next user." << endl;
00459 setPacketType(pt_init);
00460 break;
00461
00462 case rbu_linux_v1:
00463
00464 cout << "Re-initialize driver for next user." << endl;
00465 setSize(rbu_v1_mono_size_file, 0);
00466 setSize(rbu_v1_pkt_size_file, 0);
00467 fflush(NULL);
00468 break;
00469
00470 default:
00471 cout << "Could not determine RBU driver present, skipping." << endl;
00472 break;
00473 }
00474 }
00475 }
00476