📄 nagra2.c
字号:
/* * Softcam plugin to VDR (C++) * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */#include <stdlib.h>#include <string.h>#include "system.h"#include "opts.h"#include "log-core.h"#include "nagra.h"#include "nagra2.h"#define SYSTEM_NAME "Nagra2"#define SYSTEM_PRI -10// -- cN2Timer -----------------------------------------------------------------cN2Timer::cN2Timer(void){ cycles=0; ctrl=0; divisor=1; remainder=-1; latch=0xFF;}bool cN2Timer::AddCycles(unsigned int count){ bool irq=false; if(Running()) { bool stop=false; remainder+=count; if(remainder>=divisor) { cycles-=remainder/divisor; remainder%=divisor; } if(cycles<0 || (cycles==0 && remainder>=2)) stop=true; if(ctrl&tmCONTINUOUS) { while(cycles<0) cycles+=latch+1; } else if(stop) { PRINTF(L_SYS_EMU,"n2timer %d: timer stop (cycles=%d remainder=%d)",nr,cycles,remainder); cycles=0; Stop(); } if((ctrl&tmINTERRUPT) && stop) { PRINTF(L_SYS_EMU,"n2timer %d: IRQ triggered",nr); irq=true; } } return irq;}void cN2Timer::Latch(unsigned char val){ if(!Running()) { latch=val; if(latch==0) latch=0x100; cycles=latch; remainder=0; ctrl|=tmLATCHED; }}void cN2Timer::Ctrl(unsigned char val){ if(Running()) { ctrl=(ctrl&~tmRUNNING) | (val&tmRUNNING); if(!Running()) { Stop(); PRINTF(L_SYS_EMU,"n2timer %d: stopped cycles=%x ctrl=%x",nr,cycles,ctrl); } } else { ctrl=(ctrl&~tmMASK) | (val&tmMASK); 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; } }}void cN2Timer::Stop(void){ ctrl&=~(tmRUNNING|tmLATCHED);}// -- cN2CRC -------------------------------------------------------------------#define CRC_POLY 0x8408 // ccitt polycN2CRC::cN2CRC(void){ cycles=0; CRCpos=0; CRCtime=0; CRCin=0; CRCvalue=0xffff; CRCit=CRCCALC_DELAY+1; ctrl=CRC_DISABLED; GenTable();}void cN2CRC::AddCycles(unsigned int num){ cycles+=num;}void cN2CRC::GenTable(void){ for(int i=0; i<256; i++) { unsigned short c=i; for(int j=0; j<8; j++) c=(c>>1)^((c&1)?CRC_POLY:0); table[i]=c; }}void cN2CRC::Update(void){ if(!(ctrl&CRC_DISABLED) && CRCit<=CRCCALC_DELAY) { unsigned int it=CRCit; CRCit+=cycles-CRCtime; if(CRCit>CRCCALC_DELAY) // > instead of >= because of CRC_BUSY lockout CRCit=CRCCALC_DELAY+1; if(it==0 && CRCit>=CRCCALC_DELAY) CRCvalue=(CRCvalue>>8)^table[(CRCvalue^CRCin)&0xff]; else for(; it<CRCit && it<CRCCALC_DELAY; it++) CRCvalue=(CRCvalue>>1) ^ (((CRCvalue^(CRCin>>it))&1) ? CRC_POLY : 0); CRCtime=cycles; }}unsigned char cN2CRC::Ctrl(void){ Update(); unsigned char r=ctrl; if(CRCit<CRCCALC_DELAY) r|=CRC_BUSY; else r&=~CRC_BUSY; return r|0x80;}void cN2CRC::Ctrl(unsigned char c){ if(ctrl&CRC_DISABLED) { if(!(c&CRC_DISABLED)) { CRCvalue=0xffff; CRCpos=0; CRCtime=cycles; if(CRCit<=CRCCALC_DELAY) { CRCtime++; CRCit++; } } } else if(c&CRC_DISABLED) Update(); ctrl=c;}unsigned char cN2CRC::Data(void){ Update(); return (CRCvalue^0xffff)>>((CRCpos++&1)<<3);}void cN2CRC::Data(unsigned char d){ Update(); if(CRCit>CRCCALC_DELAY && !(ctrl&CRC_DISABLED)) { CRCin=d; CRCit=0; CRCtime=cycles; }}// -- cMapMemHW ----------------------------------------------------------------cMapMemHW::cMapMemHW(void):cMapMem(HW_OFFSET,HW_REGS){ for(int i=0; i<MAX_TIMERS; i++) timer[i].SetNumber(HW_NUM(i)); PRINTF(L_SYS_EMU,"mapmemhw: new HW map off=%04x size=%04x",offset,size);}int cMapMemHW::AddCycles(unsigned int num){ crc.AddCycles(num); int mask=0; for(int i=0; i<MAX_TIMERS; i++) if(timer[i].AddCycles(num)) mask|=1<<timer[i].Number(); return mask;}unsigned char cMapMemHW::Get(unsigned short ea){ if(ea<offset || ea>=offset+size) return 0; ea-=offset; switch(ea) { case HW_SECURITY: return (mem[ea]&0x70)|0x0F; case HW_TIMER0_CONTROL: case HW_TIMER1_CONTROL: case HW_TIMER2_CONTROL: return timer[TIMER_NUM(ea)].Ctrl(); case HW_TIMER0_DATA: case HW_TIMER1_DATA: case HW_TIMER2_DATA: return timer[TIMER_NUM(ea)].Cycles(); case HW_TIMER0_LATCH: case HW_TIMER1_LATCH: case HW_TIMER2_LATCH: return timer[TIMER_NUM(ea)].Latch(); case HW_CRC_CONTROL: return crc.Ctrl(); case HW_CRC_DATA: return crc.Data(); default: return mem[ea]; }}void cMapMemHW::Set(unsigned short ea, unsigned char val){ if(ea<offset || ea>=offset+size) return; ea-=offset; switch(ea) { case HW_TIMER0_CONTROL: case HW_TIMER1_CONTROL: case HW_TIMER2_CONTROL: timer[TIMER_NUM(ea)].Ctrl(val); break; case HW_TIMER0_LATCH: case HW_TIMER1_LATCH: case HW_TIMER2_LATCH: timer[TIMER_NUM(ea)].Latch(val); break; case HW_CRC_CONTROL: crc.Ctrl(val); break; case HW_CRC_DATA: crc.Data(val); break; default: mem[ea]=val; break; }}// -- cN2Emu -------------------------------------------------------------------cN2Emu::cN2Emu(void){ initDone=false;}bool cN2Emu::Init(int id, int romv){ if(!initDone) { ResetMapper(); char buff[256]; snprintf(buff,sizeof(buff),"ROM%d.bin",romv); // UROM 0x00:0x4000-0x7fff if(!AddMapper(new cMapRom(0x4000,buff,0x00000),0x4000,0x4000,0x00)) return false; // ROM00 0x00:0x8000-0xffff if(!AddMapper(new cMapRom(0x8000,buff,0x04000),0x8000,0x8000,0x00)) return false; // ROM01 0x01:0x8000-0xffff if(!AddMapper(new cMapRom(0x8000,buff,0x0C000),0x8000,0x8000,0x01)) return false; // ROM02 0x02:0x8000-0xbfff if(!AddMapper(new cMapRom(0x8000,buff,0x14000),0x8000,romv>=110?0x8000:0x4000,0x02)) return false; snprintf(buff,sizeof(buff),"EEP%02X_%d.bin",(id>>8)&0xFF|0x01,romv); // Eeprom00 0x00:0x3000-0x37ff OTP 0x80 //XXX if(!AddMapper(new cMapRom(0x3000,buff,0x0000),0x3000,0x0800,0x00)) return false; if(!AddMapper(new cMapEeprom(0x3000,buff,128,0x0000),0x3000,0x0800,0x00)) return false; // Eeprom80 0x80:0x8000-0xbfff //XXX if(!AddMapper(new cMapRom(0x8000,buff,0x0800),0x8000,0x4000,0x80)) return false; if(!AddMapper(new cMapEeprom(0x8000,buff, 0,0x0800),0x8000,0x4000,0x80)) return false; initDone=RomInit(); } return initDone;}// -- cMapReg ------------------------------------------------------------------cMapReg::cMapReg(int *_defwordsize, int _maxwordsize){ SetDefWordSize(_defwordsize); SetMaxWordSize(_maxwordsize); wordsize=DEF_WORDSIZE;}BIGNUM *cMapReg::Value(int wsize, bool mask){ wsize=OpWordSize(wsize); if(wordsize!=wsize) { Commit(); Reload(); } else if(mask) BN_mask_bits(reg,wsize*64); return reg;}void cMapReg::ClearReg(int wsize){ BN_rshift(reg,reg,wsize*64); BN_lshift(reg,reg,wsize*64);}void cMapReg::ClearFullReg(int wsize){ BN_rshift(fullreg,fullreg,wsize*64); BN_lshift(fullreg,fullreg,wsize*64);}void cMapReg::PrepTmp(BIGNUM *val, int wsize){ if(val->neg) { BN_clear(tmp); BN_set_bit(tmp,wsize*64); BN_add(tmp,tmp,val); } else BN_copy(tmp,val); BN_mask_bits(tmp,wsize*64);}void cMapReg::Commit(int wsize, int resync){ if(resync<0 && wsize<0) resync=1; wsize=OpWordSize(wsize>=0?wsize:wordsize); ClearFullReg(wsize); PrepTmp(reg,wsize); BN_add(fullreg,fullreg,tmp); if(resync) { if(wordsize==wsize) BN_mask_bits(reg,wsize*64); else wordsize=wsize; }}void cMapReg::Reload(int wsize){ wsize=OpWordSize(wsize>=0?wsize:wordsize); wordsize=wsize; BN_copy(reg,fullreg); BN_mask_bits(reg,64*wsize);}void cMapReg::GetLE(const unsigned char *in, int n){ int wsize=OpWordSize(n<=0?n:(n+7)/8); if(wordsize>wsize) Commit(); reg.GetLE(in,wsize*8); Commit(wsize);}void cMapReg::PutLE(unsigned char *out, int n){ int wsize=OpWordSize(n<=0?n:(n+7)/8); Commit(); fullreg.PutLE(out,wsize*8);}void cMapReg::Set(BIGNUM *val, int wsize){ wsize=OpWordSize(wsize); if(wordsize!=wsize) Commit(); ClearReg(wsize); PrepTmp(val,wsize); if(wordsize!=wsize) { ClearFullReg(wsize); BN_add(fullreg,fullreg,tmp); } BN_add(reg,reg,tmp);}void cMapReg::Clear(int wsize){ wsize=OpWordSize(wsize); if(wordsize!=wsize) { Commit(); ClearFullReg(wsize); } ClearReg(wsize);}// -- cMapMath -----------------------------------------------------------------cMapMath::cMapMath(void):A(&wordsize),B(&wordsize),C(&wordsize),D(&wordsize),J(0,1),I(&wordsize){ wordsize=DEF_WORDSIZE; words=-1;}bool cMapMath::ModAdd(BIGNUM *r, BIGNUM *a, BIGNUM *b, BIGNUM *d){ BN_add(r,a,b); bool ret=false; if(BN_cmp(r,d)>=0) { BN_sub(r,r,d); ret=true; } BN_mask_bits(r,wordsize<<6); return ret;}bool cMapMath::ModSub(BIGNUM *r, BIGNUM *d, BIGNUM *b){ cBN p; bool ret=BN_cmp(d,b)<0; BN_set_bit(p,wordsize<<6); BN_mod_sub(r,d,b,p,ctx); BN_mask_bits(r,wordsize<<6); return ret;}void cMapMath::MakeJ0(BIGNUM *j, BIGNUM *d, BIGNUM *c, int bits){#if OPENSSL_VERSION_NUMBER < 0x0090700fL#error BN_mod_inverse is probably buggy in your openssl version#endif BN_zero(x); BN_sub(j,x,d); j->neg=1; BN_set_bit(j,0); BN_set_bit(x,bits); BN_mod_inverse(j,j,x,ctx); if(c) { BN_copy(c,d); BN_mask_bits(c,bits); BN_mul(c,j,c,ctx); BN_rshift(c,c,bits); BN_mask_bits(c,bits); }}void cMapMath::MonMul(BIGNUM *o, BIGNUM *a, BIGNUM *b){ MonMul(o,a,b,C,D,J,0);}void cMapMath::MonMul(BIGNUM *o, BIGNUM *a, BIGNUM *b, int w){ MonMul(o,a,b,C,D,J,w);}void cMapMath::MonMul(BIGNUM *o, BIGNUM *a, BIGNUM *b, BIGNUM *c, BIGNUM *d, BIGNUM *j, int w){ MonMul0(o,a,b,c,d,j,w); MonFin(o,d);}void cMapMath::MonMul0(BIGNUM *o, BIGNUM *a, BIGNUM *b, BIGNUM *c, BIGNUM *d, BIGNUM *j, int w){ if(!w) w=wordsize; MonStart(w); int i=0; while(words>0) { BN_rshift(x,a,(i++)<<6); MonLoop(o,x,b,c,d,j); }}void cMapMath::MonStart(int w){ if(words<=0) { words=w; BN_zero(s); }}// modifies a, but pointing a to x is allowed !!void cMapMath::MonLoop(BIGNUM *o, BIGNUM *a, BIGNUM *b, BIGNUM *c, BIGNUM *d, BIGNUM *j){ words--; BN_mask_bits(a,64); BN_mul(a,a,b,ctx); BN_add(s,s,a); BN_copy(x,s); BN_mask_bits(x,64); BN_mul(x,x,j,ctx); if(!words) { BN_lshift(y,x,64); BN_add(y,y,x); // Low BN_rshift(c,y,2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -