From 5d2460d6d8ad170beaceb3626ff3fb85684da42c Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Mon, 2 Oct 2000 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2000-10-02 --- bitsy/devuart.c | 74 +++++++++++- bitsy/fns.h | 5 +- bitsy/l.s | 98 ++++++++++------ bitsy/mmu.c | 4 +- bitsy/trap.c | 301 +++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 423 insertions(+), 59 deletions(-) diff --git a/bitsy/devuart.c b/bitsy/devuart.c index 4e44b6b3f00f8e38a715ae00208f1f662a8d15f9..5585bfeca3c19dad807d845124493ceea6ec87f3 100644 --- a/bitsy/devuart.c +++ b/bitsy/devuart.c @@ -133,6 +133,10 @@ static int uartndir; static char Ekinuse[] = "device in use by kernel"; static void uartsetbaud(Uart *p, int rate); +static void uartflow(void *v); +static void uartkick0(void *v); +static void uartkick(void *v); +static void uartrts(Uart *p, int on); /* * define a Uart. @@ -149,7 +153,6 @@ uartsetup(Uartregs *regs, ulong freq, char *name) uart[nuart] = p; strcpy(p->name, name); p->dev = nuart++; - p->port = port; p->freq = freq; p->regs = regs; @@ -232,8 +235,6 @@ uartreset(void) int i; Dirtab *dp; - uartsetup(uart3regs, ; - uartndir = 3*nuart; uartdir = xalloc(uartndir * sizeof(Dirtab)); dp = uartdir; @@ -522,6 +523,9 @@ Dev uartdevtab = { uartwstat, }; +/* + * set the buad rate + */ static void uartsetbaud(Uart *p, int rate) { @@ -537,6 +541,70 @@ uartsetbaud(Uart *p, int rate) p->baud = rate; } +/* + * turn on/off rts + */ +static void +uartrts(Uart *p, int on) +{ +} + +/* + * restart input if it's off + */ +static void +uartflow(void *v) +{ + Uart *p; + + p = v; + if(p->modem){ + uartrts(p, 1); + ilock(&p->rlock); + p->haveinput = 1; + iunlock(&p->rlock); + } +} + +/* + * restart output if not blocked and OK to send + */ +static void +uartkick0(void *v) +{ + int i; + Uart *p; + + p = v; + if(p->cts == 0 || p->blocked) + return; + + /* + * 128 here is an arbitrary limit to make sure + * we don't stay in this loop too long. If the + * chips output queue is longer than 128, too + * bad -- presotto + */ + for(i = 0; i < 128; i++){ +// if(!(uartrdreg(p, Lstat) & Outready)) +// break; +// if(p->op >= p->oe && stageoutput(p) == 0) +// break; +// outb(p->port + Data, *(p->op++)); + } +} + +static void +uartkick(void *v) +{ + Uart *p; + + p = v; + ilock(&p->tlock); + uartkick0(p); + iunlock(&p->tlock); +} + void serialputs(char *str, int n) { diff --git a/bitsy/fns.h b/bitsy/fns.h index 0d1b0267ad8959f87303f69d27cab9803f1b5de2..3de57fa6374519b1d97595aacd23a637dfa25619 100644 --- a/bitsy/fns.h +++ b/bitsy/fns.h @@ -15,17 +15,20 @@ ulong getfsr(void); void idle(void); #define idlehands() /* nothing to do in the runproc */ int iprint(char*, ...); -ulong* mapspecial(ulong, int); +void* mapspecial(ulong, int); void meminit(void); void mmuinit(void); void mmuenable(void); void mmudisable(void); +void noted(Ureg*, ulong); +int notify(Ureg*); #define procrestore(p) void procsave(Proc*); void procsetup(Proc*); void putdac(ulong); void putttb(ulong); void putpid(ulong); +void reset(void); void screeninit(void); int screenprint(char*, ...); /* debugging */ void (*screenputs)(char*, int); diff --git a/bitsy/l.s b/bitsy/l.s index c31fdc7c9917acfff905b6c786e4e764af685bde..71ef71f4531d012a780d5030f145c30bf2c0b80f 100644 --- a/bitsy/l.s +++ b/bitsy/l.s @@ -153,40 +153,49 @@ TEXT exceptionvectors(SB), $-4 WORD $_vfiq(SB) /* FIQ, switch to svc mode */ TEXT _vrst(SB), $-4 - BL reset + BL reset(SB) TEXT _vsvc(SB), $-4 /* SWI */ - SUB $12, R13 /* make room for pc, psr, & type */ - MOVW R14, 8(R13) /* ureg->pc = interupted PC */ + MOVW.DB.W R14, (R13) /* ureg->pc = interupted PC */ MOVW SPSR, R14 /* ureg->psr = SPSR */ - MOVW R14, 4(R13) /* ... */ + MOVW.DB.W R14, (R13) /* ... */ MOVW $PsrMsvc, R14 /* ureg->type = PsrMsvc */ - MOVW R14, (R13) /* ... */ + MOVW.DB.W R14, (R13) /* ... */ MOVM.DB.W.S [R0-R14], (R13) /* save user level registers, at end r13 points to ureg */ - B _vexcep /* call the exception handler */ + MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ + MOVW R13, R0 /* first arg is pointer to ureg */ + SUB $8, R13 /* space for argument+link */ + + BL syscall(SB) + + ADD $(8+4*15), R13 /* make r13 point to ureg->type */ + MOVW 8(R13), R14 /* restore link */ + MOVW 4(R13), R0 /* restore SPSR */ + MOVW R0, SPSR /* ... */ + MOVM.DB.S (R13), [R0-R14] /* restore registers */ + ADD $8, R13 /* pop past ureg->{type+psr} */ + RFE /* MOVM.IA.S.W (R13), [R15] */ TEXT _vund(SB), $-4 /* undefined */ - MOVM.IA [R0-R3], (R13) /* free some working space */ + MOVM.IA [R0-R4], (R13) /* free some working space */ MOVW $PsrMund, R0 B _vswitch TEXT _vabt(SB), $-4 /* prefetch abort */ - MOVM.IA [R0-R3], (R13) /* free some working space */ + MOVM.IA [R0-R4], (R13) /* free some working space */ MOVW $PsrMabt, R0 /* r0 = type */ B _vswitch TEXT _virq(SB), $-4 /* IRQ */ - MOVM.IA [R0-R3], (R13) /* free some working space */ + MOVM.IA [R0-R4], (R13) /* free some working space */ MOVW $PsrMirq, R0 /* r0 = type */ B _vswitch -TEXT _vfiq(SB), $-4 /* FIQ */ - RFE /* RIQ is special, ignore it for now */ - /* - * come here with type in R0 and R13 pointing above saved [r0-r3] + * come here with type in R0 and R13 pointing above saved [r0-r4] + * and type in r0. we'll switch to SVC mode and then call trap. */ -_vswitch: /* switch to svc, type in R0 */ +_vswitch: MOVW SPSR, R1 /* save SPSR for ureg */ MOVW R14, R2 /* save interrupted pc for ureg */ MOVW R13, R3 /* save pointer to where the original [R0-R3] are */ @@ -197,39 +206,56 @@ _vswitch: /* switch to svc, type in R0 */ ORR $(PsrDirq|PsrDfiq|PsrMsvc), R14 MOVW R14, CPSR - /* - * R13 and R14 is now R13_SVC and R14_SVC. The values of the previous mode's - * R13 and R14 are no longer accessible. That's why R3 was left to point to where - * the old [r0-r3] are stored. - */ + /* interupted code kernel or user? */ + AND.S $0xf, R1, R4 + B.EQ _userexcep + + /* here for trap from SVC mode */ MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */ - MOVM.IA (R3), [R0-R3] /* restore [R0-R3] from previous mode's stack */ - MOVM.DB.W.S [R0-R14], (R13) /* save user level registers, at end r13 points to ureg */ + MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */ + MOVM.DB.W [R0-R14], (R13) /* save kernel level registers, at end r13 points to ureg */ + MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ + MOVW R13, R0 /* first arg is pointer to ureg */ + SUB $8, R13 /* space for argument+link (for debugger) */ - /* - * if the original interrupt happened while executing SVC mode, - * the User R14 in the Ureg is wrong. We need to save the SVC one there. - */ - MOVW 0x40(R13), R1 - AND.S $0xf, R1 - MOVW.NE R14,0x38(R13) - B _vexcep + BL trap(SB) - /* - * call the exception routine, the ureg is at the bottom of the stack - */ -_vexcep: + ADD $(8+4*15), R13 /* make r13 point to ureg->type */ + MOVW 8(R13), R14 /* restore link */ + MOVW 4(R13), R0 /* restore SPSR */ + MOVW R0, SPSR /* ... */ + MOVM.DB (R13), [R0-R14] /* restore registers */ + ADD $8, R13 /* pop past ureg->{type+psr} */ + RFE /* MOVM.IA.S.W (R13), [R15] */ + + /* here for trap from USER mode */ +_userexcep: + MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */ + MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */ + MOVM.DB.W.S [R0-R14], (R13) /* save kernel level registers, at end r13 points to ureg */ MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ MOVW R13, R0 /* first arg is pointer to ureg */ - SUB $8, R13 /* space for argument+link */ + SUB $8, R13 /* space for argument+link (for debugger) */ + BL trap(SB) -_vrfe: ADD $(8+4*15), R13 /* make r13 point to ureg->type */ MOVW 8(R13), R14 /* restore link */ MOVW 4(R13), R0 /* restore SPSR */ MOVW R0, SPSR /* ... */ - MOVM.DB.W.S (R13), [R0-R14] /* restore registers */ + MOVM.DB.S (R13), [R0-R14] /* restore registers */ + ADD $8, R13 /* pop past ureg->{type+psr} */ + RFE /* MOVM.IA.S.W (R13), [R15] */ + +TEXT _vfiq(SB), $-4 /* FIQ */ + RFE /* FIQ is special, ignore it for now */ + +TEXT forkret(SB),$-4 + ADD $(4*15), R13 /* make r13 point to ureg->type */ + MOVW 8(R13), R14 /* restore link */ + MOVW 4(R13), R0 /* restore SPSR */ + MOVW R0, SPSR /* ... */ + MOVM.DB.S (R13), [R0-R14] /* restore registers */ ADD $8, R13 /* pop past ureg->{type+psr} */ RFE /* MOVM.IA.S.W (R13), [R15] */ diff --git a/bitsy/mmu.c b/bitsy/mmu.c index 677deb4e0bcf9c9c148ec2fb6ab355ea24b296a6..53970f0d9388f2fd9f127d8e2f3621adb667bddd 100644 --- a/bitsy/mmu.c +++ b/bitsy/mmu.c @@ -98,7 +98,7 @@ mmuinit(void) putttb((ulong)l1table); /* map the uart so that we can continue using iprint */ - uart3regs = (Uartregs*)mapspecial(UART3REGS, 64); + uart3regs = mapspecial(UART3REGS, 64); /* enable mmu, and make 0xFFFF0000 the virtual address of the exception vecs */ mmuenable(); @@ -109,7 +109,7 @@ mmuinit(void) /* * map special space uncached, assume that the space isn't already mapped */ -ulong* +void* mapspecial(ulong pa, int len) { ulong *t; diff --git a/bitsy/trap.c b/bitsy/trap.c index ce68f19aa574acbd52f909e4ad7fdda6cbda11ec..e314dd96765e99bacd2dbba6a57626d5858ac0a5 100644 --- a/bitsy/trap.c +++ b/bitsy/trap.c @@ -14,7 +14,7 @@ struct Intrregs ulong iclr; /* IRQ if bit == 0, FRIQ if 1 */ ulong iccr; /* control register */ ulong icfp; /* pending FIQs */ - ulong dummy1[3] + ulong dummy1[3]; ulong icpr; /* pending interrupts */ }; @@ -54,18 +54,17 @@ trapinit(void) /* map in interrupt registers */ intrregs = mapspecial(INTRREGS, sizeof(*intrregs)); - /* make all interrupts irq and disable all interrupts */ + /* make all interrupts IRQ (i.e. not FIQ) and disable all interrupts */ intrregs->iclr = 0; intrregs->icmr = 0; } /* - * enable an interrupt and attach a function to i + * enable an interrupt and attach a function to it */ void intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name) { - int vno; Vctl *v; v = xalloc(sizeof(Vctl)); @@ -78,21 +77,21 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name) lock(&vctllock); v->next = vctl[irq]; vctl[irq] = v; + intrregs->icmr |= 1<type){ - case PsrMfiq: /* fast interrupt */ - panic("fiq can't happen"); + default: + panic("unknown trap"); break; case PsrMabt: /* fault */ - case PsrMabt+1: /* fault */ panic("faults not implemented"); break; case PsrMund: /* undefined instruction */ @@ -100,18 +99,243 @@ trap(Ureg *ureg) break; case PsrMirq: /* device interrupt */ break; - case PsrMsvc: /* system call */ + } +} + +/* + * system calls + */ +#include "../port/systab.h" + +/* + * Syscall is called directly from assembler without going through trap(). + */ +void +syscall(Ureg* ureg) +{ + ulong sp; + long ret; + int i, scallnr; + + if((ureg->psr & PsrMask) != PsrMusr) + panic("syscall: cs 0x%4.4uX\n", ureg->psr); + + m->syscall++; + up->insyscall = 1; + up->pc = ureg->pc; + up->dbgreg = ureg; + + scallnr = ureg->r0; + up->scallnr = scallnr; + spllo(); + + sp = ureg->sp; + up->nerrlab = 0; + ret = -1; + if(!waserror()){ + if(scallnr >= nsyscall){ + pprint("bad sys call number %d pc %lux\n", + scallnr, ureg->pc); + postnote(up, 1, "sys: bad sys call", NDebug); + error(Ebadarg); + } + + if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD)) + validaddr(sp, sizeof(Sargs)+BY2WD, 0); + + up->s = *((Sargs*)(sp+BY2WD)); + up->psstate = sysctab[scallnr]; + + ret = systab[scallnr](up->s.args); + poperror(); + } + if(up->nerrlab){ + print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab); + for(i = 0; i < NERR; i++) + print("sp=%lux pc=%lux\n", + up->errlab[i].sp, up->errlab[i].pc); + panic("error stack"); + } + + up->insyscall = 0; + up->psstate = 0; + + /* + * Put return value in frame. On the x86 the syscall is + * just another trap and the return value from syscall is + * ignored. On other machines the return value is put into + * the results register by caller of syscall. + */ + ureg->r0 = ret; + + if(scallnr == NOTED) + noted(ureg, *(ulong*)(sp+BY2WD)); + + if(scallnr != RFORK && (up->procctl || up->nnote)){ + splhi(); + notify(ureg); + } +} + +/* + * Return user to state before notify() + */ +void +noted(Ureg* ureg, ulong arg0) +{ + Ureg *nureg; + ulong oureg, sp; + + qlock(&up->debug); + if(arg0!=NRSTR && !up->notified) { + qunlock(&up->debug); + pprint("call to noted() when not notified\n"); + pexit("Suicide", 0); + } + up->notified = 0; + + nureg = up->ureg; /* pointer to user returned Ureg struct */ + + /* sanity clause */ + oureg = (ulong)nureg; + if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){ + pprint("bad ureg in noted or call to noted when not notified\n"); + qunlock(&up->debug); + pexit("Suicide", 0); + } + + /* don't let user change system flags */ + nureg->psr = (ureg->psr & ~(PsrMask|PsrDfiq|PsrDirq)) | + (nureg->psr & (PsrMask|PsrDfiq|PsrDirq)); + + memmove(ureg, nureg, sizeof(Ureg)); + + switch(arg0){ + case NCONT: + case NRSTR: + if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->sp, BY2WD, 0)){ + qunlock(&up->debug); + pprint("suicide: trap in noted\n"); + pexit("Suicide", 0); + } + up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD)); + qunlock(&up->debug); break; + + case NSAVE: + if(!okaddr(nureg->pc, BY2WD, 0) + || !okaddr(nureg->sp, BY2WD, 0)){ + qunlock(&up->debug); + pprint("suicide: trap in noted\n"); + pexit("Suicide", 0); + } + qunlock(&up->debug); + sp = oureg-4*BY2WD-ERRLEN; + splhi(); + ureg->sp = sp; + ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */ + ((ulong*)sp)[0] = 0; /* arg 0 is pc */ + break; + + default: + pprint("unknown noted arg 0x%lux\n", arg0); + up->lastnote.flag = NDebug; + /* fall through */ + + case NDFLT: + if(up->lastnote.flag == NDebug){ + qunlock(&up->debug); + pprint("suicide: %s\n", up->lastnote.msg); + } else + qunlock(&up->debug); + pexit(up->lastnote.msg, up->lastnote.flag!=NDebug); } } +/* + * Call user, if necessary, with note. + * Pass user the Ureg struct and the note on his stack. + */ +int +notify(Ureg* ureg) +{ + int l; + ulong s, sp; + Note *n; + + if(up->procctl) + procctl(up); + if(up->nnote == 0) + return 0; + + s = spllo(); + qlock(&up->debug); + up->notepending = 0; + n = &up->note[0]; + if(strncmp(n->msg, "sys:", 4) == 0){ + l = strlen(n->msg); + if(l > ERRLEN-15) /* " pc=0x12345678\0" */ + l = ERRLEN-15; + sprint(n->msg+l, " pc=0x%.8lux", ureg->pc); + } + + if(n->flag!=NUser && (up->notified || up->notify==0)){ + if(n->flag == NDebug) + pprint("suicide: %s\n", n->msg); + qunlock(&up->debug); + pexit(n->msg, n->flag!=NDebug); + } + + if(up->notified) { + qunlock(&up->debug); + splhi(); + return 0; + } + + if(!up->notify){ + qunlock(&up->debug); + pexit(n->msg, n->flag!=NDebug); + } + sp = ureg->sp; + sp -= sizeof(Ureg); + + if(!okaddr((ulong)up->notify, 1, 0) + || !okaddr(sp-ERRLEN-4*BY2WD, sizeof(Ureg)+ERRLEN+4*BY2WD, 1)){ + pprint("suicide: bad address in notify\n"); + qunlock(&up->debug); + pexit("Suicide", 0); + } + + up->ureg = (void*)sp; + memmove((Ureg*)sp, ureg, sizeof(Ureg)); + *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */ + up->ureg = (void*)sp; + sp -= BY2WD+ERRLEN; + memmove((char*)sp, up->note[0].msg, ERRLEN); + sp -= 3*BY2WD; + *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */ + *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg; /* arg 1 is ureg* */ + *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */ + ureg->sp = sp; + ureg->pc = (ulong)up->notify; + up->notified = 1; + up->nnote--; + memmove(&up->lastnote, &up->note[0], sizeof(Note)); + memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); + + qunlock(&up->debug); + splx(s); + return 1; +} + /* Give enough context in the ureg to produce a kernel stack for * a sleeping process */ void setkernur(Ureg *ureg, Proc *p) { - USED(ureg, p); + ureg->pc = p->sched.pc; + ureg->sp = p->sched.sp+4; } /* @@ -120,7 +344,10 @@ setkernur(Ureg *ureg, Proc *p) ulong userpc(void) { - return 0; + Ureg *ureg; + + ureg = (Ureg*)up->dbgreg; + return ureg->pc; } /* This routine must save the values of registers the user is not permitted @@ -135,8 +362,7 @@ setregisters(Ureg* ureg, char* pureg, char* uva, int n) /* * this is the body for all kproc's */ -static -void +static void linkproc(void) { spllo(); @@ -166,7 +392,20 @@ kprocchild(Proc *p, void (*func)(void*), void *arg) void forkchild(Proc *p, Ureg *ureg) { - USED(p, ureg); + Ureg *cureg; + + p->sched.sp = (ulong)p->kstack+KSTACK-sizeof(Ureg); + p->sched.pc = (ulong)forkret; + + cureg = (Ureg*)(p->sched.sp+2*BY2WD); + memmove(cureg, ureg, sizeof(Ureg)); + + /* syscall returns 0 for child */ + cureg->r0 = 0; + + /* Things from bottom of syscall which were never executed */ + p->psstate = 0; + p->insyscall = 0; } /* @@ -195,10 +434,38 @@ dumpstack(void) { } - +/* + * pc output by ps + */ ulong dbgpc(Proc *p) { - USED(p); - return 0; + Ureg *ureg; + + ureg = p->dbgreg; + if(ureg == 0) + return 0; + + return ureg->pc; +} + +/* + * called in sysfile.c + */ +void +evenaddr(ulong addr) +{ + if(addr & 3){ + postnote(up, 1, "sys: odd address", NDebug); + error(Ebadarg); + } +} + + +/* + * here on a hardware reset + */ +void +reset(void) +{ }