revert breaks some stupid old compilers
[oscam.git] / reader-dre-st20.c
blob641598e92783bebaea74f785b8675a7fc8b18ef4
1 #include "globals.h"
2 #include "reader-dre-st20.h"
4 #define IPTR 0
5 #define WPTR 1
6 #define AREG 2
7 #define BREG 3
8 #define CREG 4
10 #define FLASHS 0x7FE00000
11 #define FLASHE 0x7FFFFFFF
12 #define RAMS 0x40000000
13 #define RAME 0x401FFFFF
14 #define IRAMS 0x80000000
15 #define IRAME 0x800017FF
17 #define ERR_ILL_OP -1
18 #define ERR_CNT -2
20 // ----------------------------------------------------------------
22 #define STACKMAX 16
23 #define STACKMASK (STACKMAX-1)
25 typedef struct
27 uint32_t Iptr, Wptr;
28 uint8_t *flash, *ram;
29 uint32_t flashSize, ramSize;
30 int sptr, stack[STACKMAX];
31 uint8_t iram[0x1800];
32 int invalid;
33 int verbose;
34 } st20_context_t;
37 static void st20_set_flash(st20_context_t *ctx, uint8_t *m, int len);
38 static void st20_set_ram(st20_context_t *ctx, uint8_t *m, int len);
39 static void st20_init(st20_context_t *ctx, uint32_t IPtr, uint32_t WPtr, int verbose);
40 static void st20_free(st20_context_t *ctx);
42 static void st20_set_call_frame(st20_context_t *ctx, uint32_t raddr, int p1, int p2, int p3);
45 static uint32_t st20_get_reg(st20_context_t *ctx, int reg);
46 static void st20_set_reg(st20_context_t *ctx, int reg, uint32_t val);
47 static uint8_t st20_rbyte(st20_context_t *ctx, uint32_t off);
48 static void st20_wbyte(st20_context_t *ctx, uint32_t off, uint8_t val);
49 static uint32_t st20_rword(st20_context_t *ctx, uint32_t off);
50 static void st20_wword(st20_context_t *ctx, uint32_t off, uint32_t val);
52 #define INVALID_VALUE 0xCCCCCCCC
53 #define ERRORVAL 0xDEADBEEF
55 #define MININT 0x7FFFFFFF
56 #define MOSTPOS 0x7FFFFFFF
57 #define MOSTNEG 0x80000000
60 #define POP() ctx->stack[(ctx->sptr++)&STACKMASK]
61 #define PUSH(v) do { int32_t __v=(v); ctx->stack[(--ctx->sptr)&STACKMASK]=__v; } while(0)
62 #define DROP(n) ctx->sptr+=n
64 #define AAA ctx->stack[ctx->sptr&STACKMASK]
65 #define BBB ctx->stack[(ctx->sptr+1)&STACKMASK]
66 #define CCC ctx->stack[(ctx->sptr+2)&STACKMASK]
68 #define GET_OP() operand|=op1&0x0F
69 #define CLEAR_OP() operand=0
70 #define JUMP(x) ctx->Iptr+=(x)
71 #define POP64() ({ uint32_t __b=POP(); ((uint64_t)POP()<<32)|__b; })
72 #define PUSHPOP(op,val) do { int32_t __a=val; AAA op##= (__a); } while(0)
74 #define RB(off) st20_rbyte(ctx, off)
75 #define RW(off) st20_rword(ctx, off)
76 #define WW(off,val) st20_wword(ctx, off, val)
78 static uint32_t st20_get_reg(st20_context_t *ctx, int32_t reg)
80 switch(reg)
82 case IPTR: return ctx->Iptr;
83 case WPTR: return ctx->Wptr;
84 case AREG: return AAA;
85 case BREG: return BBB;
86 case CREG: return CCC;
88 return 0;
91 static void st20_set_reg(st20_context_t *ctx, int32_t reg, uint32_t val)
93 switch(reg)
95 case IPTR: ctx->Iptr = val; return;
96 case WPTR: ctx->Wptr = val; return;
97 case AREG: AAA=val; return;
98 case BREG: BBB=val; return;
99 case CREG: CCC=val; return;
103 static uint8_t *st20_addr(st20_context_t *ctx, uint32_t off)
105 if(off >= FLASHS && off <= FLASHE)
107 return &ctx->flash[off - FLASHS];
109 else if(off >= RAMS && off <= RAME)
111 return &ctx->ram[off - RAMS];
113 else if(off >= IRAMS && off <= IRAME)
114 return &ctx->iram[off - IRAMS];
116 ctx->invalid = ERRORVAL;
117 return (uint8_t *) &ctx->invalid;
120 static uint32_t st20_rword(st20_context_t *ctx, uint32_t off)
122 uint8_t *temp;
123 temp = st20_addr(ctx, off);
125 return ((temp[3]<<24) | (temp[2]<<16) | (temp[1]<<8) | temp[0]);
128 static uint16_t st20_rshort(st20_context_t *ctx, uint32_t off)
130 uint8_t *temp;
131 temp = st20_addr(ctx, off);
133 return ((temp[0]<<8) | temp[1]);
136 static uint8_t st20_rbyte(st20_context_t *ctx, uint32_t off)
138 return *st20_addr(ctx, off);
141 static void st20_wword(st20_context_t *ctx, uint32_t off, uint32_t val)
143 uint8_t *temp;
144 temp = st20_addr(ctx, off);
145 temp[3] = (val >> 24) & 0xFF;
146 temp[2] = (val >> 16) & 0xFF;
147 temp[1] = (val >> 8) & 0xFF;
148 temp[0] = val & 0xFF;
151 static void st20_wbyte(st20_context_t *ctx, uint32_t off, uint8_t val)
153 uint8_t *temp;
154 temp = st20_addr(ctx, off);
155 temp[0] = val;
158 static int32_t st20_decode(st20_context_t *ctx, int32_t count)
160 int32_t operand = 0;
161 CLEAR_OP();
162 while(ctx->Iptr != 0)
164 int32_t a, op1 = RB(ctx->Iptr++);
165 GET_OP();
166 switch(op1 >> 4)
168 case 0x0: // j / jump
169 JUMP(operand);
170 CLEAR_OP();
171 break;
172 case 0x1: // ldlp
173 PUSH(ctx->Wptr + (operand * 4));
174 CLEAR_OP();
175 break;
176 case 0x2: // positive prefix
177 operand <<= 4;
178 break;
179 case 0x3: // ldnl
180 AAA=RW(AAA + (operand * 4));
181 CLEAR_OP();
182 break;
183 case 0x4: // ldc
184 PUSH(operand);
185 CLEAR_OP();
186 break;
187 case 0x5: // ldnlp
188 PUSHPOP(+, operand * 4);
189 CLEAR_OP();
190 break;
191 case 0x6: // negative prefix
192 operand = (~operand) << 4;
193 break;
194 case 0x7: // ldl
195 PUSH(RW(ctx->Wptr + (operand * 4)));
196 CLEAR_OP();
197 break;
198 case 0x8: // adc
199 PUSHPOP(+, operand);
200 CLEAR_OP();
201 break;
202 case 0x9: // call
203 ctx->Wptr -= 16;
204 WW(ctx->Wptr, ctx->Iptr); WW(ctx->Wptr + 4, POP()); WW(ctx->Wptr + 8, POP()); WW(ctx->Wptr + 12, POP());
205 PUSH(ctx->Iptr);
206 JUMP(operand);
207 CLEAR_OP();
208 break;
209 case 0xA: // cj / conditional jump
210 if(AAA) { DROP(1); } else { JUMP(operand); }
211 CLEAR_OP();
212 break;
213 case 0xB: // ajw / adjust workspace
214 ctx->Wptr += operand * 4;
215 CLEAR_OP();
216 break;
217 case 0xC: // eqc / equals constant
218 AAA = (operand == AAA ? 1 : 0);
219 CLEAR_OP();
220 break;
221 case 0xD: // stl
222 WW(ctx->Wptr + (operand * 4), POP());
223 CLEAR_OP();
224 break;
225 case 0xE: // stnl
226 a = POP(); WW(a + (operand * 4), POP());
227 CLEAR_OP();
228 break;
229 case 0xF: // opr (secondary ins)
230 switch(operand)
232 case 0x00: a = AAA; AAA = BBB; BBB = a; break;
233 case 0x01: AAA = RB(AAA); break;
234 case 0x02: PUSHPOP(+, POP()); break;
235 case 0x04: PUSHPOP(-, POP()); break;
236 case 0x05: PUSHPOP(+, POP()); break;
237 case 0x06: a = AAA; AAA = ctx->Iptr; ctx->Iptr = a; break;
238 case 0x08: PUSHPOP(*, POP()); break;
239 case 0x09: a=POP(); AAA = (AAA > a); break;
240 case 0x0A: a=POP(); AAA = a + (AAA * 4); break;
241 case 0x0C: PUSHPOP(-, POP()); break;
242 case 0x1A: { a = POP(); uint64_t ll = POP64(); PUSH(ll % (uint32_t)a); PUSH(ll / (uint32_t)a); } break;
243 case 0x1B: PUSHPOP(+, ctx->Iptr); break;
244 case 0x1D: CCC = BBB; BBB = (AAA >= 0 ? 0 : -1); break;
245 case 0x1F: PUSHPOP(%, POP()); break;
246 case 0x20: ctx->Iptr = RW(ctx->Wptr); ctx->Wptr = ctx->Wptr + 16; break;
247 case 0x2C: PUSHPOP(/, POP()); break;
248 case 0x30: break;
249 case 0x32: AAA =~ AAA; break;
250 case 0x33: PUSHPOP(^, POP()); break;
251 case 0x34: PUSHPOP(*, 4); break;
252 case 0x35: { a = POP(); uint64_t ll = POP64() >> a; PUSH((ll >> 32) & 0xFFFFFFFF); PUSH(ll & 0xFFFFFFFF); } break;
253 case 0x36: { a = POP(); uint64_t ll = POP64() << a; PUSH((ll >> 32) & 0xFFFFFFFF); PUSH(ll & 0xFFFFFFFF); } break;
254 case 0x3B: a = POP(); st20_wbyte(ctx, a, POP()); break;
255 case 0x3F: a = POP(); PUSH(a & 3); PUSH((uint32_t)a >> 2); break;
256 case 0x40: a = POP(); AAA = (uint32_t)AAA >> a; break;
257 case 0x41: a = POP(); AAA = (uint32_t)AAA << a; break;
258 case 0x42: PUSH(MOSTNEG); break;
259 case 0x46: PUSHPOP(&, POP()); break;
260 case 0x4A: { a = POP(); int32_t b = POP(); int32_t c = POP(); while(a--) st20_wbyte(ctx, b++, st20_rbyte(ctx, c++)); } break;
261 case 0x4B: PUSHPOP(|, POP()); break;
262 case 0x53: PUSHPOP(*, POP()); break;
263 case 0x5A: PUSH(AAA); break;
264 case 0x5F: a = POP(); AAA = ((uint32_t)AAA > (uint32_t)a); break;
265 case 0x78: { a = POP(); int32_t b = POP(); int32_t bb = 0; while(a--){bb <<= 1; bb |= b & 1; b >>= 1;} PUSH(bb);} break;
266 case 0xCA: AAA = st20_rshort(ctx, AAA); break;
267 default:
268 cs_log("[icg] unknown opcode %X", operand);
269 return ERR_ILL_OP;
271 CLEAR_OP();
272 break;
274 if(--count <= 0 && operand == 0) return ERR_CNT;
276 return 0;
279 static void st20_set_flash(st20_context_t *ctx, uint8_t *m, int32_t len)
281 if(ctx->flash) free(ctx->flash);
282 ctx->flash = malloc(len);
283 if(ctx->flash && m) memcpy(ctx->flash, m, len);
284 else memset(ctx->flash, 0, len);
285 ctx->flashSize = len;
288 static void st20_set_ram(st20_context_t *ctx, uint8_t *m, int32_t len)
290 if(ctx->ram) free(ctx->ram);
291 ctx->ram = malloc(len);
292 if(ctx->ram && m) memcpy(ctx->ram, m, len);
293 else memset(ctx->ram, 0, len);
294 ctx->ramSize = len;
297 static void st20_init(st20_context_t *ctx, uint32_t IPtr, uint32_t WPtr, int32_t verbose)
299 ctx->Wptr = WPtr; ctx->Iptr = IPtr;
300 memset(ctx->stack, INVALID_VALUE, sizeof(ctx->stack)); ctx->sptr = STACKMAX - 3;
301 memset(ctx->iram, 0, sizeof(ctx->iram));
302 ctx->verbose = verbose;
305 static void st20_free(st20_context_t *ctx)
307 if(ctx->flash) free(ctx->flash);
308 if(ctx->ram) free(ctx->ram);
309 ctx->flash = NULL;
310 ctx->ram = NULL;
313 static void st20_set_call_frame(st20_context_t *ctx, uint32_t raddr, int32_t p1, int32_t p2, int32_t p3)
315 ctx->Wptr -= 16;
316 st20_wword(ctx, ctx->Wptr, raddr); // RET
317 st20_wword(ctx, ctx->Wptr + 4, p1); //Areg
318 st20_wword(ctx, ctx->Wptr + 8, p1); //Breg
319 st20_wword(ctx, ctx->Wptr + 12, p1); //Creg
320 st20_wword(ctx, ctx->Wptr + 16, p2);
321 st20_wword(ctx, ctx->Wptr + 20, p3);
322 st20_set_reg(ctx, AREG, raddr); // RET
325 int st20_run(uint8_t* snip, uint32_t snip_len, int addr, uint8_t *data, uint16_t overcryptId)
327 int error = 0, i, n;
328 st20_context_t ctx;
330 cs_log("[icg] decrypt address = 0x%X, id = %04X", addr, overcryptId);
332 cs_log("[icg] CW: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X "
333 ,data[0], data[1], data[2] , data[3] , data[4] , data[5] , data[6] , data[7]
334 ,data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]);
335 for(n=0;n<2;n++)
337 memset(&ctx, 0, sizeof(st20_context_t));
338 st20_set_ram(&ctx, NULL, 0x1000);
339 st20_set_flash(&ctx, snip + 0x48, (int) (snip_len - 0x48));
340 st20_init(&ctx, FLASHS + addr, RAMS + 0x100, 1);
341 st20_set_call_frame(&ctx, 0, RAMS, RAMS, RAMS);
342 for(i = 0; i < 8; i++) st20_wbyte(&ctx, RAMS + i, data[i+n*8]);
343 if ((error = st20_decode(&ctx, 800000)) < 0) break;
344 cs_log("[icg] cw%d ret = %d, AREG = %X", n+1, error, st20_get_reg(&ctx, AREG));
345 for(i = 0; i < 8; i++) data[i+n*8] = st20_rbyte(&ctx, RAMS + i);
346 st20_free(&ctx);
349 if(error < 0)
351 cs_log("[icg] st20 processing failed with error %d", error);
352 return 0;
355 cs_log("[icg] DW: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X "
356 ,data[0], data[1], data[2] , data[3] , data[4] , data[5] , data[6] , data[7]
357 ,data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]);
358 return 1;