M bitsy/devuart.c => bitsy/devuart.c +71 -3
@@ 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)
{
M bitsy/fns.h => bitsy/fns.h +4 -1
@@ 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);
M bitsy/l.s => bitsy/l.s +62 -36
@@ 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] */
M bitsy/mmu.c => bitsy/mmu.c +2 -2
@@ 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;
M bitsy/trap.c => bitsy/trap.c +284 -17
@@ 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<<irq;
unlock(&vctllock);
}
/*
- * here on all exceptions with registers saved
+ * here on all exceptions other than syscall (SWI)
*/
void
trap(Ureg *ureg)
{
switch(ureg->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)
+{
}