SASC-NG
DVBSoftCAM

nagra2-0101.c

Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines