M bitsy/dat.h => bitsy/dat.h +7 -16
@@ 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,
};
-
M bitsy/l.s => bitsy/l.s +35 -3
@@ 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 */
M bitsy/main.c => bitsy/main.c +77 -3
@@ 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
M bitsy/mmu.c => bitsy/mmu.c +30 -10
@@ 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);
}
M bitsy/trap.c => bitsy/trap.c +98 -4
@@ 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
@@ 108,6 121,31 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
}
/*
+ * 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)
*/
void
@@ 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);
+ }
}
/*
M ip/tcp.c => ip/tcp.c +6 -0
@@ 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;
M pc/main.c => pc/main.c +3 -2
@@ 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
M pc/mouse.c => pc/mouse.c +42 -7
@@ 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);
M port/devmouse.c => port/devmouse.c +5 -1
@@ 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)
M port/segment.c => port/segment.c +0 -1
@@ 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;