#include #include #include "dat.h" #include "fns.h" /* for fs */ #include #include <9P2000.h> #include #include <9p.h> #include // hacks from 386 age enum { MEMSIZE = 0x100000, RMBUF = 0x9000, RMCODE = 0x8000, PITHZ = 1193182, PITNS = 1000000000/PITHZ, }; static Cpu cpu; static unsigned char memory[MEMSIZE+4]; static unsigned char pageregtmp[0x10]; static int portfd[5]; static int realmemfd; static int cputrace; static int porttrace; static Pit pit[3]; static unsigned char rtcaddr; static long long pitclock; static void startclock(void) { print_func_entry(); pitclock = nsec(); print_func_exit(); } static void runclock(void) { print_func_entry(); long long now, dt; now = nsec(); dt = now - pitclock; if(dt >= PITNS){ clockpit(pit, dt/PITNS); pitclock = now; } print_func_exit(); } static unsigned long gw1(unsigned char *p) { print_func_entry(); print_func_exit(); return p[0]; } static unsigned long gw2(unsigned char *p) { print_func_entry(); print_func_exit(); return (unsigned long)p[0] | (unsigned long)p[1]<<8; } static unsigned long gw4(unsigned char *p) { print_func_entry(); print_func_exit(); return (unsigned long)p[0] | (unsigned long)p[1]<<8 | (unsigned long)p[2]<<16 | (unsigned long)p[3]<<24; } static unsigned long (*gw[9])(unsigned char *p) = { [1] gw1, [2] gw2, [4] gw4, [8] gw4, }; static void pw1(unsigned char *p, unsigned long w) { print_func_entry(); p[0] = w & 0xFF; print_func_exit(); } static void pw2(unsigned char *p, unsigned long w) { print_func_entry(); p[0] = w & 0xFF; p[1] = (w>>8) & 0xFF; print_func_exit(); } static void pw4(unsigned char *p, unsigned long w) { print_func_entry(); p[0] = w & 0xFF; p[1] = (w>>8) & 0xFF; p[2] = (w>>16) & 0xFF; p[3] = (w>>24) & 0xFF; print_func_exit(); } static void (*pw[5])(unsigned char *p, unsigned long w) = { [1] pw1, [2] pw2, [4] pw4, }; static unsigned long rbad(void *aux, unsigned long off, int len) { print_func_entry(); fprint(2, "bad mem read %.5lux\n", off); trap(&cpu, EMEM); /* not reached */ print_func_exit(); return 0; } static void wbad(void *aux, unsigned long off, unsigned long w, int len) { print_func_entry(); fprint(2, "bad mem write %.5lux\n", off); trap(&cpu, EMEM); print_func_exit(); } static unsigned long rmem(void *aux, unsigned long off, int len) { print_func_entry(); print_func_exit(); return gw[len](memory + off); } static void wmem(void *aux, unsigned long off, unsigned long w, int len) { print_func_entry(); pw[len](memory + off, w); print_func_exit(); } static unsigned long rrealmem(void *aux, unsigned long off, int len) { print_func_entry(); unsigned char data[4]; if(sys_pread(realmemfd, data, len, off) != len){ fprint(2, "bad real mem read %.5lux: %r\n", off); trap(&cpu, EMEM); } print_func_exit(); return gw[len](data); } static void wrealmem(void *aux, unsigned long off, unsigned long w, int len) { print_func_entry(); unsigned char data[4]; pw[len](data, w); if(sys_pwrite(realmemfd, data, len, off) != len){ fprint(2, "bad real mem write %.5lux: %r\n", off); trap(&cpu, EMEM); } print_func_exit(); } static unsigned long rport(void *aux, unsigned long p, int len) { print_func_entry(); unsigned char data[4]; unsigned long w; switch(p){ case 0x20: /* PIC 1 */ case 0x21: w = 0; break; case 0x40: case 0x41: case 0x42: case 0x43: runclock(); w = rpit(pit, p - 0x40); break; case 0x60: /* keyboard data output buffer */ w = 0; break; case 0x61: /* keyboard controller port b */ runclock(); w = pit[2].out<<5 | pit[2].gate; break; case 0x62: /* PPI (XT only) */ runclock(); w = pit[2].out<<5; break; case 0x63: /* PPI (XT only) read dip switches */ w = 0; break; case 0x65: /* A20 gate */ w = 1 << 2; break; case 0x70: /* RTC addr */ w = rtcaddr; break; case 0x71: /* RTC data */ w = 0xFF; break; case 0x80: /* extra dma registers (temp) */ case 0x84: case 0x85: case 0x86: case 0x88: case 0x8c: case 0x8d: case 0x8e: w = pageregtmp[p-0x80]; break; case 0x92: /* A20 gate (system control port a) */ w = 1 << 1; break; case 0xa0: /* PIC 2 */ case 0xa1: w = 0; break; default: if(sys_pread(portfd[len], data, len, p) != len){ fprint(2, "bad %d bit port read %.4lux: %r\n", len*8, p); trap(&cpu, EIO); } w = gw[len](data); } if(porttrace) fprint(2, "rport %.4lux %.*lux\n", p, len<<1, w); print_func_exit(); return w; } static void wport(void *aux, unsigned long p, unsigned long w, int len) { print_func_entry(); unsigned char data[4]; if(porttrace) fprint(2, "wport %.4lux %.*lux\n", p, len<<1, w); switch(p){ case 0x20: /* PIC 1 */ case 0x21: break; case 0x40: case 0x41: case 0x42: case 0x43: runclock(); wpit(pit, p - 0x40, w); break; case 0x60: /* keyboard controller data port */ break; case 0x61: /* keyboard controller port B */ setgate(&pit[2], w & 1); break; case 0x62: /* PPI (XT only) */ case 0x63: case 0x64: /* KB controller input buffer (ISA, EISA) */ case 0x65: /* A20 gate (bit 2) */ break; case 0x70: /* RTC addr */ rtcaddr = w & 0xFF; break; case 0x71: /* RTC data */ break; case 0x80: case 0x84: case 0x85: case 0x86: case 0x88: case 0x8c: case 0x8d: case 0x8e: pageregtmp[p-0x80] = w & 0xFF; break; case 0x92: /* system control port a */ case 0x94: /* system port enable setup register */ case 0x96: break; case 0xA0: /* PIC 2 */ case 0xA1: break; default: pw[len](data, w); if(sys_pwrite(portfd[len], data, len, p) != len){ fprint(2, "bad %d bit port write %.4lux: %r\n", len*8, p); trap(&cpu, EIO); } } print_func_exit(); } static Bus memio[] = { /* 0 */ memory, rmem, wmem, /* RAM: IVT, BIOS data area */ /* 1 */ memory, rmem, wmem, /* custom */ /* 2 */ nil, rbad, wbad, /* 3 */ nil, rbad, wbad, /* 4 */ nil, rbad, wbad, /* 5 */ nil, rbad, wbad, /* 6 */ nil, rbad, wbad, /* 7 */ nil, rbad, wbad, /* 8 */ nil, rbad, wbad, /* 9 */ memory, rmem, wmem, /* RAM: extended BIOS data area */ /* A */ nil, rrealmem, wrealmem, /* RAM: VGA framebuffer */ /* B */ nil, rrealmem, wrealmem, /* RAM: VGA framebuffer */ /* C */ memory, rmem, wmem, /* ROM: VGA BIOS */ /* D */ nil, rbad, wbad, /* E */ memory, rmem, wmem, /* ROM: BIOS */ /* F */ memory, rmem, wbad, /* ROM: BIOS */ }; static Bus portio = { nil, rport, wport, }; static void cpuinit(void) { print_func_entry(); int i; fmtinstall('I', instfmt); fmtinstall('J', flagfmt); fmtinstall('C', cpufmt); if((portfd[1] = sys_open("#P/iob", ORDWR)) < 0) sysfatal("open iob: %r"); if((portfd[2] = sys_open("#P/iow", ORDWR)) < 0) sysfatal("open iow: %r"); if((portfd[4] = sys_open("#P/iol", ORDWR)) < 0) sysfatal("open iol: %r"); if((realmemfd = sys_open("#P/realmodemem", ORDWR)) < 0) sysfatal("open realmodemem: %r"); for(i=0; ix)]((unsigned char*)&u->x) #define PUTUREG(x,y) pw[sizeof(u->x)]((unsigned char*)&u->x,y) static char* realmode(Cpu *cpu, struct VGAreg *u, void *r) { print_func_entry(); char *err; int i; /* N.B. it wasy always 16 bits in the kernel. */ cpu->reg[RDI] = GETUREG(di) & 0xffff; cpu->reg[RSI] = GETUREG(si); cpu->reg[RBP] = GETUREG(bp); cpu->reg[RBX] = GETUREG(bx); cpu->reg[RDX] = GETUREG(dx); cpu->reg[RCX] = GETUREG(cx); cpu->reg[RAX] = GETUREG(ax); cpu->reg[RGS] = GETUREG(gs); cpu->reg[RFS] = GETUREG(fs); cpu->reg[RES] = GETUREG(di) >> 16; cpu->reg[RDS] = GETUREG(ds); cpu->reg[RFL] = GETUREG(flags); if(i = GETUREG(trap)){ cpu->reg[RSS] = 0x0000; cpu->reg[RSP] = 0x7C00; cpu->reg[RCS] = (RMCODE>>4)&0xF000; cpu->reg[RIP] = RMCODE & 0xFFFF; memory[RMCODE] = 0xf4; /* HLT instruction */ if(intr(cpu, i) < 0) return Ebadtrap; } else { cpu->reg[RSS] = GETUREG(ss); cpu->reg[RSP] = GETUREG(sp); cpu->reg[RCS] = GETUREG(cs); cpu->reg[RIP] = GETUREG(pc); } startclock(); for(;;){ if(cputrace) fprint(2, "%C\n", cpu); switch(i = xec(cpu, (porttrace | cputrace) ? 1 : 100000)){ case -1: if(flushed(r)){ err = Eintr; break; } runclock(); continue; /* normal interrupts */ default: if(intr(cpu, i) < 0){ err = Ebadtrap; break; } continue; /* pseudo-interrupts */ case EHALT: err = nil; break; case EIO: err = Eio; break; case EMEM: err = Emem; break; /* processor traps */ case EDIV0: case EDEBUG: case ENMI: case EBRK: case EINTO: case EBOUND: case EBADOP: case ENOFPU: case EDBLF: case EFPUSEG: case EBADTSS: case ENP: case ESTACK: case EGPF: case EPF: PUTUREG(trap, i); err = trapstr[i]; break; } break; } if(err) fprint(2, "%s\n%C\n", err, cpu); PUTUREG(di, cpu->reg[RDI]); PUTUREG(si, cpu->reg[RSI]); PUTUREG(bp, cpu->reg[RBP]); PUTUREG(bx, cpu->reg[RBX]); PUTUREG(dx, cpu->reg[RDX]); PUTUREG(cx, cpu->reg[RCX]); PUTUREG(ax, cpu->reg[RAX]); PUTUREG(gs, cpu->reg[RGS]); PUTUREG(fs, cpu->reg[RFS]); PUTUREG(es, cpu->reg[RES]); PUTUREG(ds, cpu->reg[RDS]); PUTUREG(flags, cpu->reg[RFL]); PUTUREG(pc, cpu->reg[RIP]); PUTUREG(cs, cpu->reg[RCS]); PUTUREG(sp, cpu->reg[RSP]); PUTUREG(ss, cpu->reg[RSS]); print_func_exit(); return err; } enum { Qroot, Qcall, Qmem, Nqid, }; static struct Qtab { char *name; int mode; int type; int length; } qtab[Nqid] = { "/", DMDIR|0555, QTDIR, 0, "realmode", 0666, 0, 0, "realmodemem", 0666, 0, MEMSIZE, }; static int fillstat(unsigned long qid, Dir *d) { print_func_entry(); struct Qtab *t; memset(d, 0, sizeof(Dir)); d->uid = "realemu"; d->gid = "realemu"; d->muid = ""; d->qid = (Qid){qid, 0, 0}; d->atime = time(0); t = qtab + qid; d->name = t->name; d->qid.type = t->type; d->mode = t->mode; d->length = t->length; print_func_exit(); return 1; } static void fsattach(Req *r) { print_func_entry(); char *spec; spec = r->ifcall.aname; if(spec && spec[0]){ respond(r, Ebadspec); print_func_exit(); return; } r->fid->qid = (Qid){Qroot, 0, QTDIR}; r->ofcall.qid = r->fid->qid; respond(r, nil); print_func_exit(); } static void fsstat(Req *r) { print_func_entry(); fillstat((unsigned long)r->fid->qid.path, &r->d); r->d.name = estrdup9p(r->d.name); r->d.uid = estrdup9p(r->d.uid); r->d.gid = estrdup9p(r->d.gid); r->d.muid = estrdup9p(r->d.muid); respond(r, nil); print_func_exit(); } static char* fswalk1(Fid *fid, char *name, Qid *qid) { print_func_entry(); int i; unsigned long path; path = fid->qid.path; switch(path){ case Qroot: if (strcmp(name, "..") == 0) { *qid = (Qid){Qroot, 0, QTDIR}; fid->qid = *qid; print_func_exit(); return nil; } for(i = fid->qid.path; iqid = *qid; print_func_exit(); return nil; } print_func_exit(); return Enonexist; default: print_func_exit(); return Ewalk; } } static void fsopen(Req *r) { print_func_entry(); static int need[4] = { 4, 2, 6, 1 }; struct Qtab *t; int n; t = qtab + r->fid->qid.path; n = need[r->ifcall.mode & 3]; if((n & t->mode) != n) respond(r, Eperm); else respond(r, nil); print_func_exit(); } static int readtopdir(Fid *fid, unsigned char *buf, long off, int cnt, int blen) { print_func_entry(); int i, m, n; long pos; Dir d; n = 0; pos = 0; for (i = 1; i < Nqid; i++){ fillstat(i, &d); m = convD2M(&d, &buf[n], blen-n); if(off <= pos){ if(m <= BIT16SZ || m > cnt) break; n += m; cnt -= m; } pos += m; } print_func_exit(); return n; } static Channel *reqchan; static void cpuproc(void *data) { print_func_entry(); static struct VGAreg rmu; unsigned long path; long long o; unsigned long n; char *p; Req *r; threadsetname("cpuproc"); while(r = recvp(reqchan)){ if(flushed(r)){ respond(r, Eintr); continue; } path = r->fid->qid.path; p = r->ifcall.data; n = r->ifcall.count; o = r->ifcall.offset; switch(((int)r->ifcall.type<<8)|path){ case (Tread<<8) | Qmem: readbuf(r, memory, MEMSIZE); respond(r, nil); break; case (Tread<<8) | Qcall: readbuf(r, &rmu, sizeof rmu); respond(r, nil); break; case (Twrite<<8) | Qmem: if(o < 0 || o >= MEMSIZE || o+n > MEMSIZE){ respond(r, Ebadoff); break; } memmove(memory + o, p, n); r->ofcall.count = n; respond(r, nil); break; case (Twrite<<8) | Qcall: if(n != sizeof rmu){ fprint(2, "n is %d, sizeof(rmu) %d: %s\n", n, sizeof(rmu), Ebadureg); respond(r, Ebadureg); break; } memmove(&rmu, p, n); if(p = realmode(&cpu, &rmu, r)){ respond(r, p); break; } r->ofcall.count = n; respond(r, nil); break; } } print_func_exit(); } static Channel *flushchan; static int flushed(void *r) { print_func_entry(); print_func_exit(); return nbrecvp(flushchan) == r; } static void fsflush(Req *r) { print_func_entry(); nbsendp(flushchan, r->oldreq); respond(r, nil); print_func_exit(); } static void dispatch(Req *r) { print_func_entry(); if(!nbsendp(reqchan, r)) respond(r, Ebusy); print_func_exit(); } static void fsread(Req *r) { print_func_entry(); switch((unsigned long)r->fid->qid.path){ case Qroot: r->ofcall.count = readtopdir(r->fid, (void*)r->ofcall.data, r->ifcall.offset, r->ifcall.count, r->ifcall.count); respond(r, nil); break; default: dispatch(r); } print_func_exit(); } static void fsend(Srv* srv) { print_func_entry(); threadexitsall(nil); print_func_exit(); } static Srv fs = { .attach= fsattach, .walk1= fswalk1, .open= fsopen, .read= fsread, .write= dispatch, .stat= fsstat, .flush= fsflush, .end= fsend, }; static void usage(void) { print_func_entry(); fprint(2, "usgae:\t%s [-Dpt] [-s srvname] [-m mountpoint]\n", argv0); exits("usage"); print_func_exit(); } void threadmain(int argc, char *argv[]) { char *mnt = "/dev"; char *srv = nil; ARGBEGIN{ case 'D': chatty9p++; break; case 'p': porttrace = 1; break; case 't': cputrace = 1; break; case 'x': set_printx(1); break; case 's': srv = EARGF(usage()); mnt = nil; break; case 'm': mnt = EARGF(usage()); break; default: usage(); }ARGEND cpuinit(); reqchan = chancreate(sizeof(Req*), 8); flushchan = chancreate(sizeof(Req*), 8); procrfork(cpuproc, nil, 16*1024, RFNAMEG|RFNOTEG); threadpostmountsrv(&fs, srv, mnt, MBEFORE); }