1 #include <u.h>
2 #include <libc.h>
3 #include "dat.h"
4 #include "fns.h"
5
6 /* for fs */
7 #include <auth.h>
8 #include <fcall.h>
9 #include <thread.h>
10 #include <9p.h>
11
12 #include "/386/include/ureg.h"
13
14 enum {
15 MEMSIZE = 0x100000,
16
17 RMBUF = 0x9000,
18 RMCODE = 0x8000,
19
20 PITHZ = 1193182,
21 PITNS = 1000000000/PITHZ,
22 };
23
24 static Cpu cpu;
25 static uchar memory[MEMSIZE+4];
26 static uchar pageregtmp[0x10];
27 static int portfd[5];
28 static int realmemfd;
29 static int cputrace;
30 static int porttrace;
31 static Pit pit[3];
32 static uchar rtcaddr;
33
34 static vlong pitclock;
35
36 static void
startclock(void)37 startclock(void)
38 {
39 pitclock = nsec();
40 }
41
42 static void
runclock(void)43 runclock(void)
44 {
45 vlong now, dt;
46
47 now = nsec();
48 dt = now - pitclock;
49 if(dt >= PITNS){
50 clockpit(pit, dt/PITNS);
51 pitclock = now;
52 }
53 }
54
55 static ulong
gw1(uchar * p)56 gw1(uchar *p)
57 {
58 return p[0];
59 }
60 static ulong
gw2(uchar * p)61 gw2(uchar *p)
62 {
63 return (ulong)p[0] | (ulong)p[1]<<8;
64 }
65 static ulong
gw4(uchar * p)66 gw4(uchar *p)
67 {
68 return (ulong)p[0] | (ulong)p[1]<<8 | (ulong)p[2]<<16 | (ulong)p[3]<<24;
69 }
70 static ulong (*gw[5])(uchar *p) = {
71 [1] gw1,
72 [2] gw2,
73 [4] gw4,
74 };
75
76 static void
pw1(uchar * p,ulong w)77 pw1(uchar *p, ulong w)
78 {
79 p[0] = w & 0xFF;
80 }
81 static void
pw2(uchar * p,ulong w)82 pw2(uchar *p, ulong w)
83 {
84 p[0] = w & 0xFF;
85 p[1] = (w>>8) & 0xFF;
86 }
87 static void
pw4(uchar * p,ulong w)88 pw4(uchar *p, ulong w)
89 {
90 p[0] = w & 0xFF;
91 p[1] = (w>>8) & 0xFF;
92 p[2] = (w>>16) & 0xFF;
93 p[3] = (w>>24) & 0xFF;
94 }
95 static void (*pw[5])(uchar *p, ulong w) = {
96 [1] pw1,
97 [2] pw2,
98 [4] pw4,
99 };
100
101 static ulong
rbad(void *,ulong off,int)102 rbad(void *, ulong off, int)
103 {
104 fprint(2, "bad mem read %.5lux\n", off);
105 trap(&cpu, EMEM);
106
107 /* not reached */
108 return 0;
109 }
110
111 static void
wbad(void *,ulong off,ulong,int)112 wbad(void *, ulong off, ulong, int)
113 {
114 fprint(2, "bad mem write %.5lux\n", off);
115 trap(&cpu, EMEM);
116 }
117
118 static ulong
rmem(void *,ulong off,int len)119 rmem(void *, ulong off, int len)
120 {
121 return gw[len](memory + off);
122 }
123
124 static void
wmem(void *,ulong off,ulong w,int len)125 wmem(void *, ulong off, ulong w, int len)
126 {
127 pw[len](memory + off, w);
128 }
129
130 static ulong
rrealmem(void *,ulong off,int len)131 rrealmem(void *, ulong off, int len)
132 {
133 uchar data[4];
134
135 if(pread(realmemfd, data, len, off) != len){
136 fprint(2, "bad real mem read %.5lux: %r\n", off);
137 trap(&cpu, EMEM);
138 }
139 return gw[len](data);
140 }
141
142 static void
wrealmem(void *,ulong off,ulong w,int len)143 wrealmem(void *, ulong off, ulong w, int len)
144 {
145 uchar data[4];
146
147 pw[len](data, w);
148 if(pwrite(realmemfd, data, len, off) != len){
149 fprint(2, "bad real mem write %.5lux: %r\n", off);
150 trap(&cpu, EMEM);
151 }
152 }
153
154
155 static ulong
rport(void *,ulong p,int len)156 rport(void *, ulong p, int len)
157 {
158 uchar data[4];
159 ulong w;
160
161 switch(p){
162 case 0x20: /* PIC 1 */
163 case 0x21:
164 w = 0;
165 break;
166 case 0x40:
167 case 0x41:
168 case 0x42:
169 case 0x43:
170 runclock();
171 w = rpit(pit, p - 0x40);
172 break;
173 case 0x60: /* keyboard data output buffer */
174 w = 0;
175 break;
176 case 0x61: /* keyboard controller port b */
177 runclock();
178 w = pit[2].out<<5 | pit[2].gate;
179 break;
180 case 0x62: /* PPI (XT only) */
181 runclock();
182 w = pit[2].out<<5;
183 break;
184 case 0x63: /* PPI (XT only) read dip switches */
185 w = 0;
186 break;
187 case 0x65: /* A20 gate */
188 w = 1 << 2;
189 break;
190 case 0x70: /* RTC addr */
191 w = rtcaddr;
192 break;
193 case 0x71: /* RTC data */
194 w = 0xFF;
195 break;
196 case 0x80: /* extra dma registers (temp) */
197 case 0x84:
198 case 0x85:
199 case 0x86:
200 case 0x88:
201 case 0x8c:
202 case 0x8d:
203 case 0x8e:
204 w = pageregtmp[p-0x80];
205 break;
206 case 0x92: /* A20 gate (system control port a) */
207 w = 1 << 1;
208 break;
209 case 0xa0: /* PIC 2 */
210 case 0xa1:
211 w = 0;
212 break;
213 default:
214 if(pread(portfd[len], data, len, p) != len){
215 fprint(2, "bad %d bit port read %.4lux: %r\n", len*8, p);
216 trap(&cpu, EIO);
217 }
218 w = gw[len](data);
219 }
220 if(porttrace)
221 fprint(2, "rport %.4lux %.*lux\n", p, len<<1, w);
222 return w;
223 }
224
225 static void
wport(void *,ulong p,ulong w,int len)226 wport(void *, ulong p, ulong w, int len)
227 {
228 uchar data[4];
229
230 if(porttrace)
231 fprint(2, "wport %.4lux %.*lux\n", p, len<<1, w);
232
233 switch(p){
234 case 0x20: /* PIC 1 */
235 case 0x21:
236 break;
237 case 0x40:
238 case 0x41:
239 case 0x42:
240 case 0x43:
241 runclock();
242 wpit(pit, p - 0x40, w);
243 break;
244 case 0x60: /* keyboard controller data port */
245 break;
246 case 0x61: /* keyboard controller port B */
247 setgate(&pit[2], w & 1);
248 break;
249 case 0x62: /* PPI (XT only) */
250 case 0x63:
251 case 0x64: /* KB controller input buffer (ISA, EISA) */
252 case 0x65: /* A20 gate (bit 2) */
253 break;
254 case 0x70: /* RTC addr */
255 rtcaddr = w & 0xFF;
256 break;
257 case 0x71: /* RTC data */
258 break;
259 case 0x80:
260 case 0x84:
261 case 0x85:
262 case 0x86:
263 case 0x88:
264 case 0x8c:
265 case 0x8d:
266 case 0x8e:
267 pageregtmp[p-0x80] = w & 0xFF;
268 break;
269 case 0x92: /* system control port a */
270 case 0x94: /* system port enable setup register */
271 case 0x96:
272 break;
273 case 0xA0: /* PIC 2 */
274 case 0xA1:
275 break;
276
277 default:
278 pw[len](data, w);
279 if(pwrite(portfd[len], data, len, p) != len){
280 fprint(2, "bad %d bit port write %.4lux: %r\n", len*8, p);
281 trap(&cpu, EIO);
282 }
283 }
284 }
285
286 static Bus memio[] = {
287 /* 0 */ memory, rmem, wmem, /* RAM: IVT, BIOS data area */
288 /* 1 */ memory, rmem, wmem, /* custom */
289 /* 2 */ nil, rbad, wbad,
290 /* 3 */ nil, rbad, wbad,
291 /* 4 */ nil, rbad, wbad,
292 /* 5 */ nil, rbad, wbad,
293 /* 6 */ nil, rbad, wbad,
294 /* 7 */ nil, rbad, wbad,
295 /* 8 */ nil, rbad, wbad,
296 /* 9 */ memory, rmem, wmem, /* RAM: extended BIOS data area */
297 /* A */ nil, rrealmem, wrealmem, /* RAM: VGA framebuffer */
298 /* B */ nil, rrealmem, wrealmem, /* RAM: VGA framebuffer */
299 /* C */ memory, rmem, wmem, /* ROM: VGA BIOS */
300 /* D */ nil, rbad, wbad,
301 /* E */ memory, rmem, wmem, /* ROM: BIOS */
302 /* F */ memory, rmem, wbad, /* ROM: BIOS */
303 };
304
305 static Bus portio = {
306 nil, rport, wport,
307 };
308
309 static void
cpuinit(void)310 cpuinit(void)
311 {
312 int i;
313
314 fmtinstall('I', instfmt);
315 fmtinstall('J', flagfmt);
316 fmtinstall('C', cpufmt);
317
318 if((portfd[1] = open("#P/iob", ORDWR)) < 0)
319 sysfatal("open iob: %r");
320 if((portfd[2] = open("#P/iow", ORDWR)) < 0)
321 sysfatal("open iow: %r");
322 if((portfd[4] = open("#P/iol", ORDWR)) < 0)
323 sysfatal("open iol: %r");
324
325 if((realmemfd = open("#P/realmodemem", ORDWR)) < 0)
326 sysfatal("open realmodemem: %r");
327
328 for(i=0; i<nelem(memio); i++){
329 ulong off;
330
331 if(memio[i].r != rmem)
332 continue;
333
334 off = (ulong)i << 16;
335 seek(realmemfd, off, 0);
336 if(readn(realmemfd, memory + off, 0x10000) != 0x10000)
337 sysfatal("read real mem %lux: %r\n", off);
338 }
339
340 cpu.ic = 0;
341 cpu.mem = memio;
342 cpu.port = &portio;
343 cpu.alen = cpu.olen = cpu.slen = 2;
344 }
345
346 static char Ebusy[] = "device is busy";
347 static char Eintr[] = "interrupted";
348 static char Eperm[] = "permission denied";
349 static char Eio[] = "i/o error";
350 static char Emem[] = "bad memory access";
351 static char Enonexist[] = "file does not exist";
352 static char Ebadspec[] = "bad attach specifier";
353 static char Ewalk[] = "walk in non directory";
354 static char Ebadureg[] = "write a Ureg";
355 static char Ebadoff[] = "invalid offset";
356 static char Ebadtrap[] = "bad trap";
357
358 static char *trapstr[] = {
359 [EDIV0] "division by zero",
360 [EDEBUG] "debug exception",
361 [ENMI] "not maskable interrupt",
362 [EBRK] "breakpoint",
363 [EINTO] "into overflow",
364 [EBOUND] "bounds check",
365 [EBADOP] "bad opcode",
366 [ENOFPU] "no fpu installed",
367 [EDBLF] "double fault",
368 [EFPUSEG] "fpu segment overflow",
369 [EBADTSS] "invalid task state segment",
370 [ENP] "segment not present",
371 [ESTACK] "stack fault",
372 [EGPF] "general protection fault",
373 [EPF] "page fault",
374 };
375
376 static int flushed(void *);
377
378 #define GETUREG(x) gw[sizeof(u->x)]((uchar*)&u->x)
379 #define PUTUREG(x,y) pw[sizeof(u->x)]((uchar*)&u->x,y)
380
381 static char*
realmode(Cpu * cpu,struct Ureg * u,void * r)382 realmode(Cpu *cpu, struct Ureg *u, void *r)
383 {
384 char *err;
385 int i;
386
387 cpu->reg[RDI] = GETUREG(di);
388 cpu->reg[RSI] = GETUREG(si);
389 cpu->reg[RBP] = GETUREG(bp);
390 cpu->reg[RBX] = GETUREG(bx);
391 cpu->reg[RDX] = GETUREG(dx);
392 cpu->reg[RCX] = GETUREG(cx);
393 cpu->reg[RAX] = GETUREG(ax);
394
395 cpu->reg[RGS] = GETUREG(gs);
396 cpu->reg[RFS] = GETUREG(fs);
397 cpu->reg[RES] = GETUREG(es);
398 cpu->reg[RDS] = GETUREG(ds);
399
400 cpu->reg[RFL] = GETUREG(flags);
401
402 if(i = GETUREG(trap)){
403 cpu->reg[RSS] = 0x0000;
404 cpu->reg[RSP] = 0x7C00;
405 cpu->reg[RCS] = (RMCODE>>4)&0xF000;
406 cpu->reg[RIP] = RMCODE & 0xFFFF;
407 memory[RMCODE] = 0xf4; /* HLT instruction */
408 if(intr(cpu, i) < 0)
409 return Ebadtrap;
410 } else {
411 cpu->reg[RSS] = GETUREG(ss);
412 cpu->reg[RSP] = GETUREG(sp);
413 cpu->reg[RCS] = GETUREG(cs);
414 cpu->reg[RIP] = GETUREG(pc);
415 }
416
417 startclock();
418 for(;;){
419 if(cputrace)
420 fprint(2, "%C\n", cpu);
421 switch(i = xec(cpu, (porttrace | cputrace) ? 1 : 100000)){
422 case -1:
423 if(flushed(r)){
424 err = Eintr;
425 break;
426 }
427 runclock();
428 continue;
429
430 /* normal interrupts */
431 default:
432 if(intr(cpu, i) < 0){
433 err = Ebadtrap;
434 break;
435 }
436 continue;
437
438 /* pseudo-interrupts */
439 case EHALT:
440 err = nil;
441 break;
442 case EIO:
443 err = Eio;
444 break;
445 case EMEM:
446 err = Emem;
447 break;
448
449 /* processor traps */
450 case EDIV0:
451 case EDEBUG:
452 case ENMI:
453 case EBRK:
454 case EINTO:
455 case EBOUND:
456 case EBADOP:
457 case ENOFPU:
458 case EDBLF:
459 case EFPUSEG:
460 case EBADTSS:
461 case ENP:
462 case ESTACK:
463 case EGPF:
464 case EPF:
465 PUTUREG(trap, i);
466 err = trapstr[i];
467 break;
468 }
469
470 break;
471 }
472
473 if(err)
474 fprint(2, "%s\n%C\n", err, cpu);
475
476 PUTUREG(di, cpu->reg[RDI]);
477 PUTUREG(si, cpu->reg[RSI]);
478 PUTUREG(bp, cpu->reg[RBP]);
479 PUTUREG(bx, cpu->reg[RBX]);
480 PUTUREG(dx, cpu->reg[RDX]);
481 PUTUREG(cx, cpu->reg[RCX]);
482 PUTUREG(ax, cpu->reg[RAX]);
483
484 PUTUREG(gs, cpu->reg[RGS]);
485 PUTUREG(fs, cpu->reg[RFS]);
486 PUTUREG(es, cpu->reg[RES]);
487 PUTUREG(ds, cpu->reg[RDS]);
488
489 PUTUREG(flags, cpu->reg[RFL]);
490
491 PUTUREG(pc, cpu->reg[RIP]);
492 PUTUREG(cs, cpu->reg[RCS]);
493 PUTUREG(sp, cpu->reg[RSP]);
494 PUTUREG(ss, cpu->reg[RSS]);
495
496 return err;
497 }
498
499 enum {
500 Qroot,
501 Qcall,
502 Qmem,
503 Nqid,
504 };
505
506 static struct Qtab {
507 char *name;
508 int mode;
509 int type;
510 int length;
511 } qtab[Nqid] = {
512 "/",
513 DMDIR|0555,
514 QTDIR,
515 0,
516
517 "realmode",
518 0666,
519 0,
520 0,
521
522 "realmodemem",
523 0666,
524 0,
525 MEMSIZE,
526 };
527
528 static int
fillstat(ulong qid,Dir * d)529 fillstat(ulong qid, Dir *d)
530 {
531 struct Qtab *t;
532
533 memset(d, 0, sizeof(Dir));
534 d->uid = "realemu";
535 d->gid = "realemu";
536 d->muid = "";
537 d->qid = (Qid){qid, 0, 0};
538 d->atime = time(0);
539 t = qtab + qid;
540 d->name = t->name;
541 d->qid.type = t->type;
542 d->mode = t->mode;
543 d->length = t->length;
544 return 1;
545 }
546
547 static void
fsattach(Req * r)548 fsattach(Req *r)
549 {
550 char *spec;
551
552 spec = r->ifcall.aname;
553 if(spec && spec[0]){
554 respond(r, Ebadspec);
555 return;
556 }
557 r->fid->qid = (Qid){Qroot, 0, QTDIR};
558 r->ofcall.qid = r->fid->qid;
559 respond(r, nil);
560 }
561
562 static void
fsstat(Req * r)563 fsstat(Req *r)
564 {
565 fillstat((ulong)r->fid->qid.path, &r->d);
566 r->d.name = estrdup9p(r->d.name);
567 r->d.uid = estrdup9p(r->d.uid);
568 r->d.gid = estrdup9p(r->d.gid);
569 r->d.muid = estrdup9p(r->d.muid);
570 respond(r, nil);
571 }
572
573 static char*
fswalk1(Fid * fid,char * name,Qid * qid)574 fswalk1(Fid *fid, char *name, Qid *qid)
575 {
576 int i;
577 ulong path;
578
579 path = fid->qid.path;
580 switch(path){
581 case Qroot:
582 if (strcmp(name, "..") == 0) {
583 *qid = (Qid){Qroot, 0, QTDIR};
584 fid->qid = *qid;
585 return nil;
586 }
587 for(i = fid->qid.path; i<Nqid; i++){
588 if(strcmp(name, qtab[i].name) != 0)
589 continue;
590 *qid = (Qid){i, 0, 0};
591 fid->qid = *qid;
592 return nil;
593 }
594 return Enonexist;
595
596 default:
597 return Ewalk;
598 }
599 }
600
601 static void
fsopen(Req * r)602 fsopen(Req *r)
603 {
604 static int need[4] = { 4, 2, 6, 1 };
605 struct Qtab *t;
606 int n;
607
608 t = qtab + r->fid->qid.path;
609 n = need[r->ifcall.mode & 3];
610 if((n & t->mode) != n)
611 respond(r, Eperm);
612 else
613 respond(r, nil);
614 }
615
616 static int
readtopdir(Fid *,uchar * buf,long off,int cnt,int blen)617 readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
618 {
619 int i, m, n;
620 long pos;
621 Dir d;
622
623 n = 0;
624 pos = 0;
625 for (i = 1; i < Nqid; i++){
626 fillstat(i, &d);
627 m = convD2M(&d, &buf[n], blen-n);
628 if(off <= pos){
629 if(m <= BIT16SZ || m > cnt)
630 break;
631 n += m;
632 cnt -= m;
633 }
634 pos += m;
635 }
636 return n;
637 }
638
639 static Channel *reqchan;
640
641 static void
cpuproc(void *)642 cpuproc(void *)
643 {
644 static struct Ureg rmu;
645 ulong path;
646 vlong o;
647 ulong n;
648 char *p;
649 Req *r;
650
651 threadsetname("cpuproc");
652
653 while(r = recvp(reqchan)){
654 if(flushed(r)){
655 respond(r, Eintr);
656 continue;
657 }
658
659 path = r->fid->qid.path;
660
661 p = r->ifcall.data;
662 n = r->ifcall.count;
663 o = r->ifcall.offset;
664
665 switch(((int)r->ifcall.type<<8)|path){
666 case (Tread<<8) | Qmem:
667 readbuf(r, memory, MEMSIZE);
668 respond(r, nil);
669 break;
670
671 case (Tread<<8) | Qcall:
672 readbuf(r, &rmu, sizeof rmu);
673 respond(r, nil);
674 break;
675
676 case (Twrite<<8) | Qmem:
677 if(o < 0 || o >= MEMSIZE || o+n > MEMSIZE){
678 respond(r, Ebadoff);
679 break;
680 }
681 memmove(memory + o, p, n);
682 r->ofcall.count = n;
683 respond(r, nil);
684 break;
685
686 case (Twrite<<8) | Qcall:
687 if(n != sizeof rmu){
688 respond(r, Ebadureg);
689 break;
690 }
691 memmove(&rmu, p, n);
692 if(p = realmode(&cpu, &rmu, r)){
693 respond(r, p);
694 break;
695 }
696 r->ofcall.count = n;
697 respond(r, nil);
698 break;
699 }
700 }
701 }
702
703 static Channel *flushchan;
704
705 static int
flushed(void * r)706 flushed(void *r)
707 {
708 return nbrecvp(flushchan) == r;
709 }
710
711 static void
fsflush(Req * r)712 fsflush(Req *r)
713 {
714 nbsendp(flushchan, r->oldreq);
715 respond(r, nil);
716 }
717
718 static void
dispatch(Req * r)719 dispatch(Req *r)
720 {
721 if(!nbsendp(reqchan, r))
722 respond(r, Ebusy);
723 }
724
725 static void
fsread(Req * r)726 fsread(Req *r)
727 {
728 switch((ulong)r->fid->qid.path){
729 case Qroot:
730 r->ofcall.count = readtopdir(r->fid, (void*)r->ofcall.data, r->ifcall.offset,
731 r->ifcall.count, r->ifcall.count);
732 respond(r, nil);
733 break;
734 default:
735 dispatch(r);
736 }
737 }
738
739 static void
fsend(Srv *)740 fsend(Srv*)
741 {
742 threadexitsall(nil);
743 }
744
745 static Srv fs = {
746 .attach= fsattach,
747 .walk1= fswalk1,
748 .open= fsopen,
749 .read= fsread,
750 .write= dispatch,
751 .stat= fsstat,
752 .flush= fsflush,
753 .end= fsend,
754 };
755
756 static void
usage(void)757 usage(void)
758 {
759 fprint(2, "usgae:\t%s [-Dpt] [-s srvname] [-m mountpoint]\n", argv0);
760 exits("usage");
761 }
762
763 void
threadmain(int argc,char * argv[])764 threadmain(int argc, char *argv[])
765 {
766 char *mnt = "/dev";
767 char *srv = nil;
768
769 ARGBEGIN{
770 case 'D':
771 chatty9p++;
772 break;
773 case 'p':
774 porttrace = 1;
775 break;
776 case 't':
777 cputrace = 1;
778 break;
779 case 's':
780 srv = EARGF(usage());
781 mnt = nil;
782 break;
783 case 'm':
784 mnt = EARGF(usage());
785 break;
786 default:
787 usage();
788 }ARGEND
789
790 cpuinit();
791
792 reqchan = chancreate(sizeof(Req*), 8);
793 flushchan = chancreate(sizeof(Req*), 8);
794 procrfork(cpuproc, nil, 16*1024, RFNAMEG|RFNOTEG);
795 threadpostmountsrv(&fs, srv, mnt, MBEFORE);
796 }
797