From 5611c0b722b27673e252b8892b717742dff8dcec Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 11 Sep 1992 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1992-09-11 --- pc/l.s | 18 + port/fault.c | 2 + port/page.c | 4 +- ss/compile.c | 192 ++++++++++ ss/dat.h | 18 +- ss/faultsparc.c | 2 + ss/fns.h | 25 +- ss/main.c | 5 +- ss/mem.h | 13 +- ss/mmu.c | 908 ++++++++++++++++++++++++++---------------------- 10 files changed, 736 insertions(+), 451 deletions(-) create mode 100644 ss/compile.c diff --git a/pc/l.s b/pc/l.s index b436177191232f1cfec092bcef420c57f5c5b809..49f4d4bdca9c7ec5b0fe451ac8d68a901590498d 100644 --- a/pc/l.s +++ b/pc/l.s @@ -219,6 +219,24 @@ TEXT outb(SB),$0 OUTB RET +/* + * input a short + */ +TEXT ins(SB), $0 + MOVL p+0(FP), DX + XORL AX, AX + OP16; INSL + RET + +/* + * output a short + */ +TEXT outs(SB), $0 + MOVL p+0(FP), DX + MOVL s+4(FP), AX + OP16; OUTSL + RET + /* * input a string of shorts from a port */ diff --git a/port/fault.c b/port/fault.c index 43734a9c4bd9e9b70ca80cba4424cac333f8032c..3e27fffc5838559c4f9b6558cce8ecae842ff7a9 100644 --- a/port/fault.c +++ b/port/fault.c @@ -184,6 +184,8 @@ pio(Segment *s, ulong addr, ulong soff, Page **p) kaddr = (char*)VA(k); if(loadrec == 0) { /* This is demand load */ +if(u && strcmp(u->p->text, "rc") == 0) +print("dl: %d %s %lux\n", u->p->pid, u->p->text, addr); c = s->image->c; while(waserror()) { if(strcmp(u->error, Eintr) == 0) diff --git a/port/page.c b/port/page.c index 4c78a027c22261183378592f0a85654e8b5cde7c..fe00591a512016847e8bf29d3b4c9d3aa3a2f58f 100644 --- a/port/page.c +++ b/port/page.c @@ -55,8 +55,8 @@ pageinit(void) hw = swapalloc.highwater*BY2PG; hr = swapalloc.headroom*BY2PG; - print("%lud free pages, %dK bytes, swap %dK, highwater %dK, headroom %dK\n", - palloc.user, pmem, vmem, hw/1024, hr/1024); +/* print("%lud free pages, %dK bytes, swap %dK, highwater %dK, headroom %dK\n", + palloc.user, pmem, vmem, hw/1024, hr/1024);/**/ } Page* diff --git a/ss/compile.c b/ss/compile.c new file mode 100644 index 0000000000000000000000000000000000000000..567569008a90b682da697de26b1c53b561f147c4 --- /dev/null +++ b/ss/compile.c @@ -0,0 +1,192 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#define NCODE 1024 +static ulong code[NCODE]; +static ulong *codep; + +ulong (*getcontext)(void); +void (*putcontext)(ulong); +void (*putenab)(ulong); +ulong (*getenab)(void); +ulong (*getsysspace)(ulong); +void (*putsysspace)(ulong, ulong); +uchar (*getsysspaceb)(ulong); +void (*putsysspaceb)(ulong, uchar); +ulong (*getsegspace)(ulong); +void (*putsegspace)(ulong, ulong); +ulong (*getpmegspace)(ulong); +void (*putpmegspace)(ulong, ulong); +ulong (*flushcx)(ulong); +ulong (*flushpm)(ulong); +ulong (*flushpg)(ulong); + +/* + * Compile MMU code for this machine, since the MMU can only + * be addressed from parameterless machine instructions. + * What's wrong with MMUs you can talk to from C? + */ + +/* op3 */ +#define LD 0 +#define ADD 0 +#define OR 2 +#define LDA 16 +#define LDUBA 17 +#define STA 20 +#define STBA 21 +#define JMPL 56 +/* op2 */ +#define SETHI 4 + +#define ret() {*codep++ = (2<<30)|(0<<25)|(JMPL<<19)|(15<<14)|(1<<13)|8;} +#define nop() {*codep++ = (0<<30)|(0<<25)|(SETHI<<22)|(0>>10);} + +static void +parameter(int param, int reg) +{ + param += 1; /* 0th parameter is 1st word on stack */ + param *= 4; + /* LD #param(R1), Rreg */ + *codep++ = (3<<30)|(reg<<25)|(LD<<19)|(1<<14)|(1<<13)|param; +} + +static void +constant(ulong c, int reg) +{ + *codep++ = (0<<30)|(reg<<25)|(SETHI<<22)|(c>>10); + if(c & 0x3FF) + *codep++ = (2<<30)|(reg<<25)|(OR<<19)|(reg<<14)|(1<<13)|(c&0x3FF); +} + +/* + * value to/from constant address + * void f(int c) { *(word*,asi)addr = c } for stores + * ulong f(void) { return *(word*,asi)addr } for loads + */ +static void* +compileconst(int op3, ulong addr, int asi) +{ + void *a; + + a = codep; + constant(addr, 8); /* MOVW $CONSTANT, R8 */ + ret(); /* JMPL 8(R15), R0 */ + /* in delay slot st or ld R7, (R8+R0, asi) */ + *codep++ = (3<<30)|(7<<25)|(op3<<19)|(8<<14)|(asi<<5); + return a; +} + +/* + * value to parameter address + * void f(ulong addr, int c) { *(word*,asi)addr = c } + */ +static void* +compilestaddr(int op3, int asi) +{ + void *a; + + a = codep; + parameter(1, 8); /* MOVW (4*1)(FP), R8 */ + ret(); /* JMPL 8(R15), R0 */ + /* in delay slot st R8, (R7+R0, asi) */ + *codep++ = (3<<30)|(8<<25)|(op3<<19)|(7<<14)|(asi<<5); + return a; +} + +/* + * value from parameter address + * ulong f(ulong addr) { return *(word*,asi)addr } + */ +static void* +compileldaddr(int op3, int asi) +{ + void *a; + + a = codep; + ret(); /* JMPL 8(R15), R0 */ + /* in delay slot ld (R7+R0, asi), R7 */ + *codep++ = (3<<30)|(7<<25)|(op3<<19)|(7<<14)|(asi<<5); + return a; +} + +/* + * 1 store of zero + * ulong f(ulong addr) { *addr=0; addr+=offset; return addr} + * offset can be anything + */ +static void* +compile1(ulong offset, int asi) +{ + void *a; + + a = codep; + /* ST R0, (R7+R0, asi) */ + *codep++ = (3<<30)|(0<<25)|(STA<<19)|(7<<14)|(asi<<5); + if(offset < (1<<12)){ + ret(); /* JMPL 8(R15), R0 */ + /* in delay slot ADD $offset, R7 */ + *codep++ = (2<<30)|(7<<25)|(ADD<<19)|(7<<14)|(1<<13)|offset; + }else{ + constant(offset, 8); + ret(); /* JMPL 8(R15), R0 */ + /* in delay slot ADD R8, R7 */ + *codep++ = (2<<30)|(7<<25)|(ADD<<19)|(7<<14)|(0<<13)|8; + } + return a; +} + +/* + * 16 stores of zero + * ulong f(ulong addr) { for(i=0;i<16;i++) {*addr=0; addr+=offset}; return addr} + * offset must be less than 1<<12 + */ +static void* +compile16(ulong offset, int asi) +{ + void *a; + int i; + + a = codep; + for(i=0; i<16; i++){ + /* ST R0, (R7+R0, asi) */ + *codep++ = (3<<30)|(0<<25)|(STA<<19)|(7<<14)|(asi<<5); + /* ADD $offset, R7 */ + *codep++ = (2<<30)|(7<<25)|(ADD<<19)|(7<<14)|(1<<13)|offset; + } + ret(); /* JMPL 8(R15), R0 */ + nop(); + return a; +} + +void +compile(void) +{ + codep = code; + + getcontext = compileconst(LDUBA, CONTEXT, 2); + putcontext = compileconst(STBA, CONTEXT, 2); + getenab = compileconst(LDUBA, ENAB, 2); + putenab = compileconst(STBA, ENAB, 2); + getsysspace = compileldaddr(LDA, 2); + putsysspace = compilestaddr(STA, 2); + getsysspaceb = compileldaddr(LDUBA, 2); + putsysspaceb = compilestaddr(STBA, 2); + getsegspace = compileldaddr(LDUBA, 3); + putsegspace = compilestaddr(STBA, 3); + getpmegspace = compileldaddr(LDA, 4); + putpmegspace = compilestaddr(STA, 4); + if(conf.ss2){ + flushpg = compile1(BY2PG, 6); + flushpm = compile16(conf.vaclinesize, 5); + flushcx = compile16(conf.vaclinesize, 7); + }else{ + flushpg = compile16(conf.vaclinesize, 0xD); + flushpm = compile16(conf.vaclinesize, 0xC); + flushcx = compile16(conf.vaclinesize, 0xE); + } +} diff --git a/ss/dat.h b/ss/dat.h index 11f0a1e3cf1b82d21684c6b15eb3e43bf24a9cdf..31be1fb4561feb212237ba60a282f40f8045bb86 100644 --- a/ss/dat.h +++ b/ss/dat.h @@ -1,4 +1,5 @@ typedef struct Conf Conf; +typedef struct Ctx Ctx; typedef struct FFrame FFrame; typedef struct FPsave FPsave; typedef struct KMap KMap; @@ -6,12 +7,15 @@ typedef struct Lance Lance; typedef struct Lancemem Lancemem; typedef struct Label Label; typedef struct Lock Lock; +typedef struct Pmeg Pmeg; typedef struct PMMU PMMU; typedef struct Mach Mach; typedef struct Ureg Ureg; +typedef struct List List; typedef struct User User; + #define MACHP(n) (n==0? &mach0 : *(Mach**)0) extern Mach mach0; @@ -87,13 +91,13 @@ struct Conf ulong frag; /* Ip fragment assemble queue size */ }; + /* * mmu goo in the Proc structure */ struct PMMU { - int pidonmach[MAXMACH]; - int nmmuseg; /* number of segments active in mmu */ + Ctx *ctxonmach[MAXMACH]; }; #include "../port/portdat.h" @@ -121,9 +125,13 @@ struct Mach Lock alarmlock; /* access to alarm list */ void *alarm; /* alarms bound to this clock */ int fpstate; /* state of fp registers on machine */ - char pidhere[NTLBPID]; /* is this tlbpid possibly in this mmu? */ - int lastpid; /* last pid allocated on this machine */ - Proc *pidproc[NTLBPID]; /* process that owns this pid on this mach */ + + Ctx *cctx; /* current context */ + List *clist; /* lru list of all contexts */ + Pmeg *pmeg; /* array of allocatable pmegs */ + int pfirst; /* index of first allocatable pmeg */ + List *plist; /* lru list of non-kernel Pmeg's */ + int needpmeg; /* a process needs a pmeg */ int tlbfault; int tlbpurge; diff --git a/ss/faultsparc.c b/ss/faultsparc.c index 06b8712b434ae54db7dc7d9e7a52c77090666dc2..1525f3adb4045824187c52a9933d6bb195c17877 100644 --- a/ss/faultsparc.c +++ b/ss/faultsparc.c @@ -33,6 +33,8 @@ faultsparc(Ureg *ur) if(ser&(SE_WRITE|SE_PROT)) read = 0; } +if(u && strcmp(u->p->text, "rc") == 0) +print("fault pc=%lux addr=%lux %d\n", ur->pc, addr, read);/**/ spllo(); if(u == 0){ dumpregs(ur); diff --git a/ss/fns.h b/ss/fns.h index 578d8b2468427f3da64bee77d437b0f0c38ed3b1..acbeedd63e0da79e327e3033de31d40db695b083 100644 --- a/ss/fns.h +++ b/ss/fns.h @@ -5,6 +5,7 @@ ulong call(void*, ...); void clearftt(ulong); #define clearmmucache() void clockinit(void); +void compile(void); void disabfp(void); void enabfp(void); void evenaddr(ulong); @@ -12,7 +13,6 @@ char* excname(ulong); void faultasync(Ureg*); void faultsparc(Ureg*); void flushcpucache(void); -#define flushpage(x) int fpcr(int); int fpquiet(void); void fpregrestore(char*); @@ -73,11 +73,18 @@ void trapinit(void); /* * compiled entry points */ -extern void (*putcontext)(ulong); -extern void (*putenab)(ulong); -extern ulong (*getenab)(void); -extern void (*putpmegspace)(ulong, ulong); -extern void (*putsysspace)(ulong, ulong); -extern ulong (*getsysspace)(ulong); -extern ulong (*flushcx)(ulong); -extern ulong (*flushpg)(ulong); +extern ulong (*getcontext)(void); +extern void (*putcontext)(ulong); +extern void (*putenab)(ulong); +extern ulong (*getenab)(void); +extern ulong (*getsysspace)(ulong); +extern void (*putsysspace)(ulong, ulong); +extern uchar (*getsysspaceb)(ulong); +extern void (*putsysspaceb)(ulong, uchar); +extern ulong (*getsegspace)(ulong); +extern void (*putsegspace)(ulong, ulong); +extern ulong (*getpmegspace)(ulong); +extern void (*putpmegspace)(ulong, ulong); +extern ulong (*flushcx)(ulong); +extern ulong (*flushpg)(ulong); +extern ulong (*flushpm)(ulong); diff --git a/ss/main.c b/ss/main.c index 4b4624d9d10f5a3f06cdbac2d45b28c6f8dadd97..0169291b3f156a1bbc927e46ea9a20dc1a7061db 100644 --- a/ss/main.c +++ b/ss/main.c @@ -19,7 +19,6 @@ char mempres[256]; char fbstr[32]; ulong fbslot; Label catch; -int NKLUDGE; typedef struct Sysparam Sysparam; struct Sysparam @@ -58,6 +57,7 @@ main(void) active.machs = 1; trapinit(); confinit(); +conf.monitor = 0; xinit(); mmuinit(); kmapinit(); @@ -140,7 +140,6 @@ init0(void) print("Sun Sparcstation %s\n", sparam->name); print("bank 0: %dM 1: %dM\n", bank[0], bank[1]); print("frame buffer id %lux slot %ld %s\n", conf.monitor, fbslot, fbstr); - print("NKLUDGE %d\n", NKLUDGE); if(conf.npage1 != conf.base1) print("kernel mem from second bank: reboot and fix!\n"); @@ -374,8 +373,6 @@ confinit(void) conf.vacsize = sparam->vacsize; conf.vaclinesize = sparam->vacline; conf.ncontext = sparam->ncontext; - if(conf.ncontext > 8) - conf.ncontext = 8; /* BUG to enlarge NKLUDGE */ conf.npmeg = sparam->npmeg; conf.ss2cachebug = sparam->cachebug; diff --git a/ss/mem.h b/ss/mem.h index 2ff3385115b3eac5d1022683b8d9b22a5d42fcc1..c75d58ba335bbf7226cb83001031942c01ec0a95 100644 --- a/ss/mem.h +++ b/ss/mem.h @@ -58,8 +58,6 @@ #define VAMASK 0x3FFFFFFF #define BY2SEGM (1<<18) #define PG2SEGM (1<<6) -#define NTLBPID (1+MAXCONTEXT) /* TLBPID 0 is unallocated */ -#define MAXCONTEXT 16 #define CONTEXT 0x30000000 /* in ASI 2 */ /* @@ -67,15 +65,8 @@ */ #define INVALIDSEGM 0xFFFC0000 /* highest seg of VA reserved as invalid */ #define INVALIDPMEG (conf.npmeg-1) -#define ROMPMEG (conf.npmeg-2) -#define ROMSEGM 0xFFE80000 -#define ROMEND 0xFFEC0000 -#define PG2ROM ((ROMEND-ROMSEGM)/BY2PG) -#define NIOSEGM ((MB/BY2SEGM) + 8) /* 1M for screen + overhead */ -#define IOSEGM0 (ROMSEGM-NIOSEGM*BY2SEGM) -#define IOPMEG0 (ROMPMEG-NIOSEGM) -#define IOEND ROMSEGM -#define TOPPMEG IOPMEG0 +#define IOSEGSIZE (MB + 2*MB) /* 1 meg for screen plus overhead */ +#define IOSEGM (INVALIDSEGM - IOSEGSIZE) /* * MMU entries diff --git a/ss/mmu.c b/ss/mmu.c index f00a2e60120d3ed95a179b42fd18de3b156034ae..585eb288b81463eef0cb9b0a40ef7d1c48a4a6c6 100644 --- a/ss/mmu.c +++ b/ss/mmu.c @@ -1,331 +1,569 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" - -void compile(void); -#define NCODE 1024 -static ulong code[NCODE]; -static ulong *codep = code; - -void (*putcontext)(ulong); -void (*putenab)(ulong); -ulong (*getenab)(void); -void (*putpmegspace)(ulong, ulong); -void (*putsysspace)(ulong, ulong); -ulong (*getsysspace)(ulong); -ulong (*flushcx)(ulong); -ulong (*flushpg)(ulong); +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" -struct +#define SERIALPORT 0xF0000000 /* MMU bypass */ + +static int +rawputc(int c) { - Lock; - int lowpmeg; - KMap *free; - KMap arena[(IOEND-IOSEGM0)/BY2PG]; -}kmapalloc; + if(c == '\n') + rawputc('\r'); + while((getsysspaceb(SERIALPORT+4) & (1<<2)) == 0) + delay(10); + putsysspaceb(SERIALPORT+6, c); + if(c == '\n') + delay(20); + return c; +} + +void +rawputs(char *s) +{ + while(*s) + rawputc(*s++); +} -int NKLUDGE; +void +rawprint(char *fmt, ...) +{ + char buf[PRINTSIZE]; + + doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)); + rawputs(buf); +} +static void +rawpanic(char *fmt, ...) +{ + char buf[PRINTSIZE]; + int s; + + s = splhi(); + doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)); + rawputs("rawpanic: "); + rawputs(buf); + systemreset(); + splx(s); +} + +/* + * WARNING: Even though all MMU data is in the mach structure or + * pointed to by it, this code will not work on a multi-processor + * without modification. + */ + /* - * On SPARC, tlbpid i == context i-1 so that 0 means unallocated + * doubly linked list for LRU algorithm */ +struct List +{ + List *prev; /* less recently used */ + List *next; /* more recently used */ +}; -int newpid(Proc*); -void purgepid(int); -void flushcontext(void); -void putpmegnf(ulong, ulong); +/* + * a Sparc context description + */ +struct Ctx +{ + List; /* MUST BE FIRST IN STRUCTURE!! */ -int pidtime[NTLBPID]; /* should be per m */ + Proc *proc; /* process that owns this context */ + Pmeg *pmeg; /* list of pmeg's used by this context */ + ushort index; /* which context this is */ +}; /* - * Called splhi, not in Running state + * a Sparc PMEG description */ -void -mapstack(Proc *p) +struct Pmeg { - short tp; - ulong tlbphys; + List; /* MUST BE FIRST IN STRUCTURE!! */ + + ulong lo; /* low water mark of used entries */ + ulong hi; /* high water mark of used entries */ + ushort index; /* which Pmeg this is */ + + ulong virt; /* virtual address this Pmeg represents */ + Ctx *ctx; /* context Pmeg belongs to */ + Pmeg *cnext; /* next pmeg used in same context */ +}; + +#define HOWMANY(x, y) (((x)+((y)-1))/(y)) +#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) + +static Pmeg* allocpmeg(ulong); +static void freepmeg(Pmeg*, int); +static Ctx* allocctx(Proc*); +static void freectx(Ctx*, int); +static void putpme(ulong, ulong, int); +static void mklast(List**, List*); +static void mkfirst(List**, List*); +static void remove(List**, List*); +static void add(List**, List*); +static void flushpage(ulong); +static void putctx(Ctx*); - if(p->newtlb) { - mmurelease(p); - p->newtlb = 0; +/* + * move to end of use list + */ +static void +mklast(List **list, List *entry) +{ + List *first; + + first = *list; + if(entry == first){ + *list = first->next; + return; } - tp = p->pidonmach[m->machno]; - if(tp == 0){ - tp = newpid(p); - p->pidonmach[m->machno] = tp; + /* remove from list */ + entry->prev->next = entry->next; + entry->next->prev = entry->prev; + + /* chain back in */ + entry->prev = first->prev; + entry->next = first; + first->prev->next = entry; + first->prev = entry; +} + +/* + * move to front of use list + */ +static void +mkfirst(List **list, List *entry) +{ + List *first; + + first = *list; + if(entry == first) + return; /* already at front */ + + /* unchain */ + entry->prev->next = entry->next; + entry->next->prev = entry->prev; + + /* chain back in */ + entry->prev = first->prev; + entry->next = first; + first->prev->next = entry; + first->prev = entry; + + *list = entry; +} + +/* + * remove from list + */ +static void +remove(List **list, List *entry) +{ + if(*list == entry) + *list = entry->next; + + entry->prev->next = entry->next; + entry->next->prev = entry->prev; +} + +/* + * add to list + */ +static void +add(List **list, List *entry) +{ + List *first; + + first = *list; + if(first == 0){ + entry->prev = entry; + entry->next = entry; + } else { + entry->prev = first->prev; + entry->next = first; + first->prev->next = entry; + first->prev = entry; } - if(p->upage->va != (USERADDR|(p->pid&0xFFFF)) && p->pid != 0) - panic("mapstack %s %d %lux 0x%lux 0x%lux", p->text, p->pid, p->upage, p->upage->pa, p->upage->va); - tlbphys = PPN(p->upage->pa)|PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; - putcontext(tp-1); - /* - * Don't need to flush cache because no other page has been - * mapped at USERADDR in this context; can call putpmegnf. - */ - putpmegnf(USERADDR, tlbphys); - u = (User*)USERADDR; + *list = entry; } -void -mmurelease(Proc *p) +/* + * add a pmeg to the current context for the given address + */ +static Pmeg* +allocpmeg(ulong virt) { - int tp; + Pmeg *p; + Ctx *c; + + virt = virt & ~(BY2SEGM-1); + for(;;){ + p = (Pmeg*)m->plist; + c = p->ctx; + if(c == 0) + break; + m->needpmeg = 1; + sched(); + splhi(); + } - tp = p->pidonmach[m->machno]; - if(tp) - pidtime[tp] = 0; - /* easiest is to forget what pid we had.... */ - memset(p->pidonmach, 0, sizeof p->pidonmach); + /* add to current context */ + p->ctx = m->cctx; + p->cnext = m->cctx->pmeg; + m->cctx->pmeg = p; + p->virt = virt; + p->lo = virt; + p->hi = virt; + putsegspace(p->virt, p->index); + mklast(&m->plist, p); + return p; +} + +static void +freepmeg(Pmeg *p, int flush) +{ + ulong x; + + /* invalidate any used PTE's, flush cache */ + for(x = p->lo; x <= p->hi; x += BY2PG) + putpme(x, INVALIDPTE, flush); + + /* invalidate segment pointer */ + putsegspace(p->virt, INVALIDPMEG); + + p->hi = 0; + p->lo = 0; + p->cnext = 0; + p->ctx = 0; + p->virt = 0; } /* - * Process must be non-interruptible + * get a context for a process. */ -int -newpid(Proc *p) +static Ctx* +allocctx(Proc *proc) { - int i, j, nc; - ulong t; - Proc *sp; - - t = ~0; - nc = conf.ncontext; - i = 1+((m->ticks)&(nc-1)); /* random guess */ - nc++; - for(j=1; t && jpidproc[i]; - if(sp) - sp->pidonmach[m->machno] = 0; - purgepid(i); /* also does putcontext */ - pidtime[i] = m->ticks; - m->pidproc[i] = p; - m->lastpid = i; + Ctx *c; + + c = (Ctx*)m->clist; + putctx(c); + if(c->proc) + freectx(c, 1); + c->proc = proc; + c->proc->ctxonmach[m->machno] = c; + mklast(&m->clist, c); + return c; +} - /* - * kludge: each context is allowed NKLUDGE pmegs. - * NKLUDGE-1 for text & data and 1 for stack. - * initialize by giving just a stack segment. - */ - i--; /* now i==context */ - p->nmmuseg = 0; - for(j=0; jpmeg){ + c->pmeg = p->cnext; + freepmeg(p, flush); + mkfirst(&m->plist, p); + } + + /* flush u-> */ + flushpage(USERADDR); + + /* detach from process */ + c->proc->ctxonmach[m->machno] = 0; + c->proc = 0; } -void -flushcontext(void) +static void +putctx(Ctx *c) +{ + putcontext(c->index); + m->cctx = c; +} + +static void +flushpage(ulong virt) { - ulong a; + ulong a, evirt; - a = 0; + a = virt; + evirt = virt+BY2PG; do - a = flushcx(a); - while(a < conf.vacsize); + a = flushpg(a); + while(a < evirt); +} + +/* + * stuff an entry into a pmeg + */ +static void +putpme(ulong virt, ulong phys, int flush) +{ + virt = virt & ~(BY2PG-1); + if(flush) + flushpage(virt); + putpmegspace(virt, phys); +} + +/* + * put a mapping into current context + */ +void +putmmu(ulong virt, ulong phys, Page *pg) +{ + ulong x, v; + Pmeg *p; + int s; + + USED(pg); + s = splhi(); + v = virt & ~(BY2SEGM-1); + x = getsegspace(v); + if(x == INVALIDPMEG) + p = allocpmeg(v); + else + p = &m->pmeg[x - m->pfirst]; + if(virt < p->lo) + p->lo = virt; + if(virt > p->hi) + p->hi = virt; + + putpme(virt, phys, 1); + splx(s); } +/* + * Initialize cache by clearing the valid bit + * (along with the others) in all cache entries + */ void -purgepid(int pid) +cacheinit(void) { - putcontext(pid-1); - flushcontext(); + int i; + + for(i=0; ip; - tp = p->pidonmach[m->machno]; - if(tp == 0){ - tp = newpid(p); - p->pidonmach[m->machno] = tp; + /* + * Invalidate all entries in all other pmegs + */ + for(j = fp; j < conf.npmeg; j++){ + putsegspace(INVALIDSEGM, j); + for(va = INVALIDSEGM; va < INVALIDSEGM+BY2SEGM; va += BY2PG) + putpme(va, INVALIDPTE, 1); } + /* - * kludge part 2: make sure we've got a valid segment + * invalidate everything outside the kernel in every context */ - if(TSTKTOP-BY2SEGM<=tlbvirt && tlbvirtnmmuseg*BY2SEGM) /* in range; easy */ - goto put; - seg = tlbvirt/BY2SEGM; - if(seg >= (UZERO/BY2SEGM)+(NKLUDGE-1)){ - pprint("putmmu %lux\n", tlbvirt); -print("putmmu %lux %d %s\n", tlbvirt, seg, p->text); - pexit("Suicide", 1); + for(c = 0; c < conf.ncontext; c++){ + putcontext(c); + for(va = UZERO; va < (KZERO & VAMASK); va += BY2SEGM) + putsegspace(va, INVALIDPMEG); + for(va = ktop; va < IOSEGM; va += BY2SEGM) + putsegspace(va, INVALIDPMEG); } + /* - * Prepare mmu up to this address + * allocate MMU management data for this CPU */ - tp = (tp-1)*NKLUDGE; /* now tp==base of pmeg area for this proc */ - l = UZERO+p->nmmuseg*BY2SEGM; - for(j=p->nmmuseg; j<=seg; j++){ - putsegm(l, kmapalloc.lowpmeg+tp+j); - for(k=0; kpmeg = p = xalloc((INVALIDPMEG - fp) * sizeof(Pmeg)); + m->pfirst = fp; + for(; fp < INVALIDPMEG; fp++, p++){ + p->index = fp; + add(&m->plist, p); } - p->nmmuseg = seg+1; - put: - putpmeg(tlbvirt, tlbphys); - spllo(); + m->cctx = ctx = xalloc(conf.ncontext * sizeof(Ctx)); + for(i = 0; i < conf.ncontext; i++, ctx++){ + ctx->index = i; + add(&m->clist, ctx); + } + + putctx(m->cctx); } +/* + * give up our mmu context + */ void -putpmeg(ulong virt, ulong phys) +mmurelease(Proc *p) { - ulong a, evirt; + Ctx *c; - virt &= VAMASK; - virt &= ~(BY2PG-1); - /* - * Flush old entries from cache - */ - a = virt; - evirt = virt+BY2PG; - do - a = flushpg(a); - while(a < evirt); - putpmegspace(virt, phys); + c = p->ctxonmach[m->machno]; + if(c == 0) + return; + + freectx(c, 1); + mkfirst(&m->clist, c); } +/* + * set up context for a process + */ void -putpmegnf(ulong virt, ulong phys) /* no need to flush */ +mapstack(Proc *p) { - virt &= VAMASK; - virt &= ~(BY2PG-1); - putpmegspace(virt, phys); + Ctx *c; + ulong tlbphys; + Pmeg *pm, *f, **l; + + if(p->upage->va != (USERADDR|(p->pid&0xFFFF)) && p->pid != 0) + panic("mapstack %s %d %lux 0x%lux 0x%lux", + p->text, p->pid, p->upage, p->upage->pa, p->upage->va); + + /* free a pmeg if a process needs one */ + if(m->needpmeg){ + pm = (Pmeg*)m->plist; + if(c = pm->ctx){ + /* remove from context list */ + l = &c->pmeg; + for(f = *l; f; f = f->cnext){ + if(f == pm){ + *l = f->cnext; + break; + } + l = &f->cnext; + } + + /* flush cache & remove mappings */ + putctx(c); + freepmeg(pm, 1); + } + m->needpmeg = 0; + } + + /* give up our context if it is unclean */ + if(p->newtlb){ + c = p->ctxonmach[m->machno]; + if(c) + freectx(c, 1); + p->newtlb = 0; + } + + /* set to this proc's context */ + c = p->ctxonmach[m->machno]; + if(c == 0) + allocctx(p); + else + putctx(c); + + /* make sure there's a mapping for u-> */ + tlbphys = PPN(p->upage->pa)|PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; + putpmegspace(USERADDR, tlbphys); + u = (User*)USERADDR; } void flushmmu(void) { + Ctx *c; + Pmeg *p; + splhi(); - u->p->newtlb = 1; - mapstack(u->p); + c = u->p->ctxonmach[m->machno]; + if(c == 0) + panic("flushmmu"); + while(p = c->pmeg){ + c->pmeg = p->cnext; + freepmeg(p, 1); + mkfirst(&m->plist, p); + } spllo(); } void -cacheinit(void) +invalidateu(void) { - int i; - - putcontext(0); - /* - * Initialize cache by clearing the valid bit - * (along with the others) in all cache entries - */ - for(i=0; iva = IOSEGM0+i*BY2PG; + for(va = IOSEGM; va < IOSEGM + IOSEGSIZE; va += BY2PG, k++){ + k->va = va; kunmap(k); } } @@ -346,11 +584,23 @@ kmappa(ulong pa, ulong flag) unlock(&kmapalloc); k->pa = pa; s = splhi(); - putpmeg(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|flag); + putpme(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|flag, 1); splx(s); return k; } + +void +kunmap(KMap *k) +{ + k->pa = 0; + lock(&kmapalloc); + k->next = kmapalloc.free; + kmapalloc.free = k; + putpme(k->va, INVALIDPTE, 1); + unlock(&kmapalloc); +} + ulong kmapregion(ulong pa, ulong n, ulong flag) { @@ -383,185 +633,3 @@ kmap(Page *pg) return kmappa(pg->pa, PTEMAINMEM|PTENOCACHE); } -KMap* -kmapperm(Page *pg) -{ - /* - * Here we know it's a permanent entry and can be cached. - */ - return kmappa(pg->pa, PTEMAINMEM); -} - -void -kunmap(KMap *k) -{ - k->pa = 0; - lock(&kmapalloc); - k->next = kmapalloc.free; - kmapalloc.free = k; - putpmeg(k->va, INVALIDPTE); - unlock(&kmapalloc); -} - -void -invalidateu(void) -{ - putpmeg(USERADDR, INVALIDPTE); -} - -/* - * Compile MMU code for this machine, since the MMU can only - * be addressed from parameterless machine instructions. - * What's wrong with MMUs you can talk to from C? - */ - -/* op3 */ -#define LD 0 -#define ADD 0 -#define OR 2 -#define LDA 16 -#define LDUBA 17 -#define STA 20 -#define STBA 21 -#define JMPL 56 -/* op2 */ -#define SETHI 4 - -void *compileconst(int, ulong, int); /* value to/from constant address */ -void *compileldaddr(int, int); /* value from parameter address */ -void *compilestaddr(int, int); /* value to parameter address */ -void *compile16(ulong, int); /* 16 stores of zero */ -void *compile1(ulong, int); /* 1 stores of zero */ - -#define ret() {*codep++ = (2<<30)|(0<<25)|(JMPL<<19)|(15<<14)|(1<<13)|8;} -#define nop() {*codep++ = (0<<30)|(0<<25)|(SETHI<<22)|(0>>10);} - -void -compile(void) -{ - putcontext = compileconst(STBA, CONTEXT, 2); - getenab = compileconst(LDUBA, ENAB, 2); - putenab = compileconst(STBA, ENAB, 2); - putpmegspace = compilestaddr(STA, 4); - putsysspace = compilestaddr(STA, 2); - getsysspace = compileldaddr(LDA, 2); - if(conf.ss2){ - flushpg = compile1(BY2PG, 6); - flushcx = compile16(conf.vaclinesize, 7); - }else{ - flushpg = compile16(conf.vaclinesize, 0xD); - flushcx = compile16(conf.vaclinesize, 0xE); - } -} - -void -parameter(int param, int reg) -{ - param += 1; /* 0th parameter is 1st word on stack */ - param *= 4; - /* LD #param(R1), Rreg */ - *codep++ = (3<<30)|(reg<<25)|(LD<<19)|(1<<14)|(1<<13)|param; -} - -void -constant(ulong c, int reg) -{ - *codep++ = (0<<30)|(reg<<25)|(SETHI<<22)|(c>>10); - if(c & 0x3FF) - *codep++ = (2<<30)|(reg<<25)|(OR<<19)|(reg<<14)|(1<<13)|(c&0x3FF); -} - -/* - * void f(int c) { *(word*,asi)addr = c } for stores - * ulong f(void) { return *(word*,asi)addr } for loads - */ -void* -compileconst(int op3, ulong addr, int asi) -{ - void *a; - - a = codep; - constant(addr, 8); /* MOVW $CONSTANT, R8 */ - ret(); /* JMPL 8(R15), R0 */ - /* in delay slot st or ld R7, (R8+R0, asi) */ - *codep++ = (3<<30)|(7<<25)|(op3<<19)|(8<<14)|(asi<<5); - return a; -} - -/* - * ulong f(ulong addr) { return *(word*,asi)addr } - */ -void* -compileldaddr(int op3, int asi) -{ - void *a; - - a = codep; - ret(); /* JMPL 8(R15), R0 */ - /* in delay slot ld (R7+R0, asi), R7 */ - *codep++ = (3<<30)|(7<<25)|(op3<<19)|(7<<14)|(asi<<5); - return a; -} - -/* - * void f(ulong addr, int c) { *(word*,asi)addr = c } - */ -void* -compilestaddr(int op3, int asi) -{ - void *a; - - a = codep; - parameter(1, 8); /* MOVW (4*1)(FP), R8 */ - ret(); /* JMPL 8(R15), R0 */ - /* in delay slot st R8, (R7+R0, asi) */ - *codep++ = (3<<30)|(8<<25)|(op3<<19)|(7<<14)|(asi<<5); - return a; -} - -/* - * ulong f(ulong addr) { *addr=0; addr+=offset; return addr} - * offset can be anything - */ -void* -compile1(ulong offset, int asi) -{ - void *a; - - a = codep; - /* ST R0, (R7+R0, asi) */ - *codep++ = (3<<30)|(0<<25)|(STA<<19)|(7<<14)|(asi<<5); - if(offset < (1<<12)){ - ret(); /* JMPL 8(R15), R0 */ - /* in delay slot ADD $offset, R7 */ - *codep++ = (2<<30)|(7<<25)|(ADD<<19)|(7<<14)|(1<<13)|offset; - }else{ - constant(offset, 8); - ret(); /* JMPL 8(R15), R0 */ - /* in delay slot ADD R8, R7 */ - *codep++ = (2<<30)|(7<<25)|(ADD<<19)|(7<<14)|(0<<13)|8; - } - return a; -} - -/* - * ulong f(ulong addr) { for(i=0;i<16;i++) {*addr=0; addr+=offset}; return addr} - * offset must be less than 1<<12 - */ -void* -compile16(ulong offset, int asi) -{ - void *a; - int i; - - a = codep; - for(i=0; i<16; i++){ - /* ST R0, (R7+R0, asi) */ - *codep++ = (3<<30)|(0<<25)|(STA<<19)|(7<<14)|(asi<<5); - /* ADD $offset, R7 */ - *codep++ = (2<<30)|(7<<25)|(ADD<<19)|(7<<14)|(1<<13)|offset; - } - ret(); /* JMPL 8(R15), R0 */ - nop(); - return a; -}