From: leslie Date: Sat, 25 Jul 2009 07:38:36 +0000 (+0800) Subject: nagra: a bunch of updates, mainly map related (emunation) X-Git-Tag: 0.9.3~10 X-Git-Url: http://www.vanbest.org/gitweb/?a=commitdiff_plain;h=f9957dbc8dc1013fa8f41cb5b0131c9c4fc9bcb0;p=sasc-ng.git nagra: a bunch of updates, mainly map related (emunation) --- diff --git a/systems/nagra/cpu.c b/systems/nagra/cpu.c index 5afd70e..05c3044 100644 --- a/systems/nagra/cpu.c +++ b/systems/nagra/cpu.c @@ -140,15 +140,16 @@ void cMapEeprom::Set(unsigned short ea, unsigned char val) #define PAGEOFF(ea,s) (((ea)&0x8000) ? pageMap[s]:0) -c6805::c6805(void) { +c6805::c6805(void) +{ cc.c=0; cc.z=0; cc.n=0; cc.i=0; cc.h=0; cc.v=1; pc=0; a=0; x=0; y=0; cr=dr=0; sp=spHi=0x100; spLow=0xC0; hasReadHandler=hasWriteHandler=false; exptBase=0x4000; + ResetCycles(); ClearExceptions(); ClearBreakpoints(); InitMapper(); - ResetCycles(); memset(stats,0,sizeof(stats)); loglb=new cLineBuff(128); } @@ -324,7 +325,7 @@ void c6805::RaiseException(int num) void c6805::ClearExceptions(void) { - exptPending=false; timerDisable=0; + exptPending=false; exptReady=true; timerDisable=0; for(int i=0; idenom) { unsigned char r=0; - while(denom>=r) { cycles+=1; r=(r<<1)|((num&0x80)>>7); num<<=1; } + while(denom>=r) { counts[1]++; r=(r<<1)|((num&0x80)>>7); num<<=1; } } residues[i]%=primes[i]; - if(residues[i]==0) { cycles+=13; isPrime=false; } + if(residues[i]==0) { counts[2]++; isPrime=false; } } } while(!isPrime); + cycles=1290+1465*counts[0]+counts[1]+13*counts[2]; } bool cMap0101::Map(int f, unsigned char *data, int l) @@ -190,46 +205,21 @@ bool cMap0101::Map(int f, unsigned char *data, int l) cycles=898; break; case 0x22: -// START INCOMPLETE FIX - BN_zero(B); - BN_set_bit(B,80); - AddMapCycles(644); - BN_zero(B); - BN_set_bit(B,96); - AddMapCycles(76); -// END INCOMPLETE FIX if(BN_is_zero(D)) { cycles=639-6; break; } l&=0x1fff; + AddMapCycles(376); + BN_zero(B); + AddMapCycles(l>=(BN_num_bits(D)-1)/64*64 ? 244 : 210); BN_one(B); + B.SetPos(1); + AddMapCycles(17); + for(int i=2; i<=8; i++) { B.SetPos(i); AddMapCycles(9); } + AddMapCycles(44); BN_mod_lshift(B,B,l,D,ctx); - if(l<64) - cycles=927+(l&7)*9; - else { - div_t val=div(l-64,2046); - int j=16*((val.rem+1)/2) + (val.rem>4?val.rem-7:val.rem-12)/4; - cycles=1086 + j - ((j-2)%5) + 16923*val.quot - ((4*val.quot-2)%5); - } break; case 0x23: -// START FIX - { - cBN s,x,y; - BN_copy(s,D); - BN_rshift(s,s,64+ 1 *8); - BN_lshift(s,s,64); - BN_copy(x,D); - BN_mask_bits(x,64); - BN_copy(y,D); - BN_rshift(y,y,64); - BN_mask_bits(y,1*8); - BN_lshift(y,y,128-1*8); - BN_copy(D,s); - BN_add(D,D,x); - BN_add(D,D,y); - } - BN_zero(B); - BN_set_bit(B,88); -// END FIX + AddMapCycles(169); + IMonInit0(); break; case 0x25: AddMapCycles(254); @@ -243,8 +233,8 @@ bool cMap0101::Map(int f, unsigned char *data, int l) { BN_add(B,B,C); bool b=BN_is_bit_set(B,wordsize<<6); - if(data) data[0]=b; if(b) BN_mask_bits(B,wordsize<<6); + if(data) data[0]=b; cycles=501+(8*wordsize+3)/5*5-6; break; } @@ -256,45 +246,51 @@ bool cMap0101::Map(int f, unsigned char *data, int l) break; } case 0x2e: -// START INCOMPLETE FIX - H.GetLE(data,16); - BN_rshift(H,H,64); - BN_lshift(H,H,64); - BN_add(H,J,H); - BN_rshift(H,H,1<<3); - BN_copy(J,H); - BN_mask_bits(J,64); - cycles=864; -// END INCOMPLETE FIX - break; case 0x2F: -// START INCOMPLETE FIX - H.GetLE(data,16); - BN_rshift(H,H,64); - BN_lshift(H,H,64); - BN_add(H,H,J); - BN_rshift(J,H,8); - BN_mask_bits(J,64); - cycles=808; -// END INCOMPLETE FIX + if(l<=0) { cycles+=4; l=wordsize; } + else if(l>17) { cycles+=5; l=17; } + scalar.GetLE(data,l<<3); + AddMapCycles(617+30*wordsize); + for(int i=0; iwordsize) { l=wordsize; cycles+=l>17 ? 9:4; } - cBN scalar; + if(f==0x46) l=1; else l=sl; + if(l<=0) { l=wordsize; cycles+=4; } + else if(l>wordsize) { l=wordsize; cycles+=l>17 ? 9:4; } scalar.GetLE(data,l<<3); - AddMapCycles(441); + int sbits=BN_num_bits(scalar); + cycles+=3848+((sbits-1)/8)*650 - 11; + int msb=data[(sbits-1)/8]; + for(int i=7; i>=1; --i) if(msb&(1<=1; --i) if(msb&(1<4) l=4; WS_START(l); l<<=3; @@ -423,6 +398,7 @@ bool cMap0101::Map(int f, unsigned char *data, int l) BN_zero(Px); BN_copy(Py,y); BN_zero(Qz); + MakeJ0(J,D); } else { CurveInit(a); @@ -450,7 +426,7 @@ bool cMap0101::Map(int f, unsigned char *data, int l) BN_mask_bits(Px,32); BN_lshift(b,Qz,32); BN_add(Px,Px,b); - BN_mask_bits(Px,128); + BN_mask_bits(Px,l<<3); AddP(0); } } @@ -462,6 +438,7 @@ bool cMap0101::Map(int f, unsigned char *data, int l) BN_copy(Px,x); BN_copy(Py,y); BN_zero(Qz); + MakeJ0(J,D); } memset(data,0,0x40); Px.PutLE(&data[0x00],l); @@ -554,7 +531,7 @@ bool cN2Prov0101::Algo(int algo, const unsigned char *hd, unsigned char *hw) unsigned char keyNr=(algo>>5)&0x01; unsigned char mecmCode[256]; - GetMem(mecmAddr[keyNr],mecmCode,256,0x80); + GetMem(mecmAddr[keyNr],mecmCode,sizeof(mecmCode),0x80); cPlainKey *pk; unsigned char ideaKey[16]; if(!(pk=keys.FindKey('N',mecmKeyId,keyNr,sizeof(ideaKey)))) { @@ -563,11 +540,7 @@ bool cN2Prov0101::Algo(int algo, const unsigned char *hd, unsigned char *hw) } pk->Get(ideaKey); idea.SetEncKey(ideaKey,&ks); - for(int i=0x100-8; i>=8; i-=8) { - idea.Encrypt(mecmCode+i,8,mecmCode+i,&ks,0); - xxor(mecmCode+i,8,mecmCode+i,mecmCode+i-8); - } - idea.Encrypt(mecmCode,8,mecmCode,&ks,0); + idea.Decrypt(mecmCode,sizeof(mecmCode),&ks,0); HEXDUMP(L_SYS_RAWECM,mecmCode,sizeof(mecmCode),"decrypted MECM code"); // check signature unsigned char data[256]; @@ -576,8 +549,8 @@ bool cN2Prov0101::Algo(int algo, const unsigned char *hd, unsigned char *hw) SHA1(data,sizeof(data)-8,data); RotateBytes(data,20); if(memcmp(data,mecmCode,8)) { - PRINTF(L_SYS_ECM,"%04X: MECM %02x decrypt signature failed",id,keyNr); - return false; + PRINTF(L_SYS_ECM,"%04X: MECM %02x decrypt signature failed",id,keyNr); + return false; } memcpy(hw,hd,seedSize); @@ -722,7 +695,7 @@ bool cN2Prov0101::ProcessMap(int f) DoMap(f); break; case 0x22: - DoMap(f,tmp,(Get(0x48)<<16)|(Get(0x4a)<<8)|Get(0x49)); + DoMap(f,0,(Get(0x4a)<<8)|Get(0x49)); break; case 0x29: case 0x2a: @@ -752,27 +725,36 @@ bool cN2Prov0101::ProcessMap(int f) case 0x38: case 0x3a: case 0x43: - case 0x4f: DoMap(f); break; case 0x44: case 0x45: GetMem(0x400,tmp,64,0); + GetMem(0x440,tmp+64,28,0); DoMap(f,tmp,l); - SetMem(0x440,tmp,20,0); - break; + SetMem(0x400,tmp,64,0); + SetMem(0x440,tmp+64,28,0); + break; case 0x46: GetMem(HILO(0x44),tmp,8,0); - DoMap(f,tmp,l); + DoMap(f,tmp); break; case 0x4d: - DoMap(f,tmp,-((Get(0x48)<<16)|(Get(0x49)<<8)|Get(0x4a))); - SetMem(0x400,tmp,53,0); + DoMap(f,tmp,-((Get(0x48)<<16)|(Get(0x4a)<<8)|Get(0x49))); + if(*tmp==0xff) + Set(0x4b,0x00); + else { + Set(0x4b,*tmp); + SetMem(0x400,tmp+1,wordsize*8>53?wordsize*8:53,0x00); + } break; case 0x4e: - GetMem(0x400,tmp,53,0); + case 0x4f: + GetMem(0x400,tmp+1,53,0); + if(f==0x4f) GetMem(HILO(0x44),tmp+54,8,0); DoMap(f,tmp); - SetMem(0x400,tmp,53,0); + Set(0x4b,*tmp); + SetMem(0x400,tmp+1,53,0); break; case 0x57: addr=HILO(0x46); @@ -1001,9 +983,9 @@ void cN2Prov0101::TimerHandler(unsigned int num) { if(hwMapper) { int mask=hwMapper->AddCycles(num); + if(mask) DisableTimers(13); for(int t=0; mask; mask>>=1,t++) if(mask&1) { - DisableTimers(11); if(t==2) { PRINTF(L_SYS_EMU,"0101: Timer interrupt %u @ %04x",t,GetPc()); RaiseException(9); diff --git a/systems/nagra/nagra2-0501.c b/systems/nagra/nagra2-0501.c index 80a01e8..ee826ab 100644 --- a/systems/nagra/nagra2-0501.c +++ b/systems/nagra/nagra2-0501.c @@ -97,6 +97,7 @@ bool cN2Prov0501::Algo(int algo, const unsigned char *hd, unsigned char *hw) DoMap(EXPORT_C,hw+0x20); DoMap(0x43); DoMap(0x44,hw); + memcpy(hw,hw+64,20); hw[0]&=7; DoMap(EXPORT_B,hw+3); memset(hw+3+0x20,0,128-(3+0x20)); diff --git a/systems/nagra/nagra2.c b/systems/nagra/nagra2.c index a510fe8..056490e 100644 --- a/systems/nagra/nagra2.c +++ b/systems/nagra/nagra2.c @@ -19,6 +19,7 @@ #include #include +#include #include "system.h" #include "opts.h" @@ -34,43 +35,96 @@ cN2Timer::cN2Timer(void) { - cycles=0; ctrl=0; divisor=1; remainder=-1; latch=0xFF; + cycles=intrCycles=delayInterrupt=0; ctrl=0; val=0; divisor=0; invDivisor=0; latch=0xFF; + timerBugged=false; } bool cN2Timer::AddCycles(unsigned int count) { - bool irq=false; if(Running()) { - bool stop=false; - remainder+=count; - if(remainder>=divisor) { - cycles-=remainder/divisor; - remainder%=divisor; + cycles+=count; + if(!delayInterrupt && InterruptSet() && cycles>=intrCycles) { + delayInterrupt=intrCycles-cycles+3; + if(delayInterrupt<0) delayInterrupt=count; else delayInterrupt+=count; + intrCycles=0; + if((ctrl&tmCONTINUOUS)) Update(); } - if(cycles<0 || (cycles==0 && remainder>=2)) - stop=true; - if(ctrl&tmCONTINUOUS) { - while(cycles<0) cycles+=latch+1; + } + if(delayInterrupt) { + delayInterrupt-=count; + if(delayInterrupt<0) delayInterrupt=0; + if(!delayInterrupt) { + Update(); + return true; } - else if(stop) { - PRINTF(L_SYS_EMU,"n2timer %d: timer stop (cycles=%d remainder=%d)",nr,cycles,remainder); - cycles=0; - Stop(); + } + return false; +} + +double cN2Timer::GetDivisor(void) +{ + int prescalar=((ctrl&0x38)>>3)+1; + double divisor=pow(4.0,prescalar); + double multiplier; + // multipliers for 0 and 2 aren't correct yet + switch((ctrl&0xc0)>>6) { + case 0: multiplier=10.3f; break; + case 1: multiplier= 1.0f; break; + case 2: multiplier=6.375f; break; + default:multiplier=0; + } + return divisor*multiplier; +} + +void cN2Timer::Update(void) +{ + int rlatch=latch; + if(divisor) { + if(timerBugged && cycles>=0x100*divisor) { + timerBugged=false; + cycles-=0x101*divisor; } - if((ctrl&tmINTERRUPT) && stop) { - PRINTF(L_SYS_EMU,"n2timer %d: IRQ triggered",nr); - irq=true; + if(timerBugged) rlatch=0x100; + + int v=cycles*invDivisor; + if(ctrl&tmCONTINUOUS) { + val=rlatch-(v % (rlatch+1)); + if(InterruptSet() && val==0) + intrCycles = cycles + (unsigned int)((val?val:latch)*divisor); + } + else { + // one-shot + if(v>=rlatch) { + val=0; + if(Running() && ((cycles-2)*invDivisor)>=rlatch) Stop(); + } + else + val=rlatch-v; } } - return irq; + else val=0; +} + +unsigned int cN2Timer::Cycles(void) +{ + if(Running()) Update(); + PRINTF(L_SYS_EMU,"n2timer %d: read %u %02x %02x = %02x",nr,cycles,ctrl&0xff,latch&0xff,val); + return val; +} + +unsigned char cN2Timer::Ctrl(void) +{ + if(Running()) Update(); + return ctrl; } void cN2Timer::Latch(unsigned char val) { if(!Running()) { latch=val; if(latch==0) latch=0x100; - cycles=latch; remainder=0; + cycles=0; ctrl|=tmLATCHED; + timerBugged=false; } } @@ -80,19 +134,30 @@ void cN2Timer::Ctrl(unsigned char val) ctrl=(ctrl&~tmRUNNING) | (val&tmRUNNING); if(!Running()) { Stop(); - PRINTF(L_SYS_EMU,"n2timer %d: stopped cycles=%x ctrl=%x",nr,cycles,ctrl); + --cycles; + Update(); + PRINTF(L_SYS_EMU,"n2timer %d: stopped cycles=%d (%02x) ctrl=%02x latch=%02x\n",nr,cycles,val,ctrl,latch&0xff); } } else { ctrl=(ctrl&~tmMASK) | (val&tmMASK); + divisor=GetDivisor(); + if(divisor) invDivisor=1.0/divisor; if(Running()) { - if((ctrl&0xc0)==0x40) divisor=1 << (2 *(1 + ((ctrl & 0x38) >> 3))); - else divisor=4; // This is wrong, but we haven't figured the right value out yet - if(divisor<=0) divisor=1; // sanity - if(!(ctrl&tmLATCHED)) cycles=(unsigned int)(cycles-1)&0xFF; - PRINTF(L_SYS_EMU,"n2timer %d: started latch=%x div=%d cycles=%x ctrl=%x",nr,latch,divisor,cycles,ctrl); - remainder=-1; - if(!(ctrl&tmCONTINUOUS) && cycles==0) ctrl&=~tmRUNNING; + if(!(ctrl&tmLATCHED) && divisor>0) { + if(this->val==0) { + timerBugged=true; + cycles=(unsigned int)divisor; + } + else { + cycles=(unsigned int)(((timerBugged?0x100:latch)-this->val+1) * divisor); + } + } + if((ctrl&tmINTERRUPT)) { + intrCycles=cycles+(unsigned int)((timerBugged?0x101:this->val?this->val:latch)*divisor); + if(nr==2) PRINTF(L_SYS_EMU,"n2timer %d: set for %u cycles (%02x %02x)",nr,intrCycles-cycles,Latch(),ctrl&0xff); + } + ctrl&=~tmLATCHED; } } } @@ -100,6 +165,7 @@ void cN2Timer::Ctrl(unsigned char val) void cN2Timer::Stop(void) { ctrl&=~(tmRUNNING|tmLATCHED); + if(delayInterrupt>=3) delayInterrupt=0; } // -- cN2CRC ------------------------------------------------------------------- @@ -287,7 +353,8 @@ bool cN2Emu::Init(int id, int romv) // -- cMapReg ------------------------------------------------------------------ -cMapReg::cMapReg(int *_defwordsize, int _maxwordsize) +cMapReg::cMapReg(int &_pos, int *_defwordsize, int _maxwordsize) +:pos(_pos) { SetDefWordSize(_defwordsize); SetMaxWordSize(_maxwordsize); @@ -357,6 +424,7 @@ void cMapReg::GetLE(const unsigned char *in, int n) if(wordsize>wsize) Commit(); reg.GetLE(in,wsize*8); Commit(wsize); + pos=0; } void cMapReg::PutLE(unsigned char *out, int n) @@ -364,6 +432,14 @@ void cMapReg::PutLE(unsigned char *out, int n) int wsize=OpWordSize(n<=0?n:(n+7)/8); Commit(); fullreg.PutLE(out,wsize*8); + if(pos&7) { + int s=pos/8*8; + for(int i=0; i<(pos&7); i++) { + unsigned char c=out[s]; + memmove(out+s,out+s+1,7); + out[s+7]=c; + } + } } void cMapReg::Set(BIGNUM *val, int wsize) @@ -392,9 +468,10 @@ void cMapReg::Clear(int wsize) // -- cMapMath ----------------------------------------------------------------- cMapMath::cMapMath(void) -:A(&wordsize),B(&wordsize),C(&wordsize),D(&wordsize),J(0,1),I(&wordsize) +:A(regpos,&wordsize),B(regpos,&wordsize),C(regpos,&wordsize),D(regpos,&wordsize),J(regpos,0,1),I(regpos,&wordsize) { wordsize=DEF_WORDSIZE; words=-1; + regpos=0; } bool cMapMath::ModAdd(BIGNUM *r, BIGNUM *a, BIGNUM *b, BIGNUM *d) @@ -539,27 +616,39 @@ void cMapCore::IMakeJ(void) void cMapCore::IMonInit0(int bits) { - AddMapCycles(132+(wordsize*8+3)/5*5); - if(BN_num_bits(D)>1) AddMapCycles(54); + AddMapCycles(114+(wordsize*8+3)/5*5); + D.SetPos(2); + AddMapCycles(18); + if(BN_num_bits(D)>1) + for(int i=3; i<=8; i++) { + D.SetPos(i); + AddMapCycles(9); + } + D.SetPos(0); if(!BN_is_zero(D)) { AddMapCycles(54); BN_zero(I); BN_set_bit(I,bits ? bits : 68*wordsize); BN_zero(B); - AddMapCycles(141+(wordsize*8+3)/5*5); - //BN_set_bit(B,64*(wordsize-1)); - // TEMP or not? - BN_set_bit(B,64*(wordsize-1)+bits); - AddMapCycles(92+72*wordsize); + AddMapCycles(157+(wordsize*8+3)/5*5+72*(wordsize-1)); + BN_set_bit(B,64*(wordsize-1)); + B.SetPos(8*(wordsize-1)+1); + AddMapCycles(17); + for(int i=8*(wordsize-1)+2; i<=8*wordsize; i++) { + B.SetPos(i); + AddMapCycles(9); + } + B.SetPos(0); + AddMapCycles(68); BN_mod(B,I,D,ctx); AddMapCycles(639); } - AddMapCycles(52); - for(int i=0; i<4; i++) { - MonMul0(B,B,B,C,D,J,0); - AddMapCycles(96+6*(i>0)); - MonFin(B,D); - } + AddMapCycles(52); + for(int i=0; i<4; i++) { + MonMul0(B,B,B,C,D,J,0); + AddMapCycles(96+6*(i>0)); + MonFin(B,D); + } } void cMapCore::IMonInit(int bits) @@ -571,10 +660,12 @@ void cMapCore::IMonInit(int bits) void cMapCore::MonInit(int bits) { // Calculate J0 & H montgomery elements in J and B - MakeJ0(J,D); - BN_zero(I); - BN_set_bit(I,bits ? bits : 68*wordsize); - BN_mod(B,I,D,ctx); + MakeJ0(J,D,C); + if(!BN_is_zero(D)) { + BN_zero(I); + BN_set_bit(I,bits ? bits : 68*wordsize); + BN_mod(B,I,D,ctx); + } for(int i=0; i<4; i++) MonMul(B,B,B); } @@ -592,7 +683,13 @@ void cMapCore::MonExp(BIGNUM *scalar) void cMapCore::MonExpNeg(void) { - if(BN_is_zero(D)) { BN_set_word(A,1); return; } + if(BN_is_zero(D) || BN_is_word(D,2)) { + BN_one(A); + if(!BN_is_zero(D)) BN_zero(B); + return; + } + int bits=0; + for(int i=BN_num_bits(D)-1; i>=0; i--) if(BN_is_bit_set(D,i)) bits++; BN_copy(e,D); BN_mask_bits(e,8); // check LSB unsigned int n=BN_get_word(e); @@ -600,19 +697,15 @@ void cMapCore::MonExpNeg(void) if(n) BN_sub_word(e,0x02); // N -2 else BN_add_word(e,0xFE); // N + 254 ('carryless' -2) BN_copy(A,B); - for(int i=BN_num_bits(e)-2; i>-1; i--) { + for(int i=BN_num_bits(e)-2+(bits==1 && BN_num_bits(D)<=8); i>-1; i--) { MonMul(B,B,B); if(BN_is_bit_set(e,i)) MonMul(B,A,B); } - if(BN_is_bit_set(D,0)) { - int i; - for(i=BN_num_bits(D)-2; i>0; i--) if(BN_is_bit_set(D,i)) break; - if(i<=0) { - MonMul(B,B,B); - MonMul(B,A,B); - } + if(bits==2 && BN_is_bit_set(D,0)) { + MonMul(B,B,B); + MonMul(B,A,B); } - BN_set_word(A,1); + BN_one(A); MonMul(B,A,B); } @@ -747,7 +840,7 @@ void cMapCore::DoMap(int f, unsigned char *data, int l) interrupted=false; interruptible=true; try { if(!Map(f,data,l) && !MapGeneric(f,data,l)) - PRINTF(L_SYS_MAP,"%04x: unsupported call %02x",mapid,f); + PRINTF(L_SYS_MAP,"%04x: unsupported map call %02x",mapid,f); if(cycles) { unsigned int elapsed=CpuCycles()-startcycles; if(cycles>elapsed) AddMapCycles(cycles-elapsed); @@ -789,7 +882,7 @@ bool cMapCore::MapGeneric(int f, unsigned char *data, int l) case IMPORT_LAST: if(l>16) { l=1; cycles+=5; } else if(l<=0) l=1; - cycles=656+160*l-6; + cycles+=656+160*l-6; regs[last]->GetLE(data,(last==0?1:l)<<3); break; @@ -804,14 +897,14 @@ bool cMapCore::MapGeneric(int f, unsigned char *data, int l) case EXPORT_D: if(l>17) { l=17; cycles+=5; } else if(l<=0) { l=wordsize; cycles+=4; } - cycles=778+160*l-6; + cycles+=778+160*l-6; last=f-EXPORT_J; regs[last]->PutLE(data,l<<3); break; case EXPORT_LAST: if(l>16) { l=1; cycles+=5; } else if(l<=0) l=1; - cycles=668+160*l-6; + cycles+=668+160*l-6; regs[last]->PutLE(data,(last==0?1:l)<<3); break; @@ -853,32 +946,68 @@ bool cMapCore::MapGeneric(int f, unsigned char *data, int l) AddMapCycles(f==0x39?433:192); IMonInit(); if(f==0x39) { - I.GetLE(data,wordsize<<3); - MonMul(B,I,B); + scalar.GetLE(data,wordsize<<3); + MonMul(B,scalar,B); } else MonMul(B,A,B); + AddMapCycles(137); MonMul(B,A,B); break; case 0x43: // init SHA1 - SHA1_Init(&sctx); - break; case 0x44: // add 64 bytes to SHA1 buffer - RotateBytes(data,64); - SHA1_Update(&sctx,data,64); - BYTE4_LE(data ,sctx.h4); - BYTE4_LE(data+4 ,sctx.h3); - BYTE4_LE(data+8 ,sctx.h2); - BYTE4_LE(data+12,sctx.h1); - BYTE4_LE(data+16,sctx.h0); + if(f==0x43) { + l=0; + SHA1_Init(&sctx); + cycles=885; + } + else { + l=64; + RotateBytes(data,l); + sctx.h4=UINT32_LE(data+l+0x00); + sctx.h3=UINT32_LE(data+l+0x04); + sctx.h2=UINT32_LE(data+l+0x08); + sctx.h1=UINT32_LE(data+l+0x0c); + sctx.h0=UINT32_LE(data+l+0x10); + sctx.Nl=UINT32_LE(data+l+0x14); + sctx.Nh=UINT32_LE(data+l+0x18); + sctx.num=0; + SHA1_Update(&sctx,data,l); + memset(data,0,l); + cycles=65309; + } + if(data) { + BYTE4_LE(data+l+0x00,sctx.h4); + BYTE4_LE(data+l+0x04,sctx.h3); + BYTE4_LE(data+l+0x08,sctx.h2); + BYTE4_LE(data+l+0x0c,sctx.h1); + BYTE4_LE(data+l+0x10,sctx.h0); + BYTE4_LE(data+l+0x14,sctx.Nl); + BYTE4_LE(data+l+0x18,sctx.Nh); + } break; - case 0x45: // add wordsize bytes to SHA1 buffer and finalize SHA result - if(dl) { - if(dl>1) RotateBytes(data,dl); - SHA1_Update(&sctx,data,dl); + case 0x45: // add l bytes to SHA1 buffer and finalize SHA result + if(l<=0 || l>64) + cycles=465+5*(l>64); + else { + sctx.h4=UINT32_LE(data+0x40); + sctx.h3=UINT32_LE(data+0x44); + sctx.h2=UINT32_LE(data+0x48); + sctx.h1=UINT32_LE(data+0x4c); + sctx.h0=UINT32_LE(data+0x50); + sctx.Nl=UINT32_LE(data+0x54); + sctx.Nh=UINT32_LE(data+0x58); + sctx.Nl&=~0xff; + sctx.num=0; + if(l>1) RotateBytes(data,l); + SHA1_Update(&sctx,data,l); + SHA1_Final(data+0x40,&sctx); + RotateBytes(data+0x40,20); + BYTE4_LE(data+0x54,sctx.Nl); + BYTE4_LE(data+0x58,sctx.Nh); + memset(data,0,64); + cycles=65519+(64-l)*12+(l>=56)*64681-16*(l==64); } - SHA1_Final(data,&sctx); - RotateBytes(data,20); break; default: return false; @@ -1323,7 +1452,7 @@ void cSystemNagra2::ProcessEMM(int pid, int caid, unsigned char *buffer) if(emmP) emmP->PostDecrypt(false); HEXDUMP(L_SYS_RAWEMM,emmdata,cmdLen,"Nagra2 RAWEMM"); - id=(emmdata[8]<<8)+emmdata[9]; + if(buffer[0]==0x82) id=(emmdata[8]<<8)+emmdata[9]; LBSTARTF(L_SYS_EMM); bool contFail=false; for(int i=8+2+4+4; i0 ? wsize:DefWordSize(); return sz>maxwordsize ? maxwordsize:sz; } @@ -68,7 +68,7 @@ protected: void SetMaxWordSize(int max) { maxwordsize=max; } void SetDefWordSize(int *_defwordsize) { defwordsize=_defwordsize; } public: - cMapReg(int *_defwordsize=0, int _maxwordsize=DEF_MAXWORDSIZE); + cMapReg(int &_pos, int *_defwordsize=0, int _maxwordsize=DEF_MAXWORDSIZE); operator BIGNUM* () { return Value(); } BIGNUM *operator->() { return Value(); } BIGNUM *Value(int wsize=0, bool mask=false); @@ -78,6 +78,7 @@ public: void PutLE(unsigned char *out, int n=0); void Set(BIGNUM *val, int wsize); void Clear(int wsize); + void SetPos(int _pos) { pos=_pos; } }; // ---------------------------------------------------------------- @@ -90,8 +91,9 @@ private: cBN x, y, s; int words; protected: - int wordsize; - cMapReg A, B, C, D, J, I, H; + int wordsize, regpos; + cMapReg A, B, C, D, J, I; + cBN H, scalar; cBNctx ctx; SHA_CTX sctx; // stateless @@ -186,16 +188,23 @@ public: class cN2Timer { private: - int ctrl, divisor, cycles, remainder, latch, nr; + int ctrl, latch, nr, delayInterrupt; + unsigned char val; + unsigned int cycles, intrCycles; + double divisor, invDivisor; + bool timerBugged; enum { tmCONTINUOUS=0x01, tmRUNNING=0x02, tmINTERRUPT=0x04, tmMASK=0xFF, tmLATCHED=0x100 }; // bool Running(void) { return ctrl&tmRUNNING; } + bool InterruptSet(void) { return ctrl&tmINTERRUPT; } void Stop(void); + double GetDivisor(void); + void Update(void); public: cN2Timer(void); bool AddCycles(unsigned int count); - unsigned int Cycles(void) { return cycles; } - unsigned char Ctrl(void) { return ctrl&tmMASK; } + unsigned int Cycles(void); + unsigned char Ctrl(void); void Ctrl(unsigned char c); unsigned char Latch(void) { return latch&0xFF; } void Latch(unsigned char val);