1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include <regexp.h>
6 #include <bio.h>
7 #include "debug.h"
8 #include "tap.h"
9 #include "chain.h"
10 #include "jtag.h"
11 #include "icert.h"
12 #include "mmu.h"
13 #include "mpsse.h"
14 #include "/sys/src/9/kw/arm.h"
15 #include "/arm/include/ureg.h"
16 #include "lebo.h"
17
18 /*
19 * Like rdbfs + jtag icert control for arm cores.
20 * Memory just goes through in arm order, registers get translated
21 * to host order and back after.
22 */
23
24 typedef struct Fid Fid;
25 typedef struct Fs Fs;
26 enum
27 {
28 OPERM = 0x3, /* mask of all permission types in open mode */
29 Nfidhash = 32,
30
31 /*
32 * qids
33 */
34 Qroot = 1,
35 Qctl,
36 Qnote,
37 Qmem,
38 /* copied from rdbfs */
39 Qkregs,
40 Qfpregs,
41 Qproc,
42 Qregs,
43 Qtext,
44 Qstatus,
45 };
46
47 static int textfd;
48 static char* textfile = "/arm/s9plug";
49
50
51 struct Fid
52 {
53 Lock;
54 Fid *next;
55 Fid **last;
56 uint fid;
57 int ref; /* number of fcalls using the fid */
58 int attached; /* fid has beed attached or cloned and not clunked */
59
60 int open;
61 Qid qid;
62 };
63
64 static int dostat(int, uchar*, int);
65 static void* emalloc(uint);
66 static void fatal(char*, ...);
67 static void usage(void);
68
69 struct Fs
70 {
71 Lock; /* for fids */
72
73 Fid *hash[Nfidhash];
74 uchar statbuf[1024]; /* plenty big enough */
75 JMedium *jmed;
76 };
77
78 static void fsrun(Fs*, int);
79 static Fid* getfid(Fs*, uint);
80 static Fid* mkfid(Fs*, uint);
81 static void putfid(Fs*, Fid*);
82 static char* fsversion(Fs*, Fcall*);
83 static char* fsauth(Fs*, Fcall*);
84 static char* fsattach(Fs*, Fcall*);
85 static char* fswalk(Fs*, Fcall*);
86 static char* fsopen(Fs*, Fcall*);
87 static char* fscreate(Fs*, Fcall*);
88 static char* fsread(Fs*, Fcall*);
89 static char* fswrite(Fs*, Fcall*);
90 static char* fsclunk(Fs*, Fcall*);
91 static char* fsremove(Fs*, Fcall*);
92 static char* fsstat(Fs*, Fcall*);
93 static char* fswstat(Fs*, Fcall*);
94
95 static char *(*fcalls[])(Fs*, Fcall*) =
96 {
97 [Tversion] fsversion,
98 [Tattach] fsattach,
99 [Tauth] fsauth,
100 [Twalk] fswalk,
101 [Topen] fsopen,
102 [Tcreate] fscreate,
103 [Tread] fsread,
104 [Twrite] fswrite,
105 [Tclunk] fsclunk,
106 [Tremove] fsremove,
107 [Tstat] fsstat,
108 [Twstat] fswstat
109 };
110
111 static char Eperm[] = "permission denied";
112 static char Enotdir[] = "not a directory";
113 static char Enotexist[] = "file does not exist";
114 static char Eisopen[] = "file already open for I/O";
115 static char Einuse[] = "fid is already in use";
116 static char Enofid[] = "no such fid";
117 static char Enotopen[] = "file is not open";
118 static char Ebadcmd[] = "error in jtag operation";
119
120 static ArmCtxt ctxt;
121 static Fs fs;
122 static int messagesize = 8192+IOHDRSZ;
123
124 static int
cmdsetdebug(uchar * deb)125 cmdsetdebug(uchar *deb)
126 {
127 int i;
128
129 memset(debug, 0, 255);
130 for(i = 0; i < strlen((char *)deb); i++){
131 debug[deb[i]]++;
132 }
133 return 0;
134 }
135
136
137
138 void
main(int argc,char ** argv)139 main(int argc, char **argv)
140 {
141 char buf[12], *mnt, *srv, *mbname;
142 int fd, p[2], mb;
143 uchar *deb;
144
145 deb = nil;
146 mb = Sheeva;
147 mbname = nil;
148 mnt = "/n/jtagfs";
149 srv = nil;
150 ARGBEGIN{
151 case 'b':
152 mbname = EARGF(usage());
153 break;
154 case 's':
155 srv = ARGF();
156 mnt = nil;
157 break;
158 case 'm':
159 mnt = ARGF();
160 break;
161 case 'd':
162 deb = (uchar *)EARGF(usage());
163 break;
164 case 't':
165 textfile = EARGF(usage());
166 break;
167 }ARGEND
168
169 fmtinstall('F', fcallfmt);
170 if(deb != nil)
171 cmdsetdebug(deb);
172 if(argc != 1)
173 usage();
174 print("jtagfs: %s\n", argv[0]);
175 fd = open(argv[0], ORDWR);
176 if(fd < 0)
177 fatal("can't open jtag file %s: %r", argv[0]);
178
179 if(mbname == nil)
180 mb = Sheeva;
181 else if(strncmp(mbname, "sheeva", 6) == 0)
182 mb = Sheeva;
183 else if(strncmp(mbname, "gurudisp", 6) == 0)
184 mb = GuruDisp;
185 fs.jmed = initmpsse(fd, mb);
186 if(fs.jmed == nil)
187 fatal("jtag initialization %r");
188
189 if(pipe(p) < 0)
190 fatal("pipe failed");
191
192 switch(rfork(RFPROC|RFMEM|RFNOTEG|RFNAMEG)){
193 case 0:
194 fsrun(&fs, p[0]);
195 exits(nil);
196 case -1:
197 fatal("fork failed");
198 }
199
200 if(mnt == nil){
201 if(srv == nil)
202 usage();
203 fd = create(srv, OWRITE, 0666);
204 if(fd < 0){
205 remove(srv);
206 fd = create(srv, OWRITE, 0666);
207 if(fd < 0){
208 close(p[1]);
209 fatal("create of %s failed", srv);
210 }
211 }
212 sprint(buf, "%d", p[1]);
213 if(write(fd, buf, strlen(buf)) < 0){
214 close(p[1]);
215 fatal("writing %s", srv);
216 }
217 close(p[1]);
218 exits(nil);
219 }
220
221 if(mount(p[1], -1, mnt, MREPL, "") < 0){
222 close(p[1]);
223 fatal("mount failed");
224 }
225 close(p[1]);
226 exits(nil);
227 }
228
229 static void
fsrun(Fs * fs,int fd)230 fsrun(Fs *fs, int fd)
231 {
232 Fcall rpc;
233 char *err;
234 uchar *buf;
235 int n;
236
237 buf = emalloc(messagesize);
238 for(;;){
239 /*
240 * reading from a pipe or a network device
241 * will give an error after a few eof reads
242 * however, we cannot tell the difference
243 * between a zero-length read and an interrupt
244 * on the processes writing to us,
245 * so we wait for the error
246 */
247 n = read9pmsg(fd, buf, messagesize);
248 if(n == 0)
249 continue;
250 if(n < 0)
251 fatal("mount read");
252
253 rpc.data = (char*)buf + IOHDRSZ;
254 if(convM2S(buf, n, &rpc) == 0)
255 continue;
256 // fprint(2, "recv: %F\n", &rpc);
257
258
259 /*
260 * TODO: flushes are broken
261 */
262 if(rpc.type == Tflush)
263 continue;
264 else if(rpc.type >= Tmax || !fcalls[rpc.type])
265 err = "bad fcall type";
266 else
267 err = (*fcalls[rpc.type])(fs, &rpc);
268 if(err){
269 rpc.type = Rerror;
270 rpc.ename = err;
271 }
272 else
273 rpc.type++;
274 n = convS2M(&rpc, buf, messagesize);
275 // fprint(2, "send: %F\n", &rpc);
276 if(write(fd, buf, n) != n)
277 fatal("mount write");
278 }
279 }
280
281 static Fid*
mkfid(Fs * fs,uint fid)282 mkfid(Fs *fs, uint fid)
283 {
284 Fid *f;
285 int h;
286
287 h = fid % Nfidhash;
288 for(f = fs->hash[h]; f; f = f->next){
289 if(f->fid == fid)
290 return nil;
291 }
292
293 f = emalloc(sizeof *f);
294 f->next = fs->hash[h];
295 if(f->next != nil)
296 f->next->last = &f->next;
297 f->last = &fs->hash[h];
298 fs->hash[h] = f;
299
300 f->fid = fid;
301 f->ref = 1;
302 f->attached = 1;
303 f->open = 0;
304 return f;
305 }
306
307 static Fid*
getfid(Fs * fs,uint fid)308 getfid(Fs *fs, uint fid)
309 {
310 Fid *f;
311 int h;
312
313 h = fid % Nfidhash;
314 for(f = fs->hash[h]; f; f = f->next){
315 if(f->fid == fid){
316 if(f->attached == 0)
317 break;
318 f->ref++;
319 return f;
320 }
321 }
322 return nil;
323 }
324
325 static void
putfid(Fs *,Fid * f)326 putfid(Fs *, Fid *f)
327 {
328 f->ref--;
329 if(f->ref == 0 && f->attached == 0){
330 *f->last = f->next;
331 if(f->next != nil)
332 f->next->last = f->last;
333 free(f);
334 }
335 }
336
337 static char*
fsversion(Fs *,Fcall * rpc)338 fsversion(Fs *, Fcall *rpc)
339 {
340 if(rpc->msize < 256)
341 return "version: message size too small";
342 if(rpc->msize > messagesize)
343 rpc->msize = messagesize;
344 messagesize = rpc->msize;
345 if(strncmp(rpc->version, "9P2000", 6) != 0)
346 return "unrecognized 9P version";
347 rpc->version = "9P2000";
348 return nil;
349 }
350
351 static char*
fsauth(Fs *,Fcall *)352 fsauth(Fs *, Fcall *)
353 {
354 return "searchfs: authentication not required";
355 }
356
357 static char*
fsattach(Fs * fs,Fcall * rpc)358 fsattach(Fs *fs, Fcall *rpc)
359 {
360 Fid *f;
361
362 f = mkfid(fs, rpc->fid);
363 if(f == nil)
364 return Einuse;
365 f->open = 0;
366 f->qid.type = QTDIR;
367 f->qid.path = Qroot;
368 f->qid.vers = 0;
369 rpc->qid = f->qid;
370 putfid(fs, f);
371 return nil;
372 }
373
374 typedef struct DEntry DEntry;
375 struct DEntry {
376 uvlong path;
377 char *name;
378 };
379
380 DEntry entries[] = {
381 {Qctl, "ctl"},
382 {Qmem, "mem"},
383 {Qkregs, "kregs"},
384 {Qfpregs, "fpregs"},
385 {Qproc, "proc"},
386 {Qregs, "regs"},
387 {Qtext, "text"},
388 {Qstatus, "status"},
389 {Qnote, "note"},
390 {~0, nil},
391 };
392
393 static uvlong
nm2qpath(char * name)394 nm2qpath(char *name)
395 {
396 int i;
397
398 for(i = 0; entries[i].name != nil; i++)
399 if(strcmp(name, entries[i].name) == 0)
400 return entries[i].path;
401
402 return ~0;
403 }
404
405 static char*
fswalk(Fs * fs,Fcall * rpc)406 fswalk(Fs *fs, Fcall *rpc)
407 {
408 Fid *f, *nf;
409 int nqid, nwname, type;
410 char *err, *name;
411 ulong path, fpath;
412
413 f = getfid(fs, rpc->fid);
414 if(f == nil)
415 return Enofid;
416 nf = nil;
417 if(rpc->fid != rpc->newfid){
418 nf = mkfid(fs, rpc->newfid);
419 if(nf == nil){
420 putfid(fs, f);
421 return Einuse;
422 }
423 nf->qid = f->qid;
424 putfid(fs, f);
425 f = nf; /* walk f */
426 }
427
428 err = nil;
429 path = f->qid.path;
430 nwname = rpc->nwname;
431 for(nqid=0; nqid<nwname; nqid++){
432 if(path != Qroot){
433 err = Enotdir;
434 break;
435 }
436 name = rpc->wname[nqid];
437 /* BUG this is a kludge, rewrite */
438 fpath = nm2qpath(name);
439 if(fpath != ~0){
440 type = QTFILE;
441 path = fpath;
442 }
443 else if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
444 type = QTDIR;
445 else {
446 err = Enotexist;
447 break;
448 }
449
450 rpc->wqid[nqid] = (Qid){path, 0, type};
451 }
452
453 if(nwname > 0){
454 if(nf != nil && nqid < nwname)
455 nf->attached = 0;
456 if(nqid == nwname)
457 f->qid = rpc->wqid[nqid-1];
458 }
459
460 putfid(fs, f);
461 rpc->nwqid = nqid;
462 f->open = 0;
463 return err;
464 }
465
466 static char *
fsopen(Fs * fs,Fcall * rpc)467 fsopen(Fs *fs, Fcall *rpc)
468 {
469 Fid *f;
470 int mode;
471 char buf[512];
472
473 f = getfid(fs, rpc->fid);
474 if(f == nil)
475 return Enofid;
476 if(f->open){
477 putfid(fs, f);
478 return Eisopen;
479 }
480 mode = rpc->mode & OPERM;
481 if(mode == OEXEC
482 || f->qid.path == Qroot && (mode == OWRITE || mode == ORDWR)){
483 putfid(fs, f);
484 return Eperm;
485 }
486 if(f->qid.path == Qtext){
487 close(textfd);
488 textfd = open(textfile, OREAD);
489 if(textfd < 0) {
490 snprint(buf, sizeof buf, "text: %r");
491 putfid(fs, f);
492 return "opening text file";
493 }
494 }
495 f->open = 1;
496 rpc->qid = f->qid;
497 rpc->iounit = messagesize-IOHDRSZ;
498 putfid(fs, f);
499 return nil;
500 }
501
502 static char *
fscreate(Fs *,Fcall *)503 fscreate(Fs *, Fcall *)
504 {
505 return Eperm;
506 }
507
508 static int
readbuf(Fcall * rpc,void * s,long n)509 readbuf(Fcall *rpc, void *s, long n)
510 {
511 int count;
512 count = rpc->count;
513 if(rpc->offset >= n){
514 count = 0;
515 }
516 if(rpc->offset+count > n)
517 count = n - rpc->offset;
518 memmove(rpc->data, (char*)s+rpc->offset, count);
519 rpc->count = count;
520 return count;
521 }
522
523 enum{
524 Maxctl = 4*1024,
525 };
526
527 static char ctlread[Maxctl];
528
529 static int
readctl(Fs * fs,Fcall * rpc)530 readctl(Fs *fs, Fcall *rpc)
531 {
532 char *e;
533 int ssz;
534
535 ssz = Maxctl;
536 ctxt.debug = icedebugstate(fs->jmed);
537
538 if(ctxt.debug == 0){
539 e = seprint(ctlread, ctlread+Maxctl, "Arm is in debug: %d", ctxt.debug);
540 ssz = readbuf(rpc, ctlread, e - ctlread);
541 return ssz;
542 }
543 e = armsprctxt(&ctxt, ctlread, ssz);
544 if(e >= ctlread + Maxctl)
545 return e - ctlread;
546 ssz = Maxctl - (ctlread - e);
547 e = printmmuregs(&ctxt, e, ssz);
548
549 ssz = readbuf(rpc, ctlread, e - ctlread);
550 return ssz;
551
552 }
553
554 static int
readbytes(JMedium * jmed,u32int startaddr,u32int nbytes,u32int dataoff,Fcall * rpc)555 readbytes(JMedium *jmed, u32int startaddr, u32int nbytes, u32int dataoff, Fcall *rpc)
556 {
557 u32int i, data;
558 int nb, res;
559
560 nb = 0;
561 for(i = startaddr; i < startaddr+nbytes; i++){
562 res = armrdmemwd(jmed, i, &data, 1);
563 if(res < 0){
564 fprint(2, "Error reading [%#8.8ux]\n",
565 i);
566 werrstr("read error");
567 return -1;
568 break;
569 }
570 nb += res;
571 rpc->data[dataoff] = (char)data;
572 dprint(Dfs, "[B%#8.8ux] = %#2.2ux \n",
573 i, data);
574 }
575 return nb;
576
577 }
578
579 /*
580 * BUG: This is horrifyingly slow, could be made much (10x)
581 * faster using load multiple/store multiple
582 * both on memory and while reading back the registers.
583 * but it doesn't matter for acid (normally it reads words
584 * or byte long chunks). There may also be another way
585 * where you can inject instructions without waiting for
586 * debug mode on the way back. I haven't been able to
587 * make it work.
588 */
589 static int
readmem(Fs * fs,Fcall * rpc)590 readmem(Fs *fs, Fcall *rpc)
591 {
592 u32int count, i, data, addr, prenb, nb, postnb, st;
593 int res;
594
595 count = (u32int)rpc->count;
596
597 addr = (u32int)rpc->offset;
598 dprint(Dfs, "[%#8.8ux, %ud] =?\n",
599 addr, count);
600
601 prenb = 0;
602 nb = 0;
603 /* The start is not aligned */
604 if(addr & 0x3U){
605 prenb = sizeof(u32int) - (addr & 0x3U);
606 res = readbytes(fs->jmed, addr, prenb, 0, rpc);
607 if(res < 0){
608 werrstr("read error");
609 return -1;
610 }
611 nb += res;
612 dprint(Dfs, "readmem: aligned now\n");
613 }
614 for(i = prenb; i/4 < (count-prenb)/sizeof(u32int); i += sizeof(u32int)){
615 res = armrdmemwd(fs->jmed, addr+i, &data, 4);
616 if(res < 0){
617 fprint(2, "Error reading %#8.8ux [%#8.8ux]\n",
618 addr+i, i);
619 werrstr("read error");
620 return -1;
621 break;
622 }
623 nb += res;
624
625 *(u32int *)(rpc->data+i) = data;
626 dprint(Dfs, "%d[%#8.8ux] = %#8.8ux \n",
627 i, addr+i, data);
628 }
629
630 dprint(Dfs, "readmem: end of aligned\n");
631 /* The end is not aligned */
632 if((count-prenb) & 0x3U){
633 postnb = (count-prenb)%sizeof(u32int);
634 st = addr + 1 + ((count-prenb)& 0x3U);
635 res = readbytes(fs->jmed, st, postnb, nb, rpc);
636 if(res < 0){
637 werrstr("read error");
638 return -1;
639 }
640 nb += res;
641 dprint(Dfs, "readmem: end of non aligned\n");
642 }
643 return nb;
644 }
645
646 static int
writebytes(JMedium * jmed,u32int startaddr,u32int nbytes,u32int dataoff,Fcall * rpc)647 writebytes(JMedium *jmed, u32int startaddr, u32int nbytes, u32int dataoff, Fcall *rpc)
648 {
649 u32int i, data;
650 int nb, res;
651
652 nb = 0;
653 for(i = startaddr; i < startaddr+nbytes; i++){
654 data = (char)rpc->data[dataoff];
655 res = armwrmemwd(jmed, i, data, 1);
656 if(res < 0){
657 fprint(2, "Error writing [%#8.8ux]\n",
658 i);
659 werrstr("read error");
660 return -1;
661 break;
662 }
663 nb += res;
664 dprint(Dfs, "[B%#8.8ux] = %#2.2ux \n",
665 i, data);
666 }
667 return nb;
668
669 }
670
671 static int
writemem(Fs * fs,Fcall * rpc)672 writemem(Fs *fs, Fcall *rpc)
673 {
674 u32int count, i, addr, *p, prenb, nb, postnb, st;
675 int res;
676
677 count = rpc->count;
678 addr = rpc->offset;
679
680 prenb = 0;
681 nb = 0;
682 /* not aligned offset */
683 if(addr & 0x3U){
684 prenb = sizeof(u32int) - (addr & 0x3U);
685 res = writebytes(fs->jmed, addr, prenb, 0, rpc);
686 if(res < 0){
687 werrstr("write error");
688 return -1;
689 }
690 nb += res;
691 dprint(Dfs, "writemem: aligned now\n");
692 }
693 for(i = prenb; i/4 < (count-prenb)/sizeof(u32int); i += sizeof(u32int)){
694 p = (u32int *)(rpc->data + i);
695 dprint(Dfs, "%d[%#8.8ux] = %#8.8ux \n",
696 i, addr+i, *p);
697 res = armwrmemwd(fs->jmed, addr + i, *p, 4);
698 if(res < 0){
699 fprint(2, "Error writing %#8.8ux [%#8.8ux]\n",
700 addr+i, i);
701 werrstr("write error");
702 return -1;
703 break;
704 }
705 nb += res;
706 }
707 dprint(Dfs, "writemem: end of aligned\n");
708 /* not aligned end */
709 if((count-prenb) & 0x3U){
710 postnb = (count-prenb)%sizeof(u32int);
711 st = addr + 1 + ((count-prenb)& 0x3U);
712 res = writebytes(fs->jmed, st, postnb, nb, rpc);
713 if(res < 0){
714 werrstr("write error");
715 return -1;
716 }
717 nb += res;
718 dprint(Dfs, "writemem: end of non aligned\n");
719 }
720 return nb;
721 }
722
723 /* host to Arm (le) */
724 static void
setkernur(Ureg * kur,ArmCtxt * context)725 setkernur(Ureg *kur, ArmCtxt *context)
726 {
727 int i;
728 u32int *p;
729
730 kur->type = context->cpsr&PsrMask;
731 hleputl(&kur->type, kur->type);
732
733 kur->psr = context->spsr;
734 hleputl(&kur->psr, kur->psr);
735
736 p = (u32int *)kur;
737 for(i = 0; i < 14; i++)
738 hleputl(p + i, context->r[i]);
739 kur->pc = context->r[15];
740 hleputl(&kur->pc, kur->pc);
741 }
742
743 typedef struct Regs Regs;
744 struct Regs {
745 Ureg kur;
746 MMURegs mmust;
747 };
748
749 static Regs procregs; /* kludge: just for reading */
750
751 /* host to Arm (le) */
752 static void
setmmust(MMURegs * mmust,ArmCtxt * context)753 setmmust(MMURegs *mmust, ArmCtxt *context)
754 {
755 int i;
756 u32int *o, *d;
757 d = (u32int *)mmust;
758 o = (u32int *) &context->MMURegs;
759 for(i = 0; i < sizeof(MMURegs)/sizeof(u32int); i++)
760 hleputl(d + i, o[i]);
761 }
762
763 static char*
fsread(Fs * fs,Fcall * rpc)764 fsread(Fs *fs, Fcall *rpc)
765 {
766 Fid *f;
767 int off, count, len, i;
768 uchar *rptr;
769 char buf[512];
770
771 f = getfid(fs, rpc->fid);
772 if(f == nil)
773 return Enofid;
774 if(!f->open){
775 putfid(fs, f);
776 return Enotopen;
777 }
778 count = rpc->count;
779 off = rpc->offset;
780 if(f->qid.path == Qroot){
781 if(off > 0)
782 rpc->count = 0;
783 else {
784 rpc->count = 0;
785 for(i = 0; entries[i].name != nil; i++)
786 rpc->count += dostat(entries[i].path,
787 rpc->count+(uchar*)rpc->data, count-rpc->count);
788 }
789
790 putfid(fs, f);
791 if(off == 0 && rpc->count <= BIT16SZ)
792 return "directory read count too small";
793 return nil;
794 }
795 len = 0;
796 if(f->qid.path == Qctl){
797 dprint(Dfs, "ctlread\n");
798 len = readctl(fs, rpc);
799 dprint(Dfs, "ctlread read %d %s\n", len, ctlread);
800 if(len < 0){
801 putfid(fs, f);
802 return "ctl read";
803 }
804 }
805 else if(f->qid.path == Qmem){
806 dprint(Dfs, "readmem\n");
807 len = readmem(fs, rpc);
808 dprint(Dfs, "readmem read %d %s\n", len, ctlread);
809 if(len < 0){
810 putfid(fs, f);
811 return "readmem read";
812 }
813 }
814 else if(f->qid.path == Qkregs){
815 dprint(Dfs, "kregs read n %d off %d\n", rpc->count, rpc->offset);
816 memset(&procregs, 0, sizeof(Regs));
817 setkernur(&procregs.kur, &ctxt);
818 setmmust(&procregs.mmust, &ctxt);
819 rptr = (uchar*)&procregs;
820 len = readbuf(rpc, rptr, sizeof(Regs));
821 }
822 else if(f->qid.path == Qtext){
823 dprint(Dfs, "text\n");
824 len = pread(textfd, rpc->data, rpc->count, rpc->offset);
825 if(len < 0) {
826 rerrstr(buf, sizeof buf);
827 fprint(2, "error reading text: %r");
828 putfid(fs, f);
829 return "text read";
830 }
831 }
832 else if(f->qid.path == Qstatus){
833 dprint(Dfs, "status\n");
834 len = snprint(buf, sizeof buf, "%-28s%-28s%-28s", "remote", "system", "New");
835 for(i = 0; i < 9; i++)
836 len += snprint(buf + len, sizeof buf - len, "%-12d", 0);
837 len = readbuf(rpc, buf, len);
838
839 }
840 putfid(fs, f);
841 rpc->count = len;
842 return nil;
843 }
844
845 typedef struct Cmdbuf Cmdbuf;
846 typedef struct Cmdtab Cmdtab;
847 struct Cmdbuf
848 {
849 char *buf;
850 char **f;
851 int nf;
852 };
853
854 struct Cmdtab
855 {
856 int index; /* used by client to switch on result */
857 char *cmd; /* command name */
858 int narg; /* expected #args; 0 ==> variadic */
859 };
860 /*
861 * Generous estimate of number of fields, including terminal nil pointer
862 */
863 static int
ncmdfield(char * p,int n)864 ncmdfield(char *p, int n)
865 {
866 int white, nwhite;
867 char *ep;
868 int nf;
869
870 if(p == nil)
871 return 1;
872
873 nf = 0;
874 ep = p+n;
875 white = 1; /* first text will start field */
876 while(p < ep){
877 nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0); /* UTF is irrelevant */
878 if(white && !nwhite) /* beginning of field */
879 nf++;
880 white = nwhite;
881 }
882 return nf+1; /* +1 for nil */
883 }
884
885 /*
886 * parse a command written to a device
887 */
888 static Cmdbuf*
parsecmd(char * p,int n)889 parsecmd(char *p, int n)
890 {
891 Cmdbuf *cb;
892 int nf;
893 char *sp;
894
895 nf = ncmdfield(p, n);
896
897 /* allocate Cmdbuf plus string pointers plus copy of string including \0 */
898 sp = malloc(sizeof(*cb) + nf * sizeof(char*) + n + 1);
899 if(sp == nil)
900 sysfatal("memory");
901 cb = (Cmdbuf*)sp;
902 cb->f = (char**)(&cb[1]);
903 cb->buf = (char*)(&cb->f[nf]);
904
905 memmove(cb->buf, p, n);
906
907 /* dump new line and null terminate */
908 if(n > 0 && cb->buf[n-1] == '\n')
909 n--;
910 cb->buf[n] = '\0';
911
912 cb->nf = tokenize(cb->buf, cb->f, nf-1);
913 cb->f[cb->nf] = nil;
914
915 return cb;
916 }
917
918 /*
919 * Look up entry in table
920 */
921
922 static Cmdtab*
lookupcmd(Cmdbuf * cb,Cmdtab * ctab,int nctab)923 lookupcmd(Cmdbuf *cb, Cmdtab *ctab, int nctab)
924 {
925 int i;
926 Cmdtab *ct;
927
928 if(cb->nf == 0){
929 werrstr("empty control message");
930 return nil;
931 }
932
933 for(ct = ctab, i=0; i<nctab; i++, ct++){
934 if(strcmp(ct->cmd, "*") !=0) /* wildcard always matches */
935 if(strcmp(ct->cmd, cb->f[0]) != 0)
936 continue;
937 if(ct->narg != 0 && ct->narg != cb->nf){
938 werrstr("bad # args to command");
939 return nil;
940 }
941 return ct;
942 }
943
944 werrstr("unknown control message");
945 return nil;
946 }
947
948 enum {
949 CMcpuid,
950 CMdebug,
951 CMreset,
952 CMstop,
953 CMstartstop,
954 CMwaitstop,
955 CMstart,
956 CMdump,
957 CMveccatch,
958 CMbreakpoint,
959 };
960
961 static Cmdtab ctab[] = {
962 CMdebug, "debug", 2,
963 CMreset, "reset", 1,
964 CMcpuid, "cpuid", 1,
965 CMstop, "stop", 1,
966 CMstart, "start", 1,
967 CMdump, "dump", 3,
968 CMveccatch, "veccatch", 2,
969 CMwaitstop, "waitstop", 1,
970 CMstartstop, "startstop", 1,
971 CMbreakpoint, "breakpoint", 0, /* 2 or 3 args, optional mask */
972 };
973
974 static int
cmdcpuid(JMedium * jmed)975 cmdcpuid(JMedium *jmed)
976 {
977 u32int cpuid;
978
979 cpuid = armidentify(jmed);
980 dprint(Dfs, "---- Cpuid --- %8.8ux\n", cpuid);
981 if(cpuid == ~0){
982 werrstr("not feroceon or nstrs bug...");
983 return -1;
984 }
985
986 dprint(Dfs, "---- Bypass probe --- \n");
987 if(armbpasstest(jmed) < 0){
988 fprint(2, "error in bypass\n");
989 werrstr("bypass test");
990 return -1;
991 }
992 ctxt.cpuid = cpuid;
993 return 0;
994 }
995
996 static int
checkcpuid(JMedium * jmed)997 checkcpuid(JMedium *jmed)
998 {
999 if(ctxt.cpuid != 0)
1000 return 0;
1001
1002 return cmdcpuid(jmed);
1003 }
1004
1005
1006 typedef struct VecMode VecMode;
1007 struct VecMode{
1008 char c;
1009 u32int mode;
1010 };
1011
1012 static VecMode vmode[] = {
1013 {'R', ResetCat},
1014 {'S', SWICat},
1015 {'P', PAbortCat},
1016 {'D', DAbortCat},
1017 {'I', IrqCat},
1018 {'F', FiqCat},
1019 };
1020
1021 static u32int
vecval(char * conds)1022 vecval(char *conds)
1023 {
1024 int i, j;
1025 u32int vcregval;
1026
1027 vcregval = 0;
1028 for(i = 0; i < strlen(conds); i++){
1029 for(j = 0; j < nelem(vmode); j++){
1030 if(vmode[j].c == conds[i])
1031 vcregval |= vmode[j].mode;
1032 }
1033 }
1034
1035 return vcregval;
1036 }
1037 /* if running, stop, set catch, start, else, set catch, not start*/
1038 static int
cmdveccatch(JMedium * jmed,char * conds)1039 cmdveccatch(JMedium *jmed, char *conds)
1040 {
1041 u32int vcregval;
1042 int res, wasdebug;
1043
1044 wasdebug = ctxt.debug;
1045 if(!wasdebug){
1046 res = iceenterdebug(jmed, &ctxt);
1047 if(res< 0){
1048 werrstr("entering debug to set veccat");
1049 return -1;
1050 }
1051 }
1052
1053 vcregval = vecval(conds);
1054 res = setchain(jmed, ChCommit, 2);
1055 if(res < 0)
1056 return -1;
1057 fprint(Dice, "veccatch: %#8.8ux\n", vcregval);
1058 res = icesetreg(jmed, VecCatReg, vcregval);
1059 if(res < 0)
1060 return -1;
1061
1062 ctxt.exitreas = VeccatReqReas;
1063 if(!wasdebug){
1064 res = iceexitdebug(jmed, &ctxt);
1065 if(res < 0){
1066 werrstr("exiting debug to set veccat");
1067 return -1;
1068 }
1069 }
1070
1071 return 0;
1072 }
1073
1074 /* if running, stop, set breakpoint, start, else, set breakpoint, not start*/
1075 static int
cmdbreakpoint(JMedium * jmed,u32int addr,u32int mask)1076 cmdbreakpoint(JMedium *jmed, u32int addr, u32int mask)
1077 {
1078 int res, wasdebug;
1079
1080 wasdebug = ctxt.debug;
1081 if(!wasdebug){
1082 if(ctxt.debugreas != BreakReas && ctxt.debugreas != NoReas){
1083 werrstr("already waiting debug");
1084 return -1;
1085 }
1086 res = iceenterdebug(jmed, &ctxt);
1087 if(res< 0){
1088 werrstr("entering debug to set breakpoint");
1089 return -1;
1090 }
1091 }
1092
1093 res = setchain(jmed, ChCommit, 2);
1094 if(res < 0)
1095 return -1;
1096 res = icesetreg(jmed, Wp0|AddrValReg, addr);
1097 if(res < 0)
1098 return -1;
1099
1100 res = icesetreg(jmed, Wp0|AddrMskReg, mask);
1101 if(res < 0)
1102 return -1;
1103
1104 res = icesetreg(jmed, Wp0|DataMskReg, 0xffffffff);
1105 if(res < 0)
1106 return -1;
1107
1108 res = icesetreg(jmed, Wp0|CtlMskReg, 0xff&~DataWPCtl);
1109 if(res < 0)
1110 return -1;
1111 res = icesetreg(jmed, Wp0|CtlValReg, EnableWPCtl);
1112 if(res < 0)
1113 return -1;
1114 fprint(Dice, "breakpoint: addr %#8.8ux msk %#8.8ux \n", addr, mask);
1115
1116 ctxt.exitreas = BreakReqReas;
1117 if(!wasdebug){
1118 res = iceexitdebug(jmed, &ctxt);
1119 if(res < 0){
1120 werrstr("exiting debug to set breakpoint");
1121 return -1;
1122 }
1123 }
1124 return 0;
1125 }
1126
1127 static char dbgstr[4*1024];
1128
1129 static int
cmdstop(JMedium * jmed)1130 cmdstop(JMedium *jmed)
1131 {
1132 int res;
1133
1134 res = iceenterdebug(jmed, &ctxt);
1135 if(res < 0){
1136 return -1;
1137 }
1138
1139 ctxt.debug = icedebugstate(fs.jmed);
1140 return 0;
1141 }
1142
1143 static int
cmdwaitstop(JMedium * jmed)1144 cmdwaitstop(JMedium *jmed)
1145 {
1146 int res;
1147
1148 res = icewaitentry(jmed, &ctxt);
1149 if(res < 0){
1150 werrstr("timeout waiting for entry to debug state");
1151 return -1;
1152 }
1153 return 0;
1154 }
1155
1156 static int
cmdstart(JMedium * jmed)1157 cmdstart(JMedium *jmed)
1158 {
1159 int res;
1160 res = iceexitdebug(jmed, &ctxt);
1161 if(res < 0){
1162 werrstr("could not exit debug");
1163 return -1;
1164 }
1165 ctxt.debug = icedebugstate(fs.jmed);
1166 return 0;
1167 }
1168
1169 static int
cmddump(JMedium * jmed,u32int start,u32int end)1170 cmddump(JMedium *jmed, u32int start, u32int end)
1171 {
1172 int res, i;
1173 u32int data;
1174 debug[Dctxt] = 1;
1175
1176
1177 for(i = 0; i < end-start; i+=4){
1178 res = armrdmemwd(jmed, start+i, &data, 4);
1179 if(res < 0){
1180 fprint(2, "Error reading %#8.8ux [%#8.8ux]\n", start+i, i);
1181 werrstr("read error");
1182 return -1;
1183 break;
1184 }
1185 dprint(Dfs, "%d[%#8.8ux] = %#8.8ux \n",
1186 i, start+i, data);
1187 }
1188 return 0;
1189 }
1190
1191 static int
cmdhwreset(Fs * fs)1192 cmdhwreset(Fs *fs)
1193 {
1194 JMedium *jmed;
1195
1196 jmed = fs->jmed;
1197 if(jmed->flush(jmed->mdata)){
1198 werrstr("flush");
1199 return -1;
1200 }
1201
1202 fs->jmed = resetmpsse(fs->jmed);
1203 if(fs->jmed == nil)
1204 return -1;
1205 ctxt.debug = 0;
1206
1207 jmed = fs->jmed;
1208 /* BUG make this medium independant..., add a send 5 TMS to interface */
1209 if(pushcmd(jmed->mdata, "TmsCsOut EdgeDown LSB B0x7 0x7f") < 0) {
1210 werrstr("going to reset");
1211 return -1;
1212 }
1213 if(jmed->flush(jmed->mdata)){
1214 werrstr("flush");
1215 return -1;
1216 }
1217 sleep(1000);
1218 jmed->resets(jmed->mdata, 1, 0);
1219 sleep(200);
1220 jmed->resets(jmed->mdata, 1, 1);
1221 sleep(200);
1222 jmed->resets(jmed->mdata, 0, 1);
1223 sleep(200);
1224 jmed->resets(jmed->mdata, 0, 0);
1225 sleep(200);
1226 if(jmed->flush(jmed->mdata)){
1227 werrstr("flush");
1228 return -1;
1229 }
1230 memset(&ctxt, 0, sizeof(ArmCtxt));
1231 return 0;
1232 }
1233
1234 static int
cmdstartstop(JMedium * jmed)1235 cmdstartstop(JMedium *jmed)
1236 {
1237 if(cmdstart(jmed) < 0){
1238 werrstr("starting");
1239 return -1;
1240 }
1241 if(cmdstop(jmed) < 0){
1242 werrstr("stopping");
1243 return -1;
1244 }
1245 return 0;
1246 }
1247
1248
1249 static int
runcmd(Fs * fs,char * data,int count)1250 runcmd(Fs *fs, char *data, int count)
1251 {
1252 Cmdtab *t;
1253 Cmdbuf *cb;
1254 int res;
1255 u32int st, end, addr, msk;
1256
1257 cb = parsecmd(data, count);
1258 if(cb->nf < 1){
1259 werrstr("empty control message");
1260 free(cb);
1261 return -1;
1262 }
1263
1264 t = lookupcmd(cb, ctab, nelem(ctab));
1265 if(t == nil){
1266 free(cb);
1267 return -1;
1268 }
1269
1270 if(t->index != CMreset && t->index != CMcpuid &&
1271 t->index != CMdebug &&
1272 checkcpuid(fs->jmed) < 0)
1273 return -1;
1274
1275 switch(t->index){
1276 case CMdebug:
1277 res = cmdsetdebug((uchar *)cb->f[1]);
1278 break;
1279 case CMreset:
1280 dprint(Dfs, "reset\n");
1281 res = cmdhwreset(fs);
1282 break;
1283 case CMcpuid:
1284 dprint(Dfs, "cpuid\n");
1285 res = checkcpuid(fs->jmed);
1286 break;
1287 case CMstop:
1288 dprint(Dfs, "stop\n");
1289 res = cmdstop(fs->jmed);
1290 break;
1291 case CMwaitstop:
1292 dprint(Dfs, "waitstop\n");
1293 res = cmdwaitstop(fs->jmed);
1294 break;
1295 case CMstart:
1296 dprint(Dfs, "start\n");
1297 res = cmdstart(fs->jmed);
1298 break;
1299 case CMdump:
1300 st = atol(cb->f[1]);
1301 end = atol(cb->f[2]);
1302 dprint(Dfs, "dump %#8.8ux %#8.8ux\n", st, end);
1303 res = cmddump(fs->jmed, st, end);
1304 break;
1305 case CMveccatch:
1306 dprint(Dfs, "veccatch %s\n", cb->f[1]);
1307 res = cmdveccatch(fs->jmed, cb->f[1]);
1308 break;
1309 case CMbreakpoint:
1310 addr = atol(cb->f[1]);
1311 if(cb->nf > 0 && cb->nf == 3)
1312 msk = atol(cb->f[2]);
1313 else if(cb->nf > 0 && cb->nf == 2)
1314 msk = 0;
1315 else {
1316 res = -1;
1317 goto Exit;
1318 }
1319
1320 dprint(Dfs, "breakpoint addr %#8.8ux mask %#8.8ux\n", addr, msk);
1321 res = cmdbreakpoint(fs->jmed, addr, msk);
1322 break;
1323 default:
1324 res = -1;
1325 }
1326 Exit:
1327 free(cb);
1328 return res;
1329 }
1330
1331 /* Arm (le) order to host */
1332 static void
getkernur(ArmCtxt * ct,Ureg * kur)1333 getkernur(ArmCtxt *ct, Ureg *kur)
1334 {
1335 int i;
1336
1337 ct->cpsr = (ct->cpsr&~PsrMask) | kur->type;
1338 ct->cpsr = lehgetl(&ct->cpsr);
1339
1340 ct->spsr = kur->psr;
1341 ct->spsr = lehgetl(&ct->spsr);
1342
1343 memmove(ct->r, kur, 14*sizeof(u32int));
1344 ct->r[15] = kur->pc;
1345 for(i = 0; i < 15; i++)
1346 ct->r[i] = lehgetl(ct->r + i);
1347 }
1348
1349 static int
setkregs(Fs * fs,Fcall * rpc)1350 setkregs(Fs *fs, Fcall *rpc)
1351 {
1352 Ureg kur;
1353 ArmCtxt lc;
1354 u32int mask, *lp, *gp;
1355 int res, nb, i;
1356 char *p;
1357 JMedium *jmed;
1358
1359 jmed = fs->jmed;
1360
1361 nb = 0;
1362 lc = ctxt;
1363 setkernur(&kur, &ctxt);
1364 p = (char *)&kur;
1365 if(rpc->count + rpc->offset > sizeof(Ureg)) /* cannot write mmuregs*/
1366 return -1;
1367 else
1368 memmove(p + rpc->offset, rpc->data, rpc->count);
1369
1370 getkernur(&ctxt, &kur);
1371
1372 /* BUG? hmm, order matters here, if I get both I am not sure of what to do */
1373 if(ctxt.cpsr != lc.cpsr){
1374 res = armsetexec(jmed, 1, &ctxt.cpsr, ARMLDMIA|0x0001);
1375 if(res < 0)
1376 return -1;
1377 res = armgofetch(jmed, ARMMSRr0CPSR, 0);
1378 if(res < 0)
1379 return -1;
1380 nb += sizeof(u32int);
1381 }
1382
1383 if(ctxt.spsr != lc.spsr){
1384 res = armsetexec(jmed, 1, &ctxt.spsr, ARMLDMIA|0x0001);
1385 if(res < 0)
1386 return -1;
1387 res = armgofetch(jmed, ARMMSRr0SPSR, 0);
1388 if(res < 0)
1389 return -1;
1390 nb += sizeof(u32int);
1391 }
1392
1393
1394
1395 /* last I update the registers */
1396 lp = (u32int *)&lc;
1397 gp = (u32int *)&ctxt;
1398 mask = 0;
1399 for(i = 0; i < 16; i++){
1400 if(lp[i] != gp[i]){ /* see which ones changed */
1401 mask |= (1 << i);
1402 nb += sizeof(u32int);
1403 }
1404 }
1405 mask |= 0x0001; /* this one I contaminated myself */
1406 res = armsetregs(jmed, mask, ctxt.r);
1407 if(res < 0)
1408 return -1;
1409 return nb;
1410 }
1411
1412 static char*
fswrite(Fs * fs,Fcall * rpc)1413 fswrite(Fs *fs, Fcall *rpc)
1414 {
1415 Fid *f;
1416 int res, len;
1417
1418 f = getfid(fs, rpc->fid);
1419 if(f == nil)
1420 return Enofid;
1421 if(!f->open){
1422 putfid(fs, f);
1423 return Enotopen;
1424 }
1425
1426 if(f->qid.path == Qctl){
1427 res = runcmd(fs, rpc->data, rpc->count);
1428 if(res < 0){
1429 fprint(2, "error %r\n");
1430 putfid(fs, f);
1431 return Ebadcmd;
1432 }
1433 }
1434 else if(f->qid.path == Qmem){
1435 len = writemem(fs, rpc);
1436 if(len < 0){
1437 putfid(fs, f);
1438 return "reading memory";
1439 }
1440 }
1441 else if(f->qid.path == Qkregs){
1442 dprint(Dfs, "kregs write n %d off %d\n", rpc->count, rpc->offset);
1443 len = setkregs(fs, rpc);
1444 if(len < 0){
1445 putfid(fs, f);
1446 return "writing kregs";
1447 }
1448 }
1449 else {
1450 putfid(fs, f);
1451 return Eperm;
1452 }
1453 putfid(fs, f);
1454 return nil;
1455 }
1456
1457 static char *
fsclunk(Fs * fs,Fcall * rpc)1458 fsclunk(Fs *fs, Fcall *rpc)
1459 {
1460 Fid *f;
1461
1462 f = getfid(fs, rpc->fid);
1463 if(f != nil){
1464 f->attached = 0;
1465 putfid(fs, f);
1466 }
1467 return nil;
1468 }
1469
1470 static char *
fsremove(Fs *,Fcall *)1471 fsremove(Fs *, Fcall *)
1472 {
1473 return Eperm;
1474 }
1475
1476 static char *
fsstat(Fs * fs,Fcall * rpc)1477 fsstat(Fs *fs, Fcall *rpc)
1478 {
1479 Fid *f;
1480
1481 f = getfid(fs, rpc->fid);
1482 if(f == nil)
1483 return Enofid;
1484 rpc->stat = fs->statbuf;
1485 rpc->nstat = dostat(f->qid.path, rpc->stat, sizeof fs->statbuf);
1486 putfid(fs, f);
1487 if(rpc->nstat <= BIT16SZ)
1488 return "stat count too small";
1489 return nil;
1490 }
1491
1492 static char *
fswstat(Fs *,Fcall *)1493 fswstat(Fs *, Fcall *)
1494 {
1495 return Eperm;
1496 }
1497
1498 static int
dostat(int path,uchar * buf,int nbuf)1499 dostat(int path, uchar *buf, int nbuf)
1500 {
1501 Dir d;
1502
1503 switch(path){
1504 case Qroot:
1505 d.name = ".";
1506 d.mode = DMDIR|0555;
1507 d.qid.type = QTDIR;
1508 break;
1509 case Qctl:
1510 d.name = "ctl";
1511 d.mode = 0666;
1512 d.qid.type = QTFILE;
1513 break;
1514 case Qmem:
1515 d.name = "mem";
1516 d.mode = 0666;
1517 d.qid.type = QTFILE;
1518 break;
1519 case Qkregs:
1520 d.name = "kregs";
1521 d.mode = 0666;
1522 d.qid.type = QTFILE;
1523 break;
1524 case Qfpregs:
1525 d.name = "fpregs";
1526 d.mode = 0666;
1527 d.qid.type = QTFILE;
1528 break;
1529 case Qproc:
1530 d.name = "proc";
1531 d.mode = 0444;
1532 d.qid.type = QTFILE;
1533 break;
1534 case Qregs:
1535 d.name = "regs";
1536 d.mode = 0666;
1537 d.qid.type = QTFILE;
1538 break;
1539 case Qtext:
1540 d.name = "text";
1541 d.mode = 0444;
1542 d.qid.type = QTFILE;
1543 break;
1544 case Qstatus:
1545 d.name = "status";
1546 d.mode = 0444;
1547 d.qid.type = QTFILE;
1548 break;
1549 }
1550 d.qid.path = path;
1551 d.qid.vers = 0;
1552 d.length = 0;
1553 d.uid = d.gid = d.muid = "none";
1554 d.atime = d.mtime = time(nil);
1555 return convD2M(&d, buf, nbuf);
1556 }
1557
1558 static void
fatal(char * fmt,...)1559 fatal(char *fmt, ...)
1560 {
1561 va_list arg;
1562 char buf[1024];
1563
1564 write(2, "jtagfs: ", 8);
1565 va_start(arg, fmt);
1566 vseprint(buf, buf+1024, fmt, arg);
1567 va_end(arg);
1568 write(2, buf, strlen(buf));
1569 write(2, "\n", 1);
1570 exits(fmt);
1571 }
1572
1573 static void *
emalloc(uint n)1574 emalloc(uint n)
1575 {
1576 void *p;
1577
1578 p = malloc(n);
1579 if(p == nil)
1580 fatal("out of memory");
1581 memset(p, 0, n);
1582 return p;
1583 }
1584
1585 static void
usage(void)1586 usage(void)
1587 {
1588 fprint(2, "usage: jtagfs [-t text] [-d debug] [-m mountpoint] [-s srvfile] jtag\n");
1589 exits("usage");
1590 }
1591