From 00226baff35ca72828ab9237da61a70a0c5f646d Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 12 Oct 2000 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2000-10-12 --- bitsy/dat.h | 23 ++++------- bitsy/l.s | 38 ++++++++++++++++-- bitsy/main.c | 80 +++++++++++++++++++++++++++++++++++-- bitsy/mmu.c | 40 ++++++++++++++----- bitsy/trap.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++-- ip/tcp.c | 6 +++ pc/main.c | 5 ++- pc/mouse.c | 49 +++++++++++++++++++---- port/devmouse.c | 6 ++- port/segment.c | 1 - 10 files changed, 303 insertions(+), 47 deletions(-) diff --git a/bitsy/dat.h b/bitsy/dat.h index 4b6bc9e443b559033c808dcc0cbd0ebd75baa40f..0d8fe4ecab9ce2635f13ae294413edcb9a3f0170 100644 --- a/bitsy/dat.h +++ b/bitsy/dat.h @@ -80,7 +80,7 @@ enum struct PMMU { - ulong pid; /* current pid (0 if none) */ + ulong tlbpid; /* current pid (0 if none) */ Page *l1[Nmeg]; /* this's process' level 1 entries */ }; @@ -114,6 +114,7 @@ struct Mach ulong fairness; /* for runproc */ + /* stats */ int tlbfault; int tlbpurge; int pfault; @@ -123,24 +124,15 @@ struct Mach int intr; vlong fastclock; /* last sampled value */ vlong intrts; /* time stamp of last interrupt */ - int flushmmu; /* make current proc flush it's mmu state */ - ulong spuriousintr; int lastintr; - int loopconst; - - int cpumhz; - int cpuhz; - int cpuidax; - int cpuiddx; - char cpuidid[16]; - char* cpuidtype; + int flushmmu; /* make current proc flush it's mmu state */ + Proc *pid2proc[31]; /* what proc holds what pid */ + int lastpid; /* highest assigned pid slot */ - vlong mtrrcap; - vlong mtrrdef; - vlong mtrrfix[11]; - vlong mtrrvar[32]; /* 256 max. */ + int cpumhz; /* speed of cpu */ + int cpuhz; /* ... * /* save areas for exceptions */ ulong sfiq[5]; @@ -197,4 +189,3 @@ enum { OneMeg= 1024*1024, }; - diff --git a/bitsy/l.s b/bitsy/l.s index 05d570aa4e6ef81de225779ba49a3e5c23dae9fc..3f4abf8be6f23373e357691f4f11237e68beb9a2 100644 --- a/bitsy/l.s +++ b/bitsy/l.s @@ -173,8 +173,8 @@ TEXT vtable(SB), $-4 WORD $_vsvc(SB) /* reset, in svc mode already */ WORD $_vund(SB) /* undefined, switch to svc mode */ WORD $_vsvc(SB) /* swi, in svc mode already */ - WORD $_vabt(SB) /* prefetch abort, switch to svc mode */ - WORD $_vabt(SB) /* data abort, switch to svc mode */ + WORD $_vpabt(SB) /* prefetch abort, switch to svc mode */ + WORD $_vdabt(SB) /* data abort, switch to svc mode */ WORD $_vsvc(SB) /* reserved */ WORD $_virq(SB) /* IRQ, switch to svc mode */ WORD $_vfiq(SB) /* FIQ, switch to svc mode */ @@ -208,11 +208,16 @@ TEXT _vund(SB), $-4 /* undefined */ MOVW $PsrMund, R0 B _vswitch -TEXT _vabt(SB), $-4 /* prefetch abort */ +TEXT _vpabt(SB), $-4 /* prefetch abort */ MOVM.IA [R0-R4], (R13) /* free some working space */ MOVW $PsrMabt, R0 /* r0 = type */ B _vswitch +TEXT _vdabt(SB), $-4 /* prefetch abort */ + MOVM.IA [R0-R4], (R13) /* free some working space */ + MOVW $(PsrMabt+1), R0 /* r0 = type */ + B _vswitch + TEXT _virq(SB), $-4 /* IRQ */ MOVM.IA [R0-R4], (R13) /* free some working space */ MOVW $PsrMirq, R0 /* r0 = type */ @@ -277,6 +282,33 @@ _userexcep: TEXT _vfiq(SB), $-4 /* FIQ */ RFE /* FIQ is special, ignore it for now */ +/* + * This is the first jump from kernel to user mode. + * Fake a return from interrupt. + * + * Enter with R0 containing the user stack pointer. + * UTZERO + 0x20 is always the entry point. + * + */ +TEXT touser(SB),$-4 + /* store the user stack pointer into the USR_r13 */ + MOVM.DB.W [R0], (R13) + MOVM.S.IA.W (R13),[R13] + + /* set up a PSR for user level */ + MOVW $(PsrMusr), R0 + MOVW R0,SPSR + + /* save the PC on the stack */ + MOVW $(UTZERO+0x20), R0 + MOVM.DB.W [R0],(R13) + + /* return from interrupt */ + RFE /* MOVM.IA.S.W (R13), [R15] */ + +/* + * here to jump to a newly forked process + */ TEXT forkret(SB),$-4 ADD $(4*15), R13 /* make r13 point to ureg->type */ MOVW 8(R13), R14 /* restore link */ diff --git a/bitsy/main.c b/bitsy/main.c index 4f67b0224db04c17fb60032fdbd9573ad4b93907..d876595685d8c1972001eeaf98c292e52cc0f43d 100644 --- a/bitsy/main.c +++ b/bitsy/main.c @@ -13,6 +13,8 @@ Conf conf; static void gpioinit(void); +int noprint; + void main(void) { @@ -21,6 +23,7 @@ main(void) /* point to Mach structure */ m = (Mach*)MACHADDR; + memset(m, 0, sizeof(Mach)); rs232power(1); iprint("bitsy kernel\n"); @@ -31,10 +34,16 @@ main(void) sa1100_uartsetup(); gpioinit(); trapinit(); + printinit(); clockinit(); + procinit0(); + initseg(); chandevreset(); +noprint = 1; pageinit(); + swapinit(); userinit(); +iprint("schedinit(), death soon\n"); schedinit(); } @@ -44,7 +53,7 @@ main(void) void exit(int ispanic) { - void (*f)(); + void (*f)(void); USED(ispanic); delay(1000); @@ -55,6 +64,8 @@ exit(int ispanic) (*f)(); } +static uchar *sp; + /* * starting place for first process */ @@ -87,7 +98,66 @@ init0(void) } kproc("alarm", alarmkproc, 0); - touser(); + touser(sp); +} + +/* + * pass boot arguments to /boot + */ +static uchar * +pusharg(char *p) +{ + int n; + + n = strlen(p)+1; + sp -= n; + memmove(sp, p, n); + return sp; +} +static void +bootargs(ulong base) +{ + int i, ac; + uchar *av[32]; + uchar *bootpath; + uchar **lsp; + + /* + * the sizeof(Sargs) is to make the validaddr check in + * trap.c's syscall() work even when we have less than the + * max number of args. + */ + sp = (uchar*)base + BY2PG - sizeof(Sargs); + + bootpath = pusharg("/boot"); + ac = 0; + av[ac++] = pusharg("boot"); + + /* 4 byte word align stack */ + sp = (uchar*)((ulong)sp & ~3); + + /* build argc, argv on stack */ + sp -= (ac+1)*sizeof(sp); + lsp = (uchar**)sp; + for(i = 0; i < ac; i++) + *lsp++ = av[i] + ((USTKTOP - BY2PG) - base); + *lsp = 0; + + /* push argv onto stack */ + sp -= BY2WD; + lsp = (uchar**)sp; + *lsp = sp + BY2WD + ((USTKTOP - BY2PG) - base); + + /* push pointer to "/boot" */ + sp -= BY2WD; + lsp = (uchar**)sp; + *lsp = bootpath + ((USTKTOP - BY2PG) - base); + + /* leave space for where the initcode's caller's return PC would normally reside */ + sp -= BY2WD; + + /* relocate stack to user's virtual addresses */ + sp += (USTKTOP - BY2PG) - base; } /* @@ -112,11 +182,12 @@ userinit(void) strcpy(p->text, "*init*"); strcpy(p->user, eve); + /* * Kernel Stack */ p->sched.pc = (ulong)init0; - p->sched.sp = (ulong)p->kstack+KSTACK-(1+MAXSYSARG)*BY2WD; + p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD); /* * User Stack @@ -125,6 +196,9 @@ userinit(void) p->seg[SSEG] = s; pg = newpage(1, 0, USTKTOP-BY2PG); segpage(s, pg); + k = kmap(pg); + bootargs(VA(k)); + kunmap(k); /* * Text diff --git a/bitsy/mmu.c b/bitsy/mmu.c index cbb325f9dbef49cba2332b063b3a8567fffc0a00..c325ba62a3fc3b0a256ec8df2e792f6b576ebbed 100644 --- a/bitsy/mmu.c +++ b/bitsy/mmu.c @@ -100,11 +100,9 @@ mmuinit(void) t[(a&0xfffff)>>PGSHIFT] = L2SmallPage | L2KernelRW | (PHYSDRAM0 & L2PageBaseMask); /* set up the domain register to cause all domains to obey pte access bits */ - iprint("setting up domain access\n"); putdac(Dclient); /* point to map */ - iprint("setting tlb map %lux\n", (ulong)l1table); putttb((ulong)l1table); /* enable mmu */ @@ -196,14 +194,34 @@ mapspecial(ulong pa, int len) } /* - * find a new pid. If none exist, flush all pids, mmu, and caches. + * maintain pids */ static Lock pidlock; +void +flushpids(void) +{ + memset(l1table, 0, BY2WD*nelem(m->pid2proc)*32); + memset(m->pid2proc, 0, sizeof(m->pid2proc)); + flushcache(); + flushmmu(); +} + int newtlbpid(Proc *p) { - return p->pid; + int i; + + ilock(&pidlock); + i = ++(m->lastpid); + if(i >= nelem(m->pid2proc)){ + flushpids(); + i = m->lastpid = 0; + } + m->pid2proc[i] = p; + p->tlbpid = i+1; + iunlock(&pidlock); + return p->tlbpid; } /* @@ -232,9 +250,10 @@ putmmu(ulong va, ulong pa, Page*) Page *p; ulong *t; - /* if user memory, offset by pid value */ +iprint("putmmu(0x%.8lux, 0x%.8lux)\n", va, pa); + /* if user memory, add pid value */ if((va & 0xfe000000) == 0) - pva = va | (up->pid << 25); + pva = va | (up->tlbpid << 25); else pva = va; @@ -281,10 +300,11 @@ void mmuswitch(Proc* p) { /* set pid */ - if(p->pid <= 0) - p->pid = newtlbpid(p); - putpid(p->pid<<25); + if(p->tlbpid <= 0) + p->tlbpid = newtlbpid(p); +iprint("using tlbpid %d\n", p->tlbpid); + putpid(p->tlbpid<<25); /* set domain register to this + the kernel's domains */ - putdac((Dclient<<(2*p->pid)) | Dclient); + putdac((Dclient<<(2*p->tlbpid)) | Dclient); } diff --git a/bitsy/trap.c b/bitsy/trap.c index 944220b1654ffd9a7b6be5f8503a72dca1fce025..4b44083256d65849ddb5ab656bfbf1e15381309b 100644 --- a/bitsy/trap.c +++ b/bitsy/trap.c @@ -84,6 +84,19 @@ trapdump(char *tag) intrregs->iccr, intrregs->icfp); } +void +dumpregs(Ureg *ur) +{ + iprint("r0 0x%.8lux r1 0x%.8lux r3 0x%.8lux r3 0x%.8lux\n", + ur->r0, ur->r1, ur->r2, ur->r3); + iprint("r4 0x%.8lux r5 0x%.8lux r6 0x%.8lux r7 0x%.8lux\n", + ur->r4, ur->r5, ur->r6, ur->r7); + iprint("r8 0x%.8lux r9 0x%.8lux r10 0x%.8lux r11 0x%.8lux\n", + ur->r8, ur->r9, ur->r10, ur->r11); + iprint("r12 0x%.8lux r13 0x%.8lux r14 0x%.8lux\n", + ur->r12, ur->r13, ur->r14); + iprint("type %.8lux psr %.8lux pc %.8lux\n", ur->type, ur->psr, ur->pc); +} /* * enable an interrupt and attach a function to it @@ -107,6 +120,31 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name) unlock(&vctllock); } +/* + * called by trap to handle access faults + */ +static void +faultarm(Ureg *ureg, ulong va, int user, int read) +{ + int n, insyscall; + char buf[ERRLEN]; + + insyscall = up->insyscall; + up->insyscall = 1; + n = fault(va, read); +iprint("fault returns %d\n", n); + if(n < 0){ + if(!user){ + dumpregs(ureg); + panic("fault: 0x%lux\n", va); + } + sprint(buf, "sys: trap: fault %s va=0x%lux", + read? "read" : "write", va); + postnote(up, 1, buf, NDebug); + } + up->insyscall = insyscall; +} + /* * here on all exceptions other than syscall (SWI) */ @@ -115,15 +153,66 @@ trap(Ureg *ureg) { int i; Vctl *v; + int user; + ulong pc, va; + char buf[ERRLEN]; - iprint("trap %lux pc %lux psr %lux\n", ureg->type, ureg->pc, ureg->psr); - + user = (ureg->psr & PsrMask) == PsrMusr; switch(ureg->type){ default: panic("unknown trap"); break; - case PsrMabt: /* fault */ - panic("faults not implemented"); + case PsrMabt: /* prefetch fault */ + iprint("prefetch abort at %lux\n", ureg->pc-4); + faultarm(ureg, ureg->pc - 4, user, 1); + break; + case PsrMabt+1: /* data fault */ + pc = ureg->pc - 8; + va = getfar(); + switch(getfsr() & 0xf){ + case 0x0: + panic("vector exception at %lux\n", pc); + break; + case 0x1: + case 0x3: + if(user){ + snprint(buf, sizeof(buf), "sys: alignment: pc 0x%lux va 0x%lux\n", + pc, va); + postnote(up, 1, buf, NDebug); + } else + panic("kernel alignment: pc 0x%lux va 0x%lux", pc, va); + break; + case 0x2: + panic("terminal exception at %lux\n", pc); + break; + case 0x4: + case 0x6: + case 0x8: + case 0xa: + case 0xc: + case 0xe: + panic("external abort at %lux\n", pc); + break; + case 0x5: + case 0x7: + /* translation fault, i.e., no pte entry */ + faultarm(ureg, va, user, 0); + break; + case 0x9: + case 0xb: + /* domain fault, accessing something we shouldn't */ + if(user){ + sprint(buf, "sys: access violation: pc 0x%lux va 0x%lux\n", pc, va); + postnote(up, 1, buf, NDebug); + } else + panic("kernel access violation: pc 0x%lux va 0x%lux\n", pc, va); + break; + case 0xd: + case 0xf: + /* permission error, copy on write or real permission error */ + faultarm(ureg, va, user, 1); + break; + } break; case PsrMund: /* undefined instruction */ panic("undefined instruction"); @@ -137,6 +226,11 @@ trap(Ureg *ureg) } break; } + + if(user && (up->procctl || up->nnote)){ + splhi(); + notify(ureg); + } } /* diff --git a/ip/tcp.c b/ip/tcp.c index cc66b90455756ae300ab92c180295889a160ed99..d606da60ec92a27021d8e17a2e4253d55cb0c73f 100644 --- a/ip/tcp.c +++ b/ip/tcp.c @@ -1820,6 +1820,12 @@ tcpoutput(Conv *s) x = backoff(tcb->backoff) * (tcb->mdev + (tcb->srtt>>LOGAGAIN) + MSPTICK) / MSPTICK; + /* allow for slow initial response + * (miller@hamnavoe.demon.co.uk) + */ + if(tcb->state == Syn_sent && x < 500/MSPTICK) + x = 500/MSPTICK; + /* take into account delayed ack */ if(sent <= 2*tcb->mss) x += TCP_ACK/MSPTICK; diff --git a/pc/main.c b/pc/main.c index 9f230c69cac827f422f6519182b1e698912ff6c7..82f7058ebba5922aa6660c2d3725724f83e84b54 100644 --- a/pc/main.c +++ b/pc/main.c @@ -249,11 +249,12 @@ userinit(void) /* * Kernel Stack * - * N.B. The -12 for the stack pointer is important. + * N.B. make sure there's enough space for syscall to check + * for valid args and * 4 bytes for gotolabel's return PC */ p->sched.pc = (ulong)init0; - p->sched.sp = (ulong)p->kstack+KSTACK-(1+MAXSYSARG)*BY2WD; + p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD); /* * User Stack diff --git a/pc/mouse.c b/pc/mouse.c index bcc1a8ec74c9470057ba0142bcc245c5984b0d08..522756fc2c95e865de94533ba3658151a8e77e8a 100644 --- a/pc/mouse.c +++ b/pc/mouse.c @@ -22,6 +22,10 @@ enum MousePS2= 2, }; static int mousetype; +static int intellimouse; +static int packetsize; +static int resolution; +static int accelerated; /* * setup a serial mouse @@ -43,6 +47,7 @@ serialmouse(int port, char *type, int setspeed) else ns16552special(port, setspeed, 0, 0, mouseputc); mousetype = Mouseserial; + packetsize = 3; } /* @@ -53,11 +58,22 @@ serialmouse(int port, char *type, int setspeed) * byte 2 - DY * * shift & right button is the same as middle button + * + * Intellimouse and AccuPoint with extra buttons deliver + * byte 3 - 00 or 01 or FF according to extra button state. + * extra buttons are mapped in this code to buttons 4 and 5. + * AccuPoint generates repeated events for these buttons; +* it and Intellimouse generate 'down' events only, so + * user-level code is required to generate button 'up' events + * if they are needed by the application. + * Also on laptops with AccuPoint AND external mouse, the + * controller may deliver 3 or 4 bytes according to the type + * of the external mouse; code must adapt. */ static void ps2mouseputc(int c, int shift) { - static short msg[3]; + static short msg[4]; static int nb; static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 3, 2, 3, 6, 7 }; int buttons, dx, dy; @@ -66,10 +82,14 @@ ps2mouseputc(int c, int shift) * check byte 0 for consistency */ if(nb==0 && (c&0xc8)!=0x08) - return; + if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){ + /* last byte of 4-byte packet */ + packetsize = 4; + return; + } msg[nb] = c; - if(++nb == 3){ + if(++nb == packetsize){ nb = 0; if(msg[0] & 0x10) msg[1] |= 0xFF00; @@ -77,6 +97,22 @@ ps2mouseputc(int c, int shift) msg[2] |= 0xFF00; buttons = b[(msg[0]&7) | (shift ? 8 : 0)]; + if(intellimouse && packetsize==4){ + if((msg[3]&0xc8) == 0x08){ + /* first byte of 3-byte packet */ + packetsize = 3; + msg[0] = msg[3]; + nb = 1; + /* fall through to emit previous packet */ + }else{ + /* the AccuPoint on the Toshiba 34[48]0CT encodes extra buttons as 4 and 5 */ + /* they repeat and don't release, however, so user-level timing code is required */ + if(msg[3] == 0xFF) + buttons |= 1<<3; + if(msg[3] == 0x01) + buttons |= 1<<4; + } + } dx = msg[1]; dy = -msg[2]; mousetrack(buttons, dx, dy); @@ -99,12 +135,9 @@ ps2mouse(void) i8042auxcmd(0xF4); mousetype = MousePS2; + packetsize = 3; } -static int intellimouse; -static int resolution; -static int accelerated; - static void setaccelerated(int x) { @@ -149,6 +182,7 @@ static void setintellimouse(void) { intellimouse = 1; + packetsize = 4; switch(mousetype){ case MousePS2: i8042auxcmd(0xF3); /* set sample */ @@ -164,6 +198,7 @@ setintellimouse(void) static void resetmouse(void) { + packetsize = 3; switch(mousetype){ case MousePS2: i8042auxcmd(0xF6); diff --git a/port/devmouse.c b/port/devmouse.c index 38051e43928dbc3904112c5bd539ea63c1f7b5fb..63bff0a5b40c58b232b34e0e88a443e2474d6205 100644 --- a/port/devmouse.c +++ b/port/devmouse.c @@ -199,6 +199,7 @@ mouseread(Chan *c, void *va, long n, vlong off) static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 }; ulong offset = off; Mousestate m; + int b; p = va; switch(c->qid.path){ @@ -245,9 +246,12 @@ mouseread(Chan *c, void *va, long n, vlong off) unlock(&cursor); } + b = buttonmap[m.buttons&7]; + /* put buttons 4 and 5 back in */ + b |= m.buttons & (3<<3); sprint(buf, "m%11d %11d %11d %11lud", m.xy.x, m.xy.y, - buttonmap[m.buttons&7], + b, m.msec); mouse.lastcounter = m.counter; if(n > 1+4*12) diff --git a/port/segment.c b/port/segment.c index 7f667a68d9fc1fca9a3d17cdbac95ec6242b3339..98149516e48d1ceb458895f8c82fc60efce7d10a 100644 --- a/port/segment.c +++ b/port/segment.c @@ -55,7 +55,6 @@ newseg(int type, ulong base, ulong size) if(swapfull()) error(Enoswap); - s = smalloc(sizeof(Segment)); s->ref = 1; s->type = type;