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
00035
00036 #include "smbios/message.h"
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
00110 rbu_packet *pkt = reinterpret_cast<rbu_packet *>(buffer);
00111 createPacket(buffer, bufSize, totalSizeBytes);
00112
00113
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
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
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
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
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
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
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
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
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:
00280 case pt_init:
00281 default:
00282
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 }
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 ;
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
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
00366
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
00385 cout << "Using RBU v2 driver. Initializing Driver. " << endl;
00386 setPacketType(pt_init, rbu_v2_img_type_file);
00387
00388
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
00466
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
00475 cout << "Free kernel driver memory." << endl;
00476 setLoadValue('0');
00477
00478
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
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
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