00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #define LIBSMBIOS_SOURCE
00021 #include "smbios/compat.h"
00022
00023
00024
00025 #include "SmiImpl.h"
00026 #include "smbios/ISmbios.h"
00027 #include "smbios/IToken.h"
00028 #include "../token/TokenLowLevel.h"
00029
00030 using namespace std;
00031
00032 #if defined(DEBUG_SMI)
00033 # define DCOUT(line) do { cout << line; } while(0)
00034 # define DCERR(line) do { cerr << line; } while(0)
00035 #else
00036 # define DCOUT(line) do {} while(0)
00037 # define DCERR(line) do {} while(0)
00038 #endif
00039
00040
00041 #define SIZEOF_KERNELBUF (sizeof(kernel_buf) - sizeof(kernel_buf.command_buffer_start))
00042
00043 namespace smi
00044 {
00045
00046
00047
00048 ISmi::ISmi()
00049 {}
00050
00051 ISmi::~ISmi()
00052 {}
00053
00054 IDellCallingInterfaceSmi::IDellCallingInterfaceSmi()
00055 {}
00056
00057 IDellCallingInterfaceSmi::~IDellCallingInterfaceSmi()
00058 {}
00059
00060 DellCallingInterfaceSmiImpl::DellCallingInterfaceSmiImpl(SmiStrategy *initStrategy)
00061 : ISmi(), IDellCallingInterfaceSmi(), buffer(0), bufferSize(0), smiStrategy(initStrategy)
00062 {
00063
00064
00065 memset( &kernel_buf, 0, sizeof(kernel_buf) );
00066
00067 memset( &smi_buf, 0, sizeof(smi_buf) );
00068 memset( &argIsAddress, 0, sizeof(argIsAddress) );
00069 memset( &argAddressOffset, 0, sizeof(argAddressOffset) );
00070
00071 kernel_buf.magic = KERNEL_SMI_MAGIC_NUMBER;
00072 kernel_buf.ebx = 0;
00073 kernel_buf.ecx = DELL_CALLINTF_SMI_MAGIC_NUMBER;
00074 kernel_buf.command_address = 0;
00075 kernel_buf.command_code = 0;
00076
00077
00078 smi_buf.cbRES1 = -3;
00079 }
00080
00081 DellCallingInterfaceSmiImpl::~DellCallingInterfaceSmiImpl()
00082 {
00083 if(buffer)
00084 {
00085 delete [] buffer;
00086 buffer = 0;
00087 bufferSize = 0;
00088 }
00089 }
00090
00091 void DellCallingInterfaceSmiImpl::setCommandIOMagic( u16 address, u8 code )
00092 {
00093 kernel_buf.command_address = address;
00094 kernel_buf.command_code = code;
00095 }
00096
00097 u8 *DellCallingInterfaceSmiImpl::getBufferPtr()
00098 {
00099 return buffer;
00100 }
00101
00102 void DellCallingInterfaceSmiImpl::setBufferSize(size_t newSize)
00103 {
00104 if ( bufferSize != newSize )
00105 {
00106 delete [] buffer;
00107 buffer = new u8[newSize];
00108 memset(buffer, 0, newSize);
00109
00110 bufferSize=newSize;
00111 }
00112 }
00113
00114 void DellCallingInterfaceSmiImpl::execute()
00115 {
00116 smiStrategy->lock()
00117 ;
00118 smiStrategy->setSize( SIZEOF_KERNELBUF + sizeof(smi_buf) + bufferSize );
00119
00120 size_t baseAddr = smiStrategy->getPhysicalBufferBaseAddress();
00121 for( int i=0; i<4; i++)
00122 if( argIsAddress[i] )
00123 smi_buf.inputArgs[i] = static_cast<u32>(baseAddr + SIZEOF_KERNELBUF + sizeof(smi_buf) + argAddressOffset[i]);
00124
00125 smiStrategy->addInputBuffer(reinterpret_cast<u8 *>(&kernel_buf), SIZEOF_KERNELBUF);
00126 smiStrategy->addInputBuffer(reinterpret_cast<u8 *>(&smi_buf), sizeof(smi_buf));
00127 if(buffer)
00128 smiStrategy->addInputBuffer(buffer, bufferSize);
00129
00130 smiStrategy->execute();
00131
00132 smiStrategy->getResultBuffer(reinterpret_cast<u8 *>(&kernel_buf), SIZEOF_KERNELBUF);
00133 smiStrategy->getResultBuffer(reinterpret_cast<u8 *>(&smi_buf), sizeof(smi_buf));
00134 if(buffer)
00135 smiStrategy->getResultBuffer(reinterpret_cast<u8 *>(buffer), bufferSize);
00136
00137 smiStrategy->finish();
00138
00139 if( -3 == smi_buf.cbRES1 )
00140 throw UnhandledSmiImpl("Unhandled SMI call.");
00141
00142 if( -2 == smi_buf.cbRES1 )
00143 throw UnsupportedSmiImpl("Unsupported SMI call.");
00144
00145 if( -1 == smi_buf.cbRES1 )
00146 throw SmiExecutedWithErrorImpl("BIOS returned error for SMI call.");
00147 }
00148
00149 void DellCallingInterfaceSmiImpl::setArgAsPhysicalAddress( u8 argNumber, u32 bufferOffset )
00150 {
00151 if( argNumber >= 4 )
00152 throw ParameterErrorImpl("Internal programming error. Argument must be in range 0..3");
00153
00154 argIsAddress[argNumber] = true;
00155 argAddressOffset[argNumber] = bufferOffset;
00156 }
00157
00158
00159 void DellCallingInterfaceSmiImpl::setClass( u16 newClass )
00160 {
00161 smi_buf.smiClass = newClass;
00162 }
00163
00164 void DellCallingInterfaceSmiImpl::setSelect( u16 newSelect )
00165 {
00166 smi_buf.smiSelect = newSelect;
00167 }
00168
00169 void DellCallingInterfaceSmiImpl::setArg( u8 argNumber, u32 argValue )
00170 {
00171 if( argNumber >= 4 )
00172 throw ParameterErrorImpl("Internal programming error. Argument must be in range 0..3");
00173
00174 smi_buf.inputArgs[ argNumber ] = argValue;
00175 }
00176
00177 u32 DellCallingInterfaceSmiImpl::getRes( u8 resNumber ) const
00178 {
00179 if( resNumber >= 4 )
00180 throw ParameterErrorImpl("Internal programming error. Result request must be in range 0..3");
00181
00182 return smi_buf.outputRes[resNumber];
00183 }
00184
00185
00186
00187
00188
00189
00190 std::auto_ptr<smi::IDellCallingInterfaceSmi> setupCallingInterfaceSmi(u16 smiClass, u16 select, const u32 args[4])
00191 {
00192 smbios::ISmbiosTable *table = 0;
00193 table = smbios::SmbiosFactory::getFactory()->getSingleton();
00194
00195 std::auto_ptr<smi::ISmi> smi = smi::SmiFactory::getFactory()->makeNew(smi::SmiFactory::DELL_CALLING_INTERFACE_SMI);
00196 smi::IDellCallingInterfaceSmi *ci = dynamic_cast<smi::IDellCallingInterfaceSmi *>(smi.get());
00197
00198 size_t len = 0;
00199 const u8 *buf = 0;
00200 try
00201 {
00202 buf = (*table)[0xDA]->getBufferCopy(len);
00203
00204
00205 if( len < (sizeof(smbios::calling_interface_structure) - sizeof(smbios::calling_interface_token)) )
00206 throw smbios::InternalErrorImpl("Internal error. Possible BIOS problem: length of 0xDA structure is too short.");
00207
00208 const smbios::calling_interface_structure *struct_ptr = reinterpret_cast<const smbios::calling_interface_structure*>(buf);
00209 smi->setCommandIOMagic( struct_ptr->cmdIOAddress, struct_ptr->cmdIOCode );
00210 delete [] const_cast<u8 *>(buf);
00211 }
00212 catch(const smbios::DerefNullPointer &)
00213 {
00214 delete [] const_cast<u8 *>(buf);
00215 throw smbios::InternalErrorImpl("Internal error. It does not appear that this BIOS supports SMI (no 0xDA structure in SMBIOS).");
00216 }
00217 catch(...)
00218 {
00219 delete [] const_cast<u8 *>(buf);
00220 throw;
00221 }
00222
00223 ci->setClass( smiClass );
00224 ci->setSelect( select );
00225 ci->setArg(0, args[0]);
00226 ci->setArg(1, args[1]);
00227 ci->setArg(2, args[2]);
00228 ci->setArg(3, args[3]);
00229
00230 std::auto_ptr<smi::IDellCallingInterfaceSmi> retval(
00231 dynamic_cast<smi::IDellCallingInterfaceSmi *>(smi.get())
00232 );
00233 smi.release();
00234 return retval;
00235 }
00236
00237 void doSimpleCallingInterfaceSmi(u16 smiClass, u16 select, const u32 args[4], u32 res[4])
00238 {
00239
00240 std::auto_ptr<smi::IDellCallingInterfaceSmi> smi(
00241 setupCallingInterfaceSmi(smiClass, select, args));
00242
00243 smi->execute();
00244
00245 res[0] = smi->getRes(0);
00246 res[1] = smi->getRes(1);
00247 res[2] = smi->getRes(2);
00248 res[3] = smi->getRes(3);
00249 }
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 static bool getPasswordPropertiesII(u16 which, u8 &maxLen, u8 &minLen, u8 &props)
00264 {
00265 if( which != 9 && which != 10 )
00266 throw ParameterErrorImpl("Internal programming error. Argument must be either 9 or 10.");
00267
00268 bool hasPw = false;
00269
00270 u32 args[4] = {0,}, res[4] = {0,};
00271
00272
00273 doSimpleCallingInterfaceSmi(which, 3, args, res);
00274
00275
00276 if( res[1] & 0xFF )
00277 goto out;
00278
00279 DCERR( "getPasswordPropertiesII()" << hex << endl );
00280 DCERR( "res[0]: " << res[0] << endl);
00281 DCERR( "res[1]: " << res[1] << endl);
00282 DCERR( "res[2]: " << res[2] << endl);
00283 DCERR( "res[3]: " << res[3] << endl);
00284
00285 hasPw = true;
00286 maxLen = static_cast<u8>((res[1] & 0x0000FF00) >> 8);
00287 minLen = static_cast<u8>((res[1] & 0x00FF0000) >> 16);
00288 props = static_cast<u8>((res[1] & 0xFF000000) >> 24);
00289
00290 out:
00291 return hasPw;
00292 }
00293
00294 static u32 getAuthenticationKeyII(const string &password)
00295 {
00296 u32 authKey = 0;
00297
00298 DCERR( "getAuthenticationKeyII()" << endl );
00299
00300 u16 toCheck[2] = { class_admin_password, class_user_password };
00301 DCERR( " trying auth keys" << endl);
00302
00303
00304 for( int i=0; i<2; i++ )
00305 {
00306 DCERR( " trying class code: " << toCheck[i] << endl);
00307
00308 u8 maxLen=0, minLen=0, props=0;
00309
00310 try
00311 {
00312 if( ! getPasswordPropertiesII(toCheck[i], maxLen, minLen, props) )
00313 continue;
00314 }
00315 catch( const exception & )
00316 {
00317
00318
00319
00320 continue;
00321 }
00322
00323 DCERR("has a password." << hex << endl);
00324 DCERR( " max len: " << (int)maxLen << endl);
00325 DCERR( " min len: " << (int)minLen << endl);
00326 DCERR( " props : " << hex << props << endl);
00327
00328 u32 args[4] = {0,};
00329
00330 std::auto_ptr<smi::IDellCallingInterfaceSmi> smi(setupCallingInterfaceSmi(toCheck[i], 4, args));
00331 smi->setBufferSize(maxLen);
00332 strncpy( reinterpret_cast<char*>(smi->getBufferPtr()), password.c_str(), maxLen);
00333 smi->setArgAsPhysicalAddress( 0, 0 );
00334 smi->execute();
00335
00336 DCERR("after verify:"<< endl);
00337 DCERR("res[0]: " << smi->getRes(0) << endl; );
00338 DCERR("res[1]: " << smi->getRes(1) << endl; );
00339 DCERR("res[2]: " << smi->getRes(2) << endl; );
00340 DCERR("res[3]: " << smi->getRes(3) << endl; );
00341
00342 if(! smi->getRes(0))
00343 authKey = smi->getRes(1);
00344 else
00345 throw PasswordVerificationFailedImpl("BIOS setup password enabled, but given password does not match.");
00346
00347
00348
00349 break;
00350 }
00351
00352 return authKey;
00353 }
00354
00355 u32 getAuthenticationKey(const string &password)
00356 {
00357 u32 authKey = 0;
00358
00359 DCERR("getAuthenticationKey()" << endl);
00360
00361
00362 u16 toCheck[2] = { class_admin_password, class_user_password };
00363 DCERR(" trying auth keys" << endl);
00364
00365 for( int i=0; i<2; i++ )
00366 {
00367 DCERR(" trying class code: " << toCheck[i] << endl);
00368 try
00369 {
00370 u32 args[4] = {0,}, res[4] = {0,};
00371 doSimpleCallingInterfaceSmi(toCheck[i], 0, args, res);
00372
00373
00374 if( res[0] != 0 )
00375 continue;
00376 }
00377 catch(const SmiException &)
00378 {
00379
00380
00381
00382
00383 continue;
00384 }
00385
00386
00387
00388
00389 DCERR(" password installed" << endl);
00390
00391 u32 args[4] = {0}, res[4] = {0,};
00392 strncpy(reinterpret_cast<char *>(args), password.c_str(), 2 * sizeof(u32));
00393
00394 DCERR(" args are : 0x" << args[0] << " 0x" << args[1] << " 0x" << args[2] << " 0x" << args[3] << endl);
00395
00396
00397 doSimpleCallingInterfaceSmi(toCheck[i], 1, args, res);
00398
00399 if( res[0] == 0 )
00400 authKey = res[1];
00401 else
00402 throw PasswordVerificationFailedImpl("BIOS setup password enabled, but given password does not match.");
00403
00404
00405
00406 break;
00407 }
00408
00409
00410 if( ! authKey )
00411 authKey = getAuthenticationKeyII( password );
00412
00413 return authKey;
00414 }
00415
00416 password_format_enum getPasswordFormat()
00417 {
00418 password_format_enum format = PW_FORMAT_UNKNOWN;
00419
00420 try
00421 {
00422 u32 args[4] = {0,}, res[4] = {0,};
00423 doSimpleCallingInterfaceSmi(class_admin_password, 0, args, res);
00424 format = PW_FORMAT_SCAN_CODE;
00425 goto out;
00426 }
00427 catch(const exception &)
00428 { }
00429
00430 try
00431 {
00432 u32 args[4] = {0,}, res[4] = {0,};
00433 doSimpleCallingInterfaceSmi(class_user_password, 0, args, res);
00434 format = PW_FORMAT_SCAN_CODE;
00435 goto out;
00436 }
00437 catch(const exception &)
00438 { }
00439
00440 try
00441 {
00442 u8 maxLen=0, minLen=0, props=0;
00443 getPasswordPropertiesII(class_admin_password, maxLen, minLen, props);
00444 format = PW_FORMAT_SCAN_CODE;
00445 if (props & 0x01)
00446 format = PW_FORMAT_ASCII;
00447 goto out;
00448 }
00449 catch(const exception &)
00450 { }
00451
00452 try
00453 {
00454 u8 maxLen=0, minLen=0, props=0;
00455 getPasswordPropertiesII(class_user_password, maxLen, minLen, props);
00456 format = PW_FORMAT_SCAN_CODE;
00457 if (props & 0x01)
00458 format = PW_FORMAT_ASCII;
00459 goto out;
00460 }
00461 catch(const exception &)
00462 { }
00463
00464 out:
00465 return format;
00466 }
00467
00468 static u32 readSetting(u16 select, u32 location, u32 *minValue, u32 *maxValue)
00469 {
00470 u32 args[4] = {location, 0,}, res[4] = {0,};
00471 doSimpleCallingInterfaceSmi(0, select, args, res);
00472 if(minValue)
00473 *minValue = res[2];
00474 if(maxValue)
00475 *maxValue = res[3];
00476 return res[1];
00477 }
00478
00479 u32 readNVStorage(u32 location, u32 *minValue, u32 *maxValue)
00480 {
00481 return readSetting(0, location, minValue, maxValue);
00482 }
00483
00484 u32 readBatteryModeSetting(u32 location, u32 *minValue, u32 *maxValue)
00485 {
00486 return readSetting(1, location, minValue, maxValue);
00487 }
00488
00489 u32 readACModeSetting(u32 location, u32 *minValue, u32 *maxValue)
00490 {
00491 return readSetting(2, location, minValue, maxValue);
00492 }
00493
00494 u32 readSystemStatus(u32 *failingSensorHandle)
00495 {
00496
00497
00498
00499 return readSetting(3, 0, failingSensorHandle, 0);
00500 }
00501
00502
00503 static u32 writeSetting(const std::string &password, u16 select, u32 location, u32 newValue, u32 *minValue, u32 *maxValue)
00504 {
00505 u32 args[4] = {location, newValue,}, res[4] = {0,};
00506
00507
00508 for(int i=0; i<2; i++)
00509 {
00510 try
00511 {
00512
00513 doSimpleCallingInterfaceSmi(1, select, args, res);
00514 break;
00515 }
00516 catch(const SmiExecutedWithError &)
00517 {
00518
00519 if(i==1)
00520 throw;
00521
00522 args[2] = getAuthenticationKey(password);
00523 }
00524 }
00525
00526 if(minValue)
00527 *minValue = res[2];
00528 if(maxValue)
00529 *maxValue = res[3];
00530 return res[1];
00531 }
00532
00533 u32 writeNVStorage(const std::string &password, u32 location, u32 value, u32 *minValue, u32 *maxValue)
00534 {
00535 return writeSetting(password, 0, location, value, minValue, maxValue);
00536 }
00537
00538 u32 writeBatteryModeSetting(const std::string &password, u32 location, u32 value, u32 *minValue, u32 *maxValue)
00539 {
00540 return writeSetting(password, 1, location, value, minValue, maxValue);
00541 }
00542
00543 u32 writeACModeSetting(const std::string &password, u32 location, u32 value, u32 *minValue, u32 *maxValue)
00544 {
00545 return writeSetting(password, 2, location, value, minValue, maxValue);
00546 }
00547
00548 void getDisplayType(u32 &type, u32 &resolution, u32 &memSizeX256kb)
00549 {
00550 u32 args[4] = {0,}, res[4] = {0,};
00551 doSimpleCallingInterfaceSmi(4, 0, args, res);
00552
00553 type = (res[1] & 0x00FF);
00554 resolution = (res[1] & 0xFF00) >> 8;
00555 memSizeX256kb = res[2];
00556 }
00557
00558 void getPanelResolution(u32 &horiz, u32 &vert)
00559 {
00560 u32 args[4] = {0,}, res[4] = {0,};
00561 doSimpleCallingInterfaceSmi(4, 1, args, res);
00562
00563 horiz = (res[1] & 0x0000FFFF);
00564 vert = (res[1] & 0xFFFF0000) >> 16;
00565 }
00566
00567 void getActiveDisplays(u32 &bits)
00568 {
00569 u32 args[4] = {0,}, res[4] = {0,};
00570 doSimpleCallingInterfaceSmi(4, 2, args, res);
00571
00572 bits = res[1];
00573 }
00574
00575 void setActiveDisplays(u32 &bits)
00576 {
00577 u32 args[4] = {bits, 0,}, res[4] = {0,};
00578 doSimpleCallingInterfaceSmi(4, 3, args, res);
00579 }
00580
00581 void getPropertyOwnershipTag(char *tagBuf, size_t size)
00582 {
00583 u32 args[4] = {0,};
00584
00585 std::auto_ptr<smi::IDellCallingInterfaceSmi> smi(setupCallingInterfaceSmi(20, 0, args));
00586 smi->setBufferSize(120);
00587 smi->setArgAsPhysicalAddress( 0, 0 );
00588 smi->execute();
00589 strncpy( tagBuf, reinterpret_cast<char*>(smi->getBufferPtr()), size < 80? size:80);
00590 }
00591
00592 void setPropertyOwnershipTag(const string password, const char *newTag, size_t size)
00593 {
00594 u32 args[4] = {0,};
00595
00596 for(int i=0; i<2; i++)
00597 {
00598 try
00599 {
00600
00601 std::auto_ptr<smi::IDellCallingInterfaceSmi> smi(setupCallingInterfaceSmi(20, 1, args));
00602 smi->setBufferSize(120);
00603 strncpy( reinterpret_cast<char*>(smi->getBufferPtr()), newTag, size < 80? size:80);
00604 smi->setArgAsPhysicalAddress( 0, 0 );
00605 smi->execute();
00606 break;
00607 }
00608 catch(const SmiExecutedWithError &)
00609 {
00610
00611 if(i==1)
00612 throw;
00613
00614
00615 args[1] = getAuthenticationKey(password);
00616 }
00617 }
00618 }
00619
00620 }