|
SASC
DVBSoftCAM
|
00001 /* 00002 * Softcam plugin to VDR (C++) 00003 * 00004 * This code is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This code is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00018 */ 00019 00020 #include <stdio.h> 00021 #include <stdlib.h> 00022 #include <string.h> 00023 00024 #include "nagra2.h" 00025 00026 // -- cAuxSrv ------------------------------------------------------------------ 00027 00028 #ifdef HAS_AUXSRV 00029 #include "network.h" 00030 #define AUX_PROTOCOL_VERSION 2 00031 int auxEnabled=0; 00032 int auxPort=7777; 00033 char auxAddr[80]="localhost"; 00034 char auxPassword[250]="auxserver"; 00035 00036 class cAuxSrv : public cMutex { 00037 private: 00038 cNetSocket so; 00039 // 00040 bool Login(void); 00041 public: 00042 int Map(int map, unsigned char *data, int len, int outlen); 00043 }; 00044 00045 bool cAuxSrv::Login() 00046 { 00047 unsigned char buff[256]; 00048 PRINTF(L_SYS_MAP,"auxsrv: connecting to %s:%d",auxAddr,auxPort); 00049 so.SetRWTimeout(7000); 00050 if(so.Connect(auxAddr,auxPort)) { 00051 buff[0]=0xA7; 00052 buff[1]=0x7A; 00053 buff[2]=0; 00054 int l=strlen(auxPassword); 00055 buff[3]=l; 00056 memcpy(&buff[4],auxPassword,l); 00057 buff[4+l]=0xFF; 00058 if(so.Write(buff,l+5)>0 && 00059 so.Read(buff,9)>0 && 00060 buff[0]==0x7A && buff[1]==0xA7 && buff[2]==0x00 && buff[3]==0x04 && buff[8]==0xff && 00061 ((buff[4]<<8)|buff[5])==AUX_PROTOCOL_VERSION) return true; 00062 PRINTF(L_SYS_MAP,"auxsrv: login write failed"); 00063 } 00064 so.Disconnect(); 00065 return false; 00066 } 00067 00068 int cAuxSrv::Map(int map, unsigned char *data, int len, int outlen) 00069 { 00070 if(!auxEnabled) { 00071 PRINTF(L_SYS_MAP,"auxsrv: AUXserver is disabled!"); 00072 return -1; 00073 } 00074 if(len>500 || outlen>500) return -1; 00075 cMutexLock lock(this); 00076 if(!so.Connected() && !Login()) return false; 00077 PRINTF(L_SYS_MAP,"auxsrv: calling map%02x",map); 00078 unsigned char buff[512]; 00079 buff[0]=0xA7; 00080 buff[1]=0x7A; 00081 buff[2]=((len+1)>>8) & 0xff; 00082 buff[3]=(len+1)&0xff; 00083 buff[4]=map; 00084 memcpy(&buff[5],data,len); 00085 buff[len+5]=0xFF; 00086 if(so.Write(buff,len+6)>0) { 00087 if(so.Read(buff,5)>0) { 00088 if(buff[0]==0x7A && buff[1]==0xA7) { 00089 int l=buff[2]*256+buff[3]; 00090 if(so.Read(buff+5,l,200)>0) { 00091 if(buff[4]==0x00) { 00092 int cycles=(buff[5]<<16)|(buff[6]<<8)|buff[7]; 00093 if(l==outlen+4) { 00094 if(buff[l+4]==0xFF) { 00095 memcpy(data,buff+8,outlen); 00096 return cycles; 00097 } 00098 else PRINTF(L_SYS_MAP,"auxsrv: bad footer in map%02x response",map); 00099 } 00100 else PRINTF(L_SYS_MAP,"auxsrv: bad length in map%02x response (got=%d want=%d)",map,l-4,outlen); 00101 } 00102 else PRINTF(L_SYS_MAP,"auxsrv: map%02x not successfull (unsupported?)",map); 00103 } 00104 else PRINTF(L_SYS_MAP,"auxsrv: map%02x read failed (2)",map); 00105 } 00106 else PRINTF(L_SYS_MAP,"auxsrv: bad response to map%02x",map); 00107 } 00108 else PRINTF(L_SYS_MAP,"auxsrv: map%02x read failed",map); 00109 } 00110 else PRINTF(L_SYS_MAP,"auxsrv: map%02x write failed",map); 00111 so.Disconnect(); 00112 return -1; 00113 } 00114 #endif //HAS_AUXSRV 00115 00116 // -- cMap0101 ---------------------------------------------------------------- 00117 00118 class cMap0101 : public cMapCore { 00119 private: 00120 static const unsigned char primes[]; 00121 static const int tim3b[][17]; 00122 static const unsigned short msb3e[]; 00123 #ifdef HAS_AUXSRV 00124 cAuxSrv aux; 00125 #endif 00126 // 00127 void MakePrime(unsigned char *residues, bool strong); 00128 protected: 00129 virtual bool Map(int f, unsigned char *data, int l); 00130 }; 00131 00132 const unsigned char cMap0101::primes[] = { 00133 0x03,0x05,0x07,0x0B,0x0D,0x11,0x13,0x17,0x1D,0x1F,0x25,0x29,0x2B,0x2F,0x35,0x3B, 00134 0x3D,0x43,0x47,0x49,0x4F,0x53,0x59,0x61,0x65,0x67,0x6B,0x6D,0x71,0x7F,0x83,0x89, 00135 0x8B,0x95,0x97,0x9D,0xA3,0xA7,0xAD,0xB3,0xB5,0xBF,0xC1,0xC5,0xC7,0xD3,0xDF,0xE3, 00136 0xE5,0xE9,0xEF,0xF1,0xFB 00137 }; 00138 00139 const int cMap0101::tim3b[][17] = { 00140 { 2666,2804,2957,3105,3258,3406,3554,3707,3855,4008,4156,4304,4457,4605,4758,4906,5054 }, 00141 { 3163,3316,3484,3652,3815,3983,4146,4314,4482,4645,4813,4976,5144,5312,5475,5643,5806 }, 00142 { 3715,3888,4071,4254,4432,4615,4798,4981,5164,5342,5525,5708,5891,6074,6252,6435,6618 }, 00143 { 4302,4490,4688,4886,5084,5282,5480,5678,5876,6074,6272,6470,6668,6866,7064,7262,7460 }, 00144 { 4899,5107,5320,5533,5751,5964,6177,6390,6603,6821,7034,7247,7460,7673,7891,8104,8317 }, 00145 { 5541,5759,5992,6220,6453,6681,6909,7142,7370,7603,7831,8059,8292,8520,8753,8981,9209 }, 00146 { 6198,6431,6679,6927,7170,7418,7661,7909,8157,8400,8648,8891,9139,9387,9630,9878,10121 }, 00147 { 6910,7163,7426,7689,7947,8210,8473,8736,8999,9257,9520,9783,10046,10309,10567,10830,11093 }, 00148 { 7637,7905,8183,8461,8739,9017,9295,9573,9851,10129,10407,10685,10963,11241,11519,11797,12075 }, 00149 { 8394,8682,8975,9268,9566,9859,10152,10445,10738,11036,11329,11622,11915,12208,12506,12799,13092 }, 00150 { 9196,9494,9807,10115,10428,10736,11044,11357,11665,11978,12286,12594,12907,13215,13528,13836,14144 }, 00151 { 10003,10346,10674,11002,11325,11653,11976,12304,12632,12955,13283,13606,13934,14262,14585,14913,15236 }, 00152 { 10885,11218,11561,11904,12242,12585,12928,13271,13614,13952,14295,14638,14981,15324,15662,16005,16348 }, 00153 { 11792,12145,12498,12856,13214,13572,13930,14288,14646,15004,15362,15720,16078,16436,16794,17152,17510 }, 00154 { 12709,13087,13465,13843,14226,14604,14982,15360,15738,16121,16499,16877,17255,17633,18016,18394,18772 }, 00155 { 13671,14069,14477,14880,15283,15686,16084,16492,16890,17298,17696,18099,18507,18905,19313,19711,20114 }, 00156 { 14668,15091,15519,15947,16370,16798,17221,17654,18082,18505,18933,19356,19784,20212,20640,21068,21491 }, 00157 }; 00158 00159 void cMap0101::MakePrime(unsigned char *residues, bool strong) 00160 { 00161 bool isPrime; 00162 AddMapCycles(strong?462:258); 00163 BN_copy(D,B); 00164 AddMapCycles(240); 00165 BN_zero(A); 00166 AddMapCycles(41); 00167 BN_set_word(A,2); 00168 A.SetPos(1); 00169 AddMapCycles(12); 00170 for(int i=2; i<=8; i++) { A.SetPos(i); AddMapCycles(9); } 00171 A.SetPos(0); 00172 AddMapCycles(8); 00173 if(strong) D.GetLE(residues+53,8); 00174 unsigned int counts[3] = { 0 }; 00175 bool first=true; 00176 do { 00177 counts[0]++;; 00178 BN_add_word(B,2); 00179 if(first) { first=false; AddMapCycles(1600); } 00180 isPrime=true; 00181 for(int i=0; i<53; i++) { 00182 residues[i]+=2; 00183 unsigned char num=residues[i]; 00184 unsigned char denom=primes[i]; 00185 if(num>denom) { 00186 unsigned char r=0; 00187 while(denom>=r) { counts[1]++; r=(r<<1)|((num&0x80)>>7); num<<=1; } 00188 } 00189 residues[i]%=primes[i]; 00190 if(residues[i]==0) { counts[2]++; isPrime=false; } 00191 } 00192 } while(!isPrime); 00193 cycles=1290+1465*counts[0]+counts[1]+13*counts[2]; 00194 } 00195 00196 bool cMap0101::Map(int f, unsigned char *data, int l) 00197 { 00198 int sl=l; 00199 l=GetOpSize(l); 00200 switch(f) { 00201 case 0x21: 00202 AddMapCycles(169-6); 00203 IMakeJ(); 00204 cycles=898; 00205 break; 00206 case 0x22: 00207 if(BN_is_zero(D)) { cycles=639-6; break; } 00208 l&=0x1fff; 00209 AddMapCycles(376); 00210 BN_zero(B); 00211 AddMapCycles(l>=(BN_num_bits(D)-1)/64*64 ? 244 : 210); 00212 BN_one(B); 00213 B.SetPos(1); 00214 AddMapCycles(17); 00215 for(int i=2; i<=8; i++) { B.SetPos(i); AddMapCycles(9); } 00216 AddMapCycles(44); 00217 BN_mod_lshift(B,B,l,D,ctx); 00218 break; 00219 case 0x23: 00220 AddMapCycles(169); 00221 IMonInit0(); 00222 break; 00223 case 0x25: 00224 AddMapCycles(254); 00225 MakeJ0(B,D,C,wordsize<<6); 00226 // valid for wordsize 1 and 2 00227 AddMapCycles(795*wordsize-492); 00228 BN_zero(C); 00229 cycles=49+800*wordsize; 00230 break; 00231 case 0x29: 00232 { 00233 BN_add(B,B,C); 00234 bool b=BN_is_bit_set(B,wordsize<<6); 00235 if(b) BN_mask_bits(B,wordsize<<6); 00236 if(data) data[0]=b; 00237 cycles=501+(8*wordsize+3)/5*5-6; 00238 break; 00239 } 00240 case 0x2a: 00241 { 00242 bool b=ModSub(B,B,D); 00243 if(data) data[0]=b; 00244 BN_zero(C); 00245 break; 00246 } 00247 case 0x2e: 00248 case 0x2F: 00249 if(l<=0) { cycles+=4; l=wordsize; } 00250 else if(l>17) { cycles+=5; l=17; } 00251 scalar.GetLE(data,l<<3); 00252 AddMapCycles(617+30*wordsize); 00253 for(int i=0; i<l; i++) { 00254 if(i&1) { 00255 unsigned char buf[8]; 00256 J.PutLE(buf,8); 00257 AddMapCycles(10); 00258 for(int j=0; j<8; j++) { 00259 buf[j]=data[i*8+j]; 00260 J.GetLE(buf,8); 00261 J.SetPos(j+1); 00262 AddMapCycles(14); 00263 } 00264 J.SetPos(0); 00265 AddMapCycles(12); 00266 } 00267 else 00268 AddMapCycles(114); 00269 } 00270 AddMapCycles(3); 00271 BN_mul(D,scalar,B,ctx); 00272 if(f&1) BN_add(D,D,C); 00273 BN_rshift(C,D,l<<6); 00274 BN_mask_bits(D,l<<6); 00275 D.Commit(l); 00276 BN_mask_bits(C,wordsize<<6); 00277 break; 00278 case 0x30: 00279 case 0x31: 00280 BN_sqr(D,B,ctx); 00281 if((f&1)) BN_add(D,D,C); 00282 BN_rshift(C,D,wordsize<<6); 00283 BN_rshift(J,B,((wordsize+1)/2)*128-64); 00284 BN_mask_bits(J,64); 00285 break; 00286 case 0x32: 00287 AddMapCycles(1000); 00288 l=min(34,l); 00289 if(!BN_is_zero(D)) { 00290 scalar.GetLE(data,l<<3); 00291 BN_div(C,B,scalar,D,ctx); 00292 BN_rshift(A,C,17*64); 00293 A.Commit(17); 00294 C.Commit(17); 00295 } 00296 BN_zero(J); 00297 break; 00298 case 0x36: 00299 case 0x38: 00300 AddMapCycles(230); 00301 MonMul0(B,f==0x36?A:B,B,C,D,J,wordsize); 00302 AddMapCycles(102); 00303 MonFin(B,D); 00304 break; 00305 case 0x3b: 00306 AddMapCycles(441); 00307 IMakeJ(); 00308 AddMapCycles(46); 00309 IMonInit0(wordsize*60+4*l); 00310 scalar.GetLE(data,l<<3); 00311 MonMul(B,scalar,B,l); 00312 cycles=tim3b[wordsize-1][l-1]-6; 00313 break; 00314 case 0x3d: 00315 AddMapCycles(652); 00316 D.GetLE(data,wordsize<<3); 00317 AddMapCycles(514); 00318 IMakeJ(); 00319 AddMapCycles(35); 00320 MonMul0(C,B,B,C,D,J,wordsize); 00321 AddMapCycles(143); 00322 BN_copy(A,B); 00323 AddMapCycles(73); 00324 MonExpNeg(); 00325 MonMul(B,A,B); 00326 BN_zero(C); 00327 cycles+=rand()%(wordsize*20000)+2000; 00328 break; 00329 case 0x3c: 00330 case 0x3e: 00331 case 0x46: 00332 { 00333 if(f==0x46) l=1; else l=sl; 00334 if(l<=0) { l=wordsize; cycles+=4; } 00335 else if(l>wordsize) { l=wordsize; cycles+=l>17 ? 9:4; } 00336 scalar.GetLE(data,l<<3); 00337 int sbits=BN_num_bits(scalar); 00338 cycles+=3848+((sbits-1)/8)*650 - 11; 00339 int msb=data[(sbits-1)/8]; 00340 for(int i=7; i>=1; --i) if(msb&(1<<i)) { cycles+=i*75-15; break; } 00341 for(int i=0; i<sbits; ++i) if(BN_is_bit_set(scalar,i)) cycles+=88; 00342 AddMapCycles(f==0x46 ? 400:441); 00343 if(BN_is_zero(scalar) || BN_num_bits(D)<=1) { 00344 IMakeJ(); 00345 if(BN_num_bits(D)==1 || !BN_is_zero(scalar)) BN_zero(B); 00346 else BN_one(B); 00347 BN_one(A); 00348 } 00349 else { 00350 IMonInit(); 00351 MonMul0(B,A,B,C,D,J,0); 00352 if(f==0x3c) AddMapCycles(2200+(rand()%(wordsize*2000))); 00353 MonFin(B,D); 00354 } 00355 BN_zero(C); 00356 if(f==0x46) cycles-=37; 00357 } 00358 break; 00359 case 0x4d: 00360 if(-0x018000==l) 00361 BN_mask_bits(B,64); 00362 else { 00363 BN_set_bit(B,(wordsize<<6)-1); 00364 if(-0x028000==l) BN_set_bit(B,(wordsize<<6)-2); 00365 } 00366 BN_set_bit(B,0); 00367 for(int i=0; i<53; i++) data[i]=BN_mod_word(B,primes[i]); 00368 BN_copy(A,B); 00369 BN_zero(C); BN_zero(D); BN_zero(J); 00370 break; 00371 case 0x4e: 00372 case 0x4f: 00373 MakePrime(data,f==0x4f); 00374 break; 00375 case 0x57: 00376 #ifdef HAS_AUXSRV 00377 { 00378 int c=aux.Map(0x57,data,0x60,0x40); 00379 if(c>0) { cycles=c-6; break; } 00380 } 00381 #endif 00382 { 00383 cBN a, b, x, y; 00384 if(l<2 || l>4) l=4; 00385 WS_START(l); 00386 l<<=3; 00387 D.GetLE(data+0*l,l); 00388 x.GetLE(data+1*l,l); 00389 y.GetLE(data+2*l,l); 00390 b.GetLE(data+3*l,l); 00391 a.GetLE(data+4*l,l); 00392 scalar.GetLE(data+5*l,l); 00393 bool doz=false; 00394 int scalarbits=BN_num_bits(scalar); 00395 if(scalarbits>=2) { 00396 if(BN_is_zero(x) && (BN_is_zero(y) || (BN_is_zero(b) && BN_num_bits(y)==1))) { 00397 BN_zero(Px); 00398 BN_copy(Py,y); 00399 BN_zero(Qz); 00400 MakeJ0(J,D); 00401 } 00402 else { 00403 CurveInit(a); 00404 ToProjective(0,x,y); 00405 BN_copy(Qx,Px); 00406 BN_copy(Qy,Py); 00407 for(int i=scalarbits-2; i>=0; i--) { 00408 DoubleP(0); 00409 if(BN_is_bit_set(scalar,i)) { 00410 BN_copy(A,Pz); 00411 if(BN_is_zero(Pz) || BN_is_zero(D)) { 00412 BN_copy(Px,Qx); 00413 BN_copy(Py,Qy); 00414 BN_copy(Pz,Qz); 00415 AddP(1); 00416 } 00417 else { 00418 doz=true; 00419 if(wordsize==4) { 00420 BN_rshift(Py,Py,32); 00421 BN_lshift(Py,Py,32); 00422 BN_rshift(b,Qz,224); 00423 BN_add(Py,Py,b); 00424 } 00425 BN_mask_bits(Px,32); 00426 BN_lshift(b,Qz,32); 00427 BN_add(Px,Px,b); 00428 BN_mask_bits(Px,l<<3); 00429 AddP(0); 00430 } 00431 } 00432 } 00433 ToAffine(); 00434 } 00435 } 00436 else { 00437 BN_copy(Px,x); 00438 BN_copy(Py,y); 00439 BN_zero(Qz); 00440 MakeJ0(J,D); 00441 } 00442 memset(data,0,0x40); 00443 Px.PutLE(&data[0x00],l); 00444 if(l<0x20 && doz) { 00445 unsigned char tmp[0x20]; 00446 Qz.PutLE(tmp,l); 00447 memcpy(&data[l],&tmp[l-4],4); 00448 } 00449 Py.PutLE(&data[0x20],l); 00450 BN_zero(A); 00451 BN_zero(B); 00452 BN_zero(C); 00453 WS_END(); 00454 break; 00455 } 00456 default: 00457 return false; 00458 } 00459 return true; 00460 } 00461 00462 // -- cN2Prov0101 -------------------------------------------------------------- 00463 00464 class cN2Prov0101 : public cN2Prov, public cN2Emu, private cMap0101 { 00465 private: 00466 int desSize; 00467 DES_key_schedule desks1, desks2; 00468 unsigned char desblock[8]; 00469 IdeaKS ks; 00470 cMapMemHW *hwMapper; 00471 // Randomiser 00472 unsigned int rnd, rndtime; 00473 // 00474 void AddRomCallbacks(void); 00475 bool RomCallbacks(void); 00476 bool ProcessMap(int f); 00477 bool ProcessDESMap(int f); 00478 protected: 00479 int mecmAddr[2]; 00480 int mecmKeyId; 00481 // 00482 virtual bool Algo(int algo, const unsigned char *hd, unsigned char *hw); 00483 virtual void DynamicHD(unsigned char *hd, const unsigned char *ed); 00484 virtual bool RomInit(void); 00485 virtual void Stepper(void); 00486 virtual void ReadHandler(unsigned char seg, unsigned short ea, unsigned char &op); 00487 virtual void TimerHandler(unsigned int num); 00488 virtual void AddMapCycles(unsigned int num) { AddCycles(num); } 00489 virtual unsigned int CpuCycles(void) { return Cycles(); } 00490 public: 00491 cN2Prov0101(int Id, int Flags); 00492 virtual bool PostProcAU(int id, unsigned char *data); 00493 virtual int ProcessBx(unsigned char *data, int len, int pos); 00494 virtual int ProcessEx(unsigned char *data, int len, int pos); 00495 virtual int RunEmu(unsigned char *data, int len, unsigned short load, unsigned short run, unsigned short stop, unsigned short fetch, int fetch_len); 00496 virtual void PostDecrypt(bool ecm) { PostDecryptSetup(ecm); } 00497 }; 00498 00499 static cN2ProvLinkReg<cN2Prov0101,0x0101,(N2FLAG_MECM|N2FLAG_POSTAU|N2FLAG_Bx|N2FLAG_Ex)> staticPL0101; 00500 00501 cN2Prov0101::cN2Prov0101(int Id, int Flags) 00502 :cN2Prov(Id,Flags) 00503 { 00504 mecmAddr[0]=0x91d7; mecmAddr[1]=0x92d7; mecmKeyId=0x106; 00505 seedSize=10; 00506 desSize=16; hwMapper=0; 00507 SetMapIdent(Id); 00508 hasReadHandler=true; 00509 } 00510 00511 void cN2Prov0101::DynamicHD(unsigned char *hd, const unsigned char *ed) 00512 { 00513 hd[5]=ed[5]; 00514 hd[6]=(ed[7]&0xEF) | ((ed[6]&0x40)>>2); 00515 hd[7]=ed[8]; 00516 hd[8]=(ed[9]&0x7F) | ((ed[6]&0x20)<<2); 00517 hd[9]=ed[6]&0x80; 00518 } 00519 00520 bool cN2Prov0101::Algo(int algo, const unsigned char *hd, unsigned char *hw) 00521 { 00522 if(algo!=0x40 && algo!=0x60) { 00523 PRINTF(L_SYS_ECM,"%04X: unknown MECM algo %02x",id,algo); 00524 return false; 00525 } 00526 if(!Init(id,102)) { 00527 PRINTF(L_SYS_ECM,"%04X: failed to initialize ROM",id); 00528 return false; 00529 } 00530 00531 unsigned char keyNr=(algo>>5)&0x01; 00532 unsigned char mecmCode[256]; 00533 GetMem(mecmAddr[keyNr],mecmCode,sizeof(mecmCode),0x80); 00534 cPlainKey *pk; 00535 unsigned char ideaKey[16]; 00536 if(!(pk=keys.FindKey('N',mecmKeyId,keyNr,sizeof(ideaKey)))) { 00537 PRINTF(L_SYS_KEY,"missing %04x %02x MECM key",mecmKeyId,keyNr); 00538 return false; 00539 } 00540 pk->Get(ideaKey); 00541 idea.SetEncKey(ideaKey,&ks); 00542 idea.Decrypt(mecmCode,sizeof(mecmCode),&ks,0); 00543 HEXDUMP(L_SYS_RAWECM,mecmCode,sizeof(mecmCode),"decrypted MECM code"); 00544 // check signature 00545 unsigned char data[256]; 00546 memcpy(data,mecmCode,sizeof(data)); 00547 RotateBytes(data,sizeof(data)); 00548 SHA1(data,sizeof(data)-8,data); 00549 RotateBytes(data,20); 00550 if(memcmp(data,mecmCode,8)) { 00551 PRINTF(L_SYS_ECM,"%04X: MECM %02x decrypt signature failed",id,keyNr); 00552 return false; 00553 } 00554 00555 memcpy(hw,hd,seedSize); 00556 ExpandInput(hw); 00557 00558 SetSp(0x0FFF,0x0EF8); 00559 ClearBreakpoints(); 00560 SetMem(0x0100,mecmCode+8,0x100-8); 00561 SetMem(0xa00,hd,seedSize); 00562 SetMem(0x0ba2,hw,0x80); 00563 AddBreakpoint(0x0000); 00564 AddRomCallbacks(); 00565 SetPc(0x0100); 00566 while(!Run(100000)) { 00567 if(GetPc()==0x0000) { 00568 GetMem(0x0ba2,hw,0x80); 00569 return true; 00570 } 00571 else if(!RomCallbacks()) return false; 00572 } 00573 00574 /* 00575 if(algo==0x40) { 00576 const int hwCount=2; 00577 memcpy(hw,hd,hwCount+1); 00578 ExpandInput(hw); 00579 hw[0x18]|=1; hw[0x40]|=1; 00580 DoMap(SETSIZE,0,2); 00581 DoMap(IMPORT_A,hw,3); 00582 DoMap(IMPORT_D,hw+24); 00583 DoMap(0x3b); 00584 DoMap(EXPORT_C,hw); 00585 DoMap(IMPORT_A,hw+40,3); 00586 DoMap(IMPORT_D,hw+64); 00587 DoMap(0x3b); 00588 DoMap(EXPORT_C,hw+40); 00589 DoMap(0x43); 00590 DoMap(0x44,hw); 00591 DoMap(0x44,hw+64); 00592 memcpy(&hw[0],&hw[64+4],hwCount); 00593 memset(&hw[hwCount],0,128-hwCount); 00594 return true; 00595 } 00596 else if(algo==0x60) { // map 4D/4E/57 00597 hw[127]|=0x80; hw[0]|=0x01; 00598 DoMap(SETSIZE,0,16); 00599 DoMap(IMPORT_A,hw); 00600 DoMap(0x4d); 00601 DoMap(0x4e); 00602 DoMap(EXPORT_A,hw); 00603 RotateBytes(hw,16); 00604 DoMap(IMPORT_A,hw); 00605 DoMap(0x4e); 00606 DoMap(EXPORT_A,hw); 00607 DoMap(0x57,hw); 00608 return true; 00609 } 00610 00611 PRINTF(L_SYS_ECM,"%04X: unknown MECM algo %02x",id,algo); 00612 */ 00613 return false; 00614 } 00615 00616 bool cN2Prov0101::PostProcAU(int id, unsigned char *data) 00617 { 00618 if(data[1]&0x5f) return false; 00619 return true; 00620 } 00621 00622 bool cN2Prov0101::RomInit(void) 00623 { 00624 if(!AddMapper(hwMapper=new cMapMemHW(),HW_OFFSET,HW_REGS,0x00)) return false; 00625 SetPc(0x4000); 00626 SetSp(0x0FFF,0x0FE0); 00627 ClearBreakpoints(); 00628 AddBreakpoint(0x537d); 00629 AddBreakpoint(0x8992); 00630 AddBreakpoint(0xA822); 00631 while(!Run(7000)) { 00632 switch(GetPc()) { 00633 case 0x537d: 00634 PRINTF(L_SYS_EMU,"%04x: ROM init successfull",id); 00635 return true; 00636 default: 00637 PRINTF(L_SYS_EMU,"%04x: ROM init failed: unexpected breakpoint",id); 00638 break; 00639 } 00640 } 00641 return false; 00642 } 00643 00644 bool cN2Prov0101::ProcessMap(int f) 00645 { 00646 unsigned short addr; 00647 unsigned char tmp[512]; 00648 int l=GetOpSize(Get(0x48)); 00649 int dl=l<<3; 00650 00651 switch(f) { 00652 case SETSIZE: 00653 DoMap(f,0,Get(0x48)); 00654 break; 00655 case IMPORT_J: 00656 l=1; dl=1<<3; 00657 // fall throught 00658 case IMPORT_A: 00659 case IMPORT_B: 00660 case IMPORT_C: 00661 case IMPORT_D: 00662 case IMPORT_LAST: 00663 addr=HILO(0x44); 00664 GetMem(addr,tmp,dl,0); DoMap(f,tmp,l); 00665 break; 00666 case EXPORT_J: 00667 l=1; dl=1<<3; 00668 // fall throught 00669 case EXPORT_A: 00670 case EXPORT_B: 00671 case EXPORT_C: 00672 case EXPORT_D: 00673 case EXPORT_LAST: 00674 addr=HILO(0x44); 00675 DoMap(f,tmp,l); SetMem(addr,tmp,dl,0); 00676 break; 00677 case SWAP_A: 00678 case SWAP_B: 00679 case SWAP_C: 00680 case SWAP_D: 00681 addr=HILO(0x44); 00682 GetMem(addr,tmp,dl,0); DoMap(f,tmp,l); SetMem(addr,tmp,dl,0); 00683 break; 00684 case CLEAR_A: 00685 case CLEAR_B: 00686 case CLEAR_C: 00687 case CLEAR_D: 00688 case COPY_A_B: 00689 case COPY_B_A: 00690 case COPY_A_C: 00691 case COPY_C_A: 00692 case COPY_C_D: 00693 case COPY_D_C: 00694 DoMap(f); 00695 break; 00696 case 0x22: 00697 DoMap(f,0,(Get(0x4a)<<8)|Get(0x49)); 00698 break; 00699 case 0x29: 00700 case 0x2a: 00701 DoMap(f,tmp); 00702 Set(0x4b,tmp[0]); 00703 break; 00704 case 0x3c: 00705 case 0x3e: 00706 GetMem(HILO(0x44),tmp,dl,0); 00707 DoMap(f,tmp,Get(0x48)); 00708 break; 00709 case 0x2e: 00710 case 0x2f: 00711 case 0x32: 00712 case 0x39: 00713 case 0x3b: 00714 case 0x3d: 00715 GetMem(HILO(0x44),tmp,dl,0); 00716 DoMap(f,tmp,l); 00717 break; 00718 case 0x21: 00719 case 0x23: 00720 case 0x25: 00721 case 0x30: 00722 case 0x31: 00723 case 0x36: 00724 case 0x38: 00725 case 0x3a: 00726 case 0x43: 00727 DoMap(f); 00728 break; 00729 case 0x44: 00730 case 0x45: 00731 GetMem(0x400,tmp,64,0); 00732 GetMem(0x440,tmp+64,28,0); 00733 DoMap(f,tmp,l); 00734 SetMem(0x400,tmp,64,0); 00735 SetMem(0x440,tmp+64,28,0); 00736 break; 00737 case 0x46: 00738 GetMem(HILO(0x44),tmp,8,0); 00739 DoMap(f,tmp); 00740 break; 00741 case 0x4d: 00742 DoMap(f,tmp,-((Get(0x48)<<16)|(Get(0x4a)<<8)|Get(0x49))); 00743 if(*tmp==0xff) 00744 Set(0x4b,0x00); 00745 else { 00746 Set(0x4b,*tmp); 00747 SetMem(0x400,tmp+1,wordsize*8>53?wordsize*8:53,0x00); 00748 } 00749 break; 00750 case 0x4e: 00751 case 0x4f: 00752 GetMem(0x400,tmp+1,53,0); 00753 if(f==0x4f) GetMem(HILO(0x44),tmp+54,8,0); 00754 DoMap(f,tmp); 00755 Set(0x4b,*tmp); 00756 SetMem(0x400,tmp+1,53,0); 00757 break; 00758 case 0x57: 00759 addr=HILO(0x46); 00760 l=wordsize; if(l<2 || l>4) l=4; 00761 dl=l<<3; 00762 for(int i=0; i<6; i++) GetMem(HILO(addr+i*2),tmp+i*dl,dl,0); 00763 DoMap(f,tmp); 00764 SetMem(0x400,tmp,0x40,0); 00765 memset(tmp,0,11*32); 00766 SetMem(0x440,tmp,11*32,0); 00767 break; 00768 default: 00769 PRINTF(L_SYS_EMU,"%04x: map call %02x not emulated",id,f); 00770 return false; 00771 } 00772 c6805::a=0; c6805::x=0; c6805::y=0; 00773 return true; 00774 } 00775 00776 bool cN2Prov0101::ProcessDESMap(int f) 00777 { 00778 unsigned char data[16]; 00779 switch(f) { 00780 case 0x05: // 3DES encrypt 00781 DES_ecb2_encrypt(DES_CAST(desblock),DES_CAST(desblock),&desks1,&desks2,DES_ENCRYPT); 00782 break; 00783 case 0x06: // 3DES decrypt 00784 DES_ecb2_encrypt(DES_CAST(desblock),DES_CAST(desblock),&desks1,&desks2,DES_DECRYPT); 00785 break; 00786 case 0x07: 00787 Set(0x2d,0x02); //XXX quick-hack or the real thing?? 00788 break; 00789 case 0x0b: // load DES data block from memory 00790 GetMem(HILO(0x25),desblock,8,Get(0x24)); 00791 break; 00792 case 0x0c: // store DES data block to memory 00793 SetMem(HILO(0x2b),desblock,8,Get(0x2a)); 00794 break; 00795 case 0x0e: // get DES key1 and key2 00796 GetMem(HILO(0x25),data,8,Get(0x24)); 00797 DES_key_sched((DES_cblock *)data,&desks1); 00798 GetMem(HILO(0x28),data,8,Get(0x27)); 00799 DES_key_sched((DES_cblock *)data,&desks2); 00800 break; 00801 case 0x0f: // set DES size 00802 desSize=Get(0x2d); 00803 if(desSize!=0x10 && desSize!=0x18) { 00804 PRINTF(L_SYS_EMU,"%04x: invalid DES key size %02x",id,desSize); 00805 return false; 00806 } 00807 break; 00808 default: 00809 PRINTF(L_SYS_EMU,"%04x: DES map call %02x not emulated",id,f); 00810 return false; 00811 } 00812 return true; 00813 } 00814 00815 bool cN2Prov0101::RomCallbacks(void) 00816 { 00817 bool dopop=true; 00818 unsigned int ea=GetPc(); 00819 if(ea&0x8000) ea|=(cr<<16); 00820 switch(ea) { 00821 case 0x3840: //MAP Handler 00822 case 0x00A822: 00823 if(!ProcessMap(a)) return false; 00824 if(Interrupted()) dopop=false; 00825 break; 00826 case 0x3844: //DES Handler 00827 case 0x008992: 00828 if(!ProcessDESMap(a)) return false; 00829 break; 00830 case 0x5F23: //Erase_RAM_and_Hang 00831 case 0x5F27: //Erase_RAM_and_Hang_Lp 00832 case 0x5F5E: //BrainDead 00833 PRINTF(L_SYS_EMU,"%04x: emu hung at %04x",id,ea); 00834 return false; 00835 case 0x70A6: //Write_Row_EEP_RC2_Len_A_To_RC1 00836 { 00837 unsigned short rc1=HILO(0x47); 00838 unsigned short rc2=HILO(0x4a); 00839 for(int i=0; i<a; i++) Set(0x80,rc1++,Get(dr,rc2++)); 00840 Set(0x4a,rc2>>8); 00841 Set(0x4b,rc2&0xff); 00842 break; 00843 } 00844 case 0x7BFE: //Write_Row_EEPROM_A_from_X_to_RC1 00845 { 00846 unsigned short rc1=HILO(0x47); 00847 unsigned short rc2=c6805::x; 00848 for(int i=0; i<a; i++) Set(0x80,rc1++,Get(rc2++)); 00849 break; 00850 } 00851 case 0x7CFF: //UPDATE_USW_03DD_03DE 00852 Set(0x30E8,Get(0x03DD)); 00853 Set(0x30E9,Get(0x03DE)); 00854 break; 00855 case 0x00A23C: //IDEA_Generate_Expanded_Key 00856 { 00857 unsigned char key[16]; 00858 GetMem(0x0a20,key,16); 00859 idea.SetEncKey(key,&ks); 00860 break; 00861 } 00862 case 0x00A2E9: //IDEA_Cypher 00863 { 00864 unsigned char data[8]; 00865 GetMem(0x070,data,8); 00866 idea.Encrypt(data,8,data,&ks,0); 00867 SetMem(0x070,data,8); 00868 break; 00869 } 00870 default: 00871 PRINTF(L_SYS_EMU,"%04X: unknown ROM breakpoint %04x",id,ea); 00872 return false; 00873 } 00874 if(dopop) { 00875 if(ea>=0x8000) PopCr(); 00876 PopPc(); 00877 } 00878 return true; 00879 } 00880 00881 void cN2Prov0101::AddRomCallbacks(void) 00882 { 00883 AddBreakpoint(0xA822); // map handler 00884 AddBreakpoint(0x3840); 00885 AddBreakpoint(0x3844); 00886 AddBreakpoint(0xA23C); //IDEA 00887 AddBreakpoint(0xA2E9); 00888 AddBreakpoint(0x70A6); 00889 AddBreakpoint(0x7BFE); 00890 AddBreakpoint(0x7CFF); 00891 AddBreakpoint(0x5F23); 00892 AddBreakpoint(0x5F27); 00893 AddBreakpoint(0x5F5E); 00894 } 00895 00896 int cN2Prov0101::ProcessBx(unsigned char *data, int len, int pos) 00897 { 00898 if(Init(id,102)) { 00899 SetMem(0x92,data+pos-1,len-pos+1); 00900 SetPc(0x93); 00901 SetSp(0x0FFF,0x0EF8); 00902 ClearBreakpoints(); 00903 AddBreakpoint(0x9569); 00904 AddBreakpoint(0x0000); 00905 AddRomCallbacks(); 00906 while(!Run(1000)) { 00907 if(GetPc()==0x9569) { 00908 GetMem(0x80,data,len); 00909 return a; 00910 } 00911 else if(GetPc()==0x0000) break; 00912 else if(!RomCallbacks()) break; 00913 } 00914 } 00915 return -1; 00916 } 00917 00918 int cN2Prov0101::ProcessEx(unsigned char *data, int len, int pos) 00919 { 00920 if(Init(id,102)) { 00921 SetMem(0x80,data,len); 00922 SetPc(0x9591); 00923 SetSp(0x0FFF,0x0EF8); 00924 Push(0x99); //push the bug-table return onto the stack 00925 Push(0x95); 00926 Push(0x00); 00927 Set(0x00,0x62,0x26); 00928 Set(0x00,0x63,0x02); 00929 Set(0x00,0x03d3,len-0x12); 00930 ClearBreakpoints(); 00931 AddBreakpoint(0x9569); 00932 AddBreakpoint(0x9599); 00933 AddRomCallbacks(); 00934 while(!Run(10000)) { 00935 if(GetPc()==0x9569) { 00936 GetMem(0x80,data,len); 00937 return max((int)a,6); 00938 } 00939 else if(GetPc()==0x9599) break; 00940 else if(!RomCallbacks()) break; 00941 } 00942 } 00943 return -1; 00944 } 00945 00946 int cN2Prov0101::RunEmu(unsigned char *data, int len, unsigned short load, unsigned short run, unsigned short stop, unsigned short fetch, int fetch_len) 00947 { 00948 if(Init(id,102)) { 00949 SetSp(0x0FFF,0x0EF8); 00950 SetMem(load,data,len); 00951 SetPc(run); 00952 ClearBreakpoints(); 00953 AddBreakpoint(stop); 00954 if(stop!=0x0000) AddBreakpoint(0x0000); 00955 AddRomCallbacks(); 00956 while(!Run(100000)) { 00957 if(GetPc()==0x0000 || GetPc()==stop) { 00958 GetMem(fetch,data,fetch_len); 00959 return 1; 00960 } 00961 else if(!RomCallbacks()) break; 00962 } 00963 } 00964 return -1; 00965 } 00966 00967 void cN2Prov0101::ReadHandler(unsigned char seg, unsigned short ea, unsigned char &op) 00968 { 00969 if(ea==0x2f70) op=random()&0xFF; 00970 else if(ea==0x2f71) { 00971 unsigned int n=random()&0xFF; 00972 unsigned int cy=Cycles(); 00973 if(cy>rndtime && cy<=rndtime+4) { 00974 unsigned int o=sn8(rnd); 00975 n=(n&0xE3) | (o&4) | ((o>>1)&16) | ((o^(o>>1))&8); 00976 } 00977 op=rnd=n; rndtime=cy; 00978 } 00979 } 00980 00981 void cN2Prov0101::TimerHandler(unsigned int num) 00982 { 00983 if(hwMapper) { 00984 int mask=hwMapper->AddCycles(num); 00985 if(mask) DisableTimers(13); 00986 for(int t=0; mask; mask>>=1,t++) 00987 if(mask&1) { 00988 if(t==2) { 00989 PRINTF(L_SYS_EMU,"0101: Timer interrupt %u @ %04x",t,GetPc()); 00990 RaiseException(9); 00991 if(Interruptible()) throw(t); 00992 } 00993 } 00994 } 00995 } 00996 00997 void cN2Prov0101::Stepper(void) 00998 { 00999 unsigned short pc=GetPc(); 01000 if(pc>=0x93 && pc<=0xE0) { // pc in EMM data 01001 unsigned char op=Get(pc); 01002 if((op&0xF0)==0x00) { // current opcode BRCLR/BRSET 01003 int fake=0; // 1=branch -1=non-branch 01004 if(Get(pc+3)==0x81) // next opcode == RTS 01005 fake=1; // fake branch 01006 else { 01007 unsigned char off=Get(pc+2); 01008 unsigned short target=pc+3+off; 01009 if(off&0x80) target-=0x100; 01010 if(Get(target)==0x81) // branch target == RTS 01011 fake=-1; // fake non-branch 01012 } 01013 if(fake) { 01014 unsigned short ea=Get(pc+1); 01015 unsigned char val=Get(dr,ea); 01016 int bit=1<<((op&0xF)>>1); 01017 // set/clr bit according to fake-mode and opcode 01018 if((fake>0 && (op&0x01)) || (fake<0 && !(op&0x01))) { 01019 if(val&bit) loglb->Printf("*"); 01020 val&=~bit; 01021 } 01022 else { 01023 if(!(val&bit)) loglb->Printf("*"); 01024 val|=bit; 01025 } 01026 Set(dr,ea,val); 01027 } 01028 } 01029 } 01030 } 01031 01032 // -- cN2Prov0901 -------------------------------------------------------------- 01033 01034 class cN2Prov0901 : public cN2Prov0101 { 01035 public: 01036 cN2Prov0901(int Id, int Flags); 01037 }; 01038 01039 static cN2ProvLinkReg<cN2Prov0901,0x0901,(N2FLAG_MECM|N2FLAG_POSTAU|N2FLAG_Bx|N2FLAG_Ex)> staticPL0901; 01040 01041 cN2Prov0901::cN2Prov0901(int Id, int Flags) 01042 :cN2Prov0101(Id,Flags) 01043 { 01044 mecmAddr[0]=0x91f5; mecmAddr[1]=0x92f5; mecmKeyId=0x907; 01045 }