896a05ff98d255b712d6ea9f8df148e2b615d696
[goodfet] / firmware / apps / jscan / jscan.c
1 /*! \file jscan.c
2   \author Don A. Bailey
3   \brief JTAG Scanner
4 */
5
6 /* set tabstop=8 */
7
8 #include "platform.h"
9 #include "command.h"
10
11 #if (platform != donbfet)
12 # include <signal.h>
13 # include <io.h>
14 # include <iomacros.h>
15 #endif
16
17 #include "jscan.h"
18
19 #define OFFSETIO 32
20 #define NPATTERN 64
21
22 typedef struct Pin Pin;
23
24 struct
25 Pin
26 {
27         Pin * next;
28         Pin * prev;
29         uint8_t id;
30         uint8_t bit;
31         uint8_t pullup;
32         volatile uint8_t * ddr;
33         volatile uint8_t * pin;
34         volatile uint8_t * port;
35 };
36
37 static Pin * pins;
38 static int nfound;
39 static uint8_t found[CMDDATALEN];
40 static char * tap_shiftir = "1111101100";
41 static uint8_t xdelay = JSCAN_DEFAULT_DELAY;
42 static uint8_t endian = JSCAN_ENDIAN_LITTLE;
43 static char pattern[NPATTERN] = "0110011101001101101000010111001001";
44
45 static void jscan(uint8_t, uint8_t, uint32_t);
46
47 static uint8_t setdelay(uint32_t);
48 static uint8_t setpullup(uint32_t);
49 static uint8_t setendian(uint32_t);
50
51 static uint8_t npins(void);
52 static void listpin(uint8_t);
53 static uint8_t addpin(Pin * );
54 static uint8_t rmpin(uint32_t);
55 static uint8_t newpin(uint32_t);
56 static uint8_t findpin(uint8_t, Pin ** );
57
58 static void scan(uint8_t);
59 static void loopback(uint8_t);
60 static void getresults(uint8_t);
61 static void clockstrobe(Pin * );
62 static void tdipulse(Pin *, Pin *, uint8_t);
63 static void tapstate(char *, Pin *, Pin * );
64 static void initpins(Pin *, Pin *, Pin *, Pin *, Pin * );
65 static int checkdata(char *, int, Pin *, Pin *, Pin *, int * );
66
67 app_t const 
68 jscan_app = 
69 {
70         JSCAN,
71         jscan,
72         "JSCAN",
73         "\tThe JScan app adds support for JTAG brute-force scanning.\n"
74 };
75
76 static void 
77 jscan(uint8_t a, uint8_t v, uint32_t l)
78 {
79         switch(v)
80         {
81         case JSCAN_CMD_ADDPIN:
82                 txdata(a, newpin(l), 1);
83                 break;
84         case JSCAN_CMD_RMPIN:
85                 txdata(a, rmpin(l), 1);
86                 break;
87         case JSCAN_CMD_DELAY:
88                 txdata(a, setdelay(l), 1);
89                 break;
90         case JSCAN_CMD_PULLUP:
91                 txdata(a, setpullup(l), 0);
92                 break;
93         case JSCAN_CMD_LOOPBACK:
94                 loopback(a);
95                 break;
96         case JSCAN_CMD_ENDIAN:
97                 txdata(a, setendian(l), 1);
98                 break;
99         case JSCAN_CMD_SCAN:
100                 scan(a);
101                 break;
102         case JSCAN_CMD_LISTPIN:
103                 listpin(a);
104                 break;
105         case JSCAN_CMD_RESULTS:
106                 getresults(a);
107                 break;
108         default:
109                 debugstr("Verb unimplemented in JSCAN application.");
110                 txdata(a, NOK, 0);
111                 break;
112         }
113 }
114
115 static uint8_t
116 npins(void)
117 {
118         uint8_t x;
119         Pin * p;
120
121         x = 0;
122         p = pins;
123         while(p)
124         {
125                 p = p->next;
126                 x++;
127         }
128
129         return x;
130 }
131
132 static uint8_t
133 newpin(uint32_t l)
134 {
135         Pin * p;
136
137         if(l != 5)
138                 return NOK;
139
140         if(npins() == JSCAN_LIMIT_PINS)
141         {
142                 return LIMIT;
143         }
144
145         if(findpin(cmddata[0], NULL))
146         {
147                 return EXIST;
148         }
149
150         p = calloc(1, sizeof *p);
151         if(!p)
152                 return NMEM;
153
154         /* enable pullups by default */
155         p->pullup       = 1;
156
157         p->id           = cmddata[0];
158         p->bit          = cmddata[1];
159         p->ddr          = (volatile uint8_t * )((uint16_t)cmddata[2] + OFFSETIO);
160         p->pin          = (volatile uint8_t * )((uint16_t)cmddata[3] + OFFSETIO);
161         p->port         = (volatile uint8_t * )((uint16_t)cmddata[4] + OFFSETIO);
162
163         /* explicitly set return value */
164         cmddata[0] = p->id;
165
166         return addpin(p);
167 }
168
169 static uint8_t
170 addpin(Pin * p)
171 {
172         Pin * a;
173
174         if(!pins)
175         {
176                 pins = p;
177                 return OK;
178         }
179
180         a = pins;
181         while(a && a->next)
182                 a = a->next;
183         a->next = p;
184         p->prev = a;
185
186         return OK;
187 }
188
189 static uint8_t
190 rmpin(uint32_t l)
191 {
192         uint8_t i;
193         Pin * p;
194
195         if(l != 1)
196                 return NOK;
197
198         i = cmddata[0];
199         if(!findpin(i, &p))
200                 return NOK;
201
202         if(p->prev)
203                 (p->prev)->next = p->next;
204         if(p->next)
205                 (p->next)->prev = p->prev;
206         if(p == pins)
207                 pins = p->next;
208
209         free(p);
210
211         cmddata[0] = i;
212
213         return OK;
214 }
215
216 static uint8_t 
217 findpin(uint8_t i, Pin ** pp)
218 {
219         Pin * p;
220
221         p = pins;
222         while(p)
223         {
224                 if(p->id == i)
225                 {
226                         if(pp)
227                                 *pp = p;
228                         return 1;
229                 }
230
231                 p = p->next;
232         }
233
234         return 0;
235 }
236
237 static uint8_t
238 setdelay(uint32_t l)
239 {
240         if(l != 1)
241         {
242                 cmddata[0] = xdelay;
243                 return OK;
244         }
245
246         xdelay = cmddata[0];
247         return OK;
248 }
249
250 static uint8_t
251 setpullup(uint32_t l)
252 {
253         Pin * p;
254
255         if(l != 2)
256                 return NOK;
257
258         /* change all or one? */
259         if(cmddata[0] != 0xff)
260         {
261                 if(!findpin(l, &p))
262                         return EXIST;
263                 p->pullup = cmddata[1] ? 1 : 0 ;
264         }
265         else
266         {
267                 p = pins; 
268                 while(p)
269                 {
270                         p->pullup = cmddata[1] ? 1 : 0 ;
271                         p = p->next;
272                 }
273         }
274
275         return OK;
276 }
277
278 static uint8_t
279 setendian(uint32_t l)
280 {
281         if(l != 1)
282         {
283                 cmddata[0] = endian;
284                 return OK;
285         }
286
287         switch(cmddata[0])
288         {
289         case JSCAN_ENDIAN_BIG:
290                 endian = JSCAN_ENDIAN_BIG;
291                 break;
292         case JSCAN_ENDIAN_LITTLE:
293                 endian = JSCAN_ENDIAN_LITTLE;
294                 break;
295         default:
296                 return NOK;
297         }
298
299         return OK;
300 }
301
302 static void
303 loopback(uint8_t a)
304 {
305         Pin * tdo;
306         Pin * tdi;
307         int nb;
308         int r;
309
310         if(npins() < 2)
311         {
312                 txdata(a, EXIST, 0);
313                 return;
314         }
315
316         nb = 0;
317
318         tdo = pins;
319         while(tdo)
320         {
321                 tdi = pins;
322                 while(tdi)
323                 {
324                         if(tdi == tdo)
325                         {
326                                 tdi = tdi->next;
327                                 continue;
328                         }
329
330                         initpins(NULL, NULL, tdi, NULL, NULL);
331
332                         r = checkdata(pattern, (2*NPATTERN), NULL, tdi, tdo, NULL);
333                         if(r == 1)
334                         {
335                                 if(nb >= (CMDDATALEN-4))
336                                 {
337                                         txdata(a, NMEM, 0);
338                                         return;
339                                 }
340
341                                 /* add the response in couples; TDI first */
342                                 cmddata[nb++] = tdi->id;
343                                 cmddata[nb++] = tdo->id;
344                         }
345
346                         tdi = tdi->next;
347                 }
348
349                 tdo = tdo->next;
350         }
351
352         txdata(a, OK, nb);
353 }
354
355 static void
356 initpins(Pin * tck, Pin * tms, Pin * tdi, Pin * tdo, Pin * nrst)
357 {
358         Pin * p;
359
360 /* XXX test removing syncs */
361         p = pins;
362         while(p)
363         {
364                 /* set as input by default */
365                 *p->ddr &= ~(1 << p->bit);
366
367                 /* sync */
368                 _delay_ms(xdelay);
369
370                 /* set pullup if desired while in input mode */
371                 if(p->pullup)
372                         *p->port |= (1 << p->bit);
373                 else
374                         *p->port &= ~(1 << p->bit);
375
376                 /* sync */
377                 _delay_ms(xdelay);
378
379                 if(p == nrst)
380                 {
381                         /* set as output */
382                         *p->ddr |= (1 << p->bit);
383
384                         /* nrst requires output fixed high */
385                         *p->port &= ~(1 << p->bit);
386                         *p->port |=  (1 << p->bit);
387                 }
388                 else if(p == tck || p == tms || p == tdi)
389                 {
390                         /* set as output */
391                         *p->ddr |= (1 << p->bit);
392
393                         /* sync */
394                         _delay_ms(xdelay);
395
396                         /* these pins must start low */
397                         *p->port &= ~(1 << p->bit);
398                 }
399
400                 /* tdo should need no special sauce */
401
402                 /* sync */
403                 _delay_ms(xdelay);
404
405                 p = p->next;
406         }
407 }
408
409 static int
410 checkdata(char * pattern, int ntimes, Pin * tck, Pin * tdi, Pin * tdo, int * nreg)
411 {
412         char rcv[NPATTERN];
413         int tdo_read;
414         int tdo_prev;
415         int ntoggle;
416         uint8_t x;
417         int np;
418         int i;
419         int w;
420
421         w = 0;
422         np = strlen(pattern);
423
424         x = (*tdo->pin & (1 << tdo->bit)) >> tdo->bit;
425
426         tdo_prev = '0' + (x == 1);
427
428         for(i = 0; i < ntimes; i++)
429         {
430                 tdipulse(tck, tdi, pattern[w++] - '0');
431                 if(!pattern[w])
432                 {
433                         w = 0;
434                 }
435
436                 x = (*tdo->pin & (1 << tdo->bit)) >> tdo->bit;
437
438                 tdo_read = '0' + (x == 1);
439
440                 ntoggle += (tdo_read != tdo_prev);
441                 tdo_prev = tdo_read;
442
443                 if(i < np)
444                 {
445                         rcv[i] = tdo_read;
446                 }
447                 else
448                 {
449                         memmove(rcv, rcv + 1, np - 1);
450                         rcv[np - 1] = tdo_read;
451                 }
452
453                 if(i >= np - 1)
454                 {
455                         if(!memcmp(pattern, rcv, np))
456                         {
457                                 if(nreg)
458                                         *nreg = i + 1 - np;
459                                 return 1;
460                         }
461                 }
462         }
463
464         if(nreg)
465                 *nreg = 0;
466
467         return ntoggle > 1 ? ntoggle : 0 ;
468 }
469
470 static void
471 tdipulse(Pin * tck, Pin * tdi, uint8_t x)
472 {
473         if(x)   
474                 *tdi->port |= (1 << tdi->bit);
475         else
476                 *tdi->port &= ~(1 << tdi->bit);
477
478         /* sync */
479         _delay_ms(xdelay);
480
481         clockstrobe(tck);
482 }
483
484 static void
485 clockstrobe(Pin * tck)
486 {
487         *tck->port |= (1 << tck->bit);
488         _delay_ms(xdelay);
489
490         *tck->port &= ~(1 << tck->bit);
491         _delay_ms(xdelay);
492 }
493
494 static void
495 scan(uint8_t a)
496 {
497         Pin * nrst;
498         Pin * tck;
499         Pin * tms;
500         Pin * tdi;
501         Pin * tdo;
502         int nreg;
503         int r;
504
505         if(npins() < 5)
506         {
507                 txdata(a, EXIST, 0);
508                 return;
509         }
510
511         nfound = 0;
512         nrst = pins;
513
514         /* send back an OK to let the user know we've started */
515         txdata(a, OK, 0);
516
517         while(nrst)
518         {
519                 tck = pins;
520                 while(tck)
521                 {
522                         if(tck == nrst)
523                         {
524                                 tck = tck->next;
525                                 continue;
526                         }
527
528                         tms = pins;
529                         while(tms)
530                         {
531                                 if(tms == nrst || tms == tck)
532                                 {
533                                         tms = tms->next;
534                                         continue;
535                                 }
536
537                                 tdo = pins;
538                                 while(tdo)
539                                 {
540                                         if(tdo == nrst || tdo == tck || tdo == tms)
541                                         {
542                                                 tdo = tdo->next;
543                                                 continue;
544                                         }
545
546                                         tdi = pins;
547                                         while(tdi)
548                                         {
549                                                 if(tdi == nrst || tdi == tck || tdi == tms || tdi == tdo)
550                                                 {
551                                                         tdi = tdi->next;
552                                                         continue;
553                                                 }
554
555                                                 initpins(tck, tms, tdi, tdo, nrst);
556
557                                                 tapstate(tap_shiftir, tck, tms);
558
559                                                 r = checkdata(pattern, (2*NPATTERN), tck, tdi, tdo, &nreg);
560                                                 if(r == 1)
561                                                 {
562                                                         /* found potential JTAG */
563                                                         /* NB */
564                                                         /* can fit around 100 detections; but total should hover around 0.5% of total tests. 
565                                                          * so if the number of tests is really high, one could exceed 100 detected JTAGs,
566                                                          * so caveat emptor
567                                                          */
568                                                         if(nfound < (CMDDATALEN-4)-5)
569                                                         {
570                                                                 /* order is important */
571                                                                 found[nfound++] = tck->id;
572                                                                 found[nfound++] = tms->id;
573                                                                 found[nfound++] = tdi->id;
574                                                                 found[nfound++] = tdo->id;
575                                                                 found[nfound++] = nrst->id;
576                                                         }
577                                                 }
578
579                                                 tdi = tdi->next;
580                                         }
581
582                                         tdo = tdo->next;
583                                 }
584
585                                 tms = tms->next;
586                         }
587
588                         tck = tck->next;
589                 }
590
591                 nrst = nrst->next;
592         }
593
594 }
595
596 static void
597 tapstate(char * s, Pin * tck, Pin * tms)
598 {
599         int x;
600
601         while(*s)
602         {
603                 x = *s - '0';
604                 /* issue */
605                 if(x)   
606                         *tms->port |= (1 << tms->bit);
607                 else
608                         *tms->port &= ~(1 << tms->bit);
609
610                 /* strobe */
611                 *tck->port &= ~(1 << tck->bit);
612                 _delay_ms(xdelay);
613                 *tck->port |= (1 << tck->bit);
614
615                 s++;
616         }
617 }
618
619 static void
620 listpin(uint8_t a)
621 {
622         Pin * p;
623         int nb;
624
625         nb = 0;
626         p = pins;
627         while(p)
628         {
629                 cmddata[nb++] = p->id;
630                 cmddata[nb++] = p->bit;
631                 cmddata[nb++] = ((uint16_t)(p->ddr)) & 0xff;
632                 cmddata[nb++] = ((uint16_t)(p->pin)) & 0xff;
633                 cmddata[nb++] = ((uint16_t)(p->port)) & 0xff;
634                 p = p->next;
635         }
636
637         txdata(a, OK, nb);
638 }
639
640 static void
641 getresults(uint8_t a)
642 {
643         memcpy(cmddata, found, nfound);
644         txdata(a, OK, nfound);
645 }
646