M pc/l.s => pc/l.s +18 -0
@@ 220,6 220,24 @@ TEXT outb(SB),$0
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
*/
TEXT inss(SB),$0
M port/fault.c => port/fault.c +2 -0
@@ 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)
M port/page.c => port/page.c +2 -2
@@ 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*
A ss/compile.c => ss/compile.c +192 -0
@@ 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);
+ }
+}
M ss/dat.h => ss/dat.h +13 -5
@@ 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;
M ss/faultsparc.c => ss/faultsparc.c +2 -0
@@ 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);
M ss/fns.h => ss/fns.h +16 -9
@@ 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);
M ss/main.c => ss/main.c +1 -4
@@ 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;
M ss/mem.h => ss/mem.h +2 -11
@@ 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
M ss/mmu.c => ss/mmu.c +488 -420
@@ 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 && j<nc; j++)
- if(pidtime[j] < t){
- i = j;
- t = pidtime[j];
- }
-
- sp = m->pidproc[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; j<NKLUDGE-1; j++)
- putsegm(UZERO+j*BY2SEGM, INVALIDPMEG);
- putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+NKLUDGE*i+(NKLUDGE-1));
- for(j=0; j<PG2SEGM; j++)
- putpmegnf((TSTKTOP-BY2SEGM)+j*BY2PG, INVALIDPTE);
- return i+1;
+static void
+freectx(Ctx *c, int flush)
+{
+ Pmeg *p;
+
+ putctx(c);
+
+ /* give back mappings */
+ while(p = c->pmeg){
+ 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; i<conf.vacsize; i+=conf.vaclinesize)
+ putsysspace(CACHETAGS+i, 0);
+
+ /*
+ * Turn cache on
+ */
+ putenab(getenab()&~ENABCACHE);
}
+/*
+ * set up initial mappings and a the LRU lists for contexts and pmegs
+ */
void
mmuinit(void)
{
- ulong ktop, l, i, j, c, pte;
+ int c, i, j;
+ ulong va, ktop, pme;
+ int fp; /* first free pmeg */
+ Pmeg *p;
+ Ctx *ctx;
+conf.ncontext = 1; /**/
compile();
+
/*
- * xinit sets conf.npage0 to maximum kernel address
+ * First map kernel text, data, bss, and xalloc regions.
+ * xinit sets conf.npage0 to end of these.
*/
- ktop = PADDR(conf.npage0);
+ ktop = PGROUND(conf.npage0);
+ i = 0;
+ for(c = 0; c < conf.ncontext; c++){
+ i = 0;
+ for(va = KZERO; va < ktop; va += BY2SEGM)
+ putcxsegm(c, va, i++);
+ }
+ fp = i;
+
/*
- * First map lots of memory as kernel addressable in all contexts
+ * Make sure cache is turned on for kernel
*/
- i = 0; /* used */
- for(c=0; c<conf.ncontext; c++)
- for(i=0; i < ktop/BY2SEGM; i++)
- putcxsegm(c, KZERO+i*BY2SEGM, i);
-
- kmapalloc.lowpmeg = i;
- if(ktop & (BY2SEGM-1))
- kmapalloc.lowpmeg++;
+ pme = PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM;
+ i = 0;
+ for(va = KZERO; va < ktop; va += BY2PG, i++)
+ putpme(va, pme+i, 1);
/*
- * Make sure cache is turned on for kernel
+ * invalidate rest of kernel's PMEG
*/
- pte = PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM;
- ktop /= BY2PG;
- for(i=0; i < ktop; i++)
- putpmeg(KZERO+i*BY2PG, pte+i);
+ va = ROUNDUP(ktop, BY2SEGM);
+ for(; ktop < va; ktop += BY2PG)
+ putpme(ktop, INVALIDPTE, 1);
/*
- * Create invalid pmeg; use highest segment
+ * allocate pmegs for kmap'ing
*/
- putsegm(INVALIDSEGM, INVALIDPMEG);
- for(i=0; i<PG2SEGM; i++)
- putpmeg(INVALIDSEGM+i*BY2PG, INVALIDPTE);
-
- for(c=0; c<conf.ncontext; c++){
+ for(c = 0; c < conf.ncontext; c++){
putcontext(c);
- putsegm(INVALIDSEGM, INVALIDPMEG);
- /*
- * Invalidate user addresses
- */
- for(l=UZERO; l<(KZERO&VAMASK); l+=BY2SEGM)
- putsegm(l, INVALIDPMEG);
-
- /*
- * Map ROM
- */
- putsegm(ROMSEGM, ROMPMEG);
- if(c == 0){
- pte = PTEVALID|PTEKERNEL|PTENOCACHE|
- PTEIO|PPN(EPROM);
- for(i=0; i<PG2ROM; i++)
- putpmeg(ROMSEGM+i*BY2PG, pte+i);
- for(; i<PG2SEGM; i++)
- putpmeg(ROMSEGM+i*BY2PG, INVALIDPTE);
- }
- /*
- * Segments for IO and kmap
- */
- for(j=0; j<NIOSEGM; j++){
- putsegm(IOSEGM0+j*BY2SEGM, IOPMEG0+j);
- if(c == 0)
- for(i=0; i<PG2SEGM; i++)
- putpmeg(IOSEGM0+j*BY2SEGM+i*BY2PG, INVALIDPTE);
- }
+ i = fp;
+ for(va = IOSEGM; va < IOSEGM+IOSEGSIZE; va += BY2SEGM)
+ putsegspace(va, i++);
}
- putcontext(0);
- NKLUDGE = ((TOPPMEG-kmapalloc.lowpmeg)/conf.ncontext);
-}
-
-void
-putmmu(ulong tlbvirt, ulong tlbphys, Page *pg)
-{
- short tp;
- Proc *p;
- ulong seg, l;
- int j, k;
+ fp = i;
- USED(pg);
- splhi();
- p = u->p;
- 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 && tlbvirt<TSTKTOP) /* stack; easy */
- goto put;
- /* UZERO is known to be zero here */
- if(tlbvirt < UZERO+p->nmmuseg*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; k<PG2SEGM; k++,l+=BY2PG)
- putpmegnf(l, INVALIDPTE);
+ m->pmeg = 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; i<conf.vacsize; i+=conf.vaclinesize)
- putsysspace(CACHETAGS+i, 0);
-
- /*
- * Turn cache on
- */
- putenab(getenab()|ENABCACHE); /**/
+ putpme(USERADDR, INVALIDPTE, 1);
}
+struct
+{
+ Lock;
+ KMap *free;
+ KMap arena[IOSEGSIZE/BY2PG];
+}kmapalloc;
+
void
kmapinit(void)
{
KMap *k;
- int i;
+ ulong va;
kmapalloc.free = 0;
k = kmapalloc.arena;
- for(i=0; i<(IOEND-IOSEGM0)/BY2PG; i++,k++){
- k->va = 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;
-}