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 size_t numBytes = fread(&(pkt->pktData), 1, bufSize - sizeof(rbu_packet) + 1, hdr_fh);
00122 UNREFERENCED_PARAMETER(numBytes);
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
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
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
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
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
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
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
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
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:
00281 case pt_init:
00282 default:
00283
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 }
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 ;
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
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
00367
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
00386 cout << "Using RBU v2 driver. Initializing Driver. " << endl;
00387 setPacketType(pt_init, rbu_v2_img_type_file);
00388
00389
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
00467
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
00476 cout << "Free kernel driver memory." << endl;
00477 setLoadValue('0');
00478
00479
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
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
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