Annotation of lucent/sys/src/9/pc/mmu.c, revision 1.1.1.1

1.1       root        1: #include       "u.h"
                      2: #include       "../port/lib.h"
                      3: #include       "mem.h"
                      4: #include       "dat.h"
                      5: #include       "fns.h"
                      6: #include       "io.h"
                      7: 
                      8: /*
                      9:  *  segment descriptor initializers
                     10:  */
                     11: #define        DATASEGM(p) (Segdesc){  0xFFFF,\
                     12:                                SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW }
                     13: #define        EXECSEGM(p) (Segdesc){  0xFFFF,\
                     14:                                SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR }
                     15: #define CALLGATE(s,o,p) (Segdesc){     ((o)&0xFFFF)|((s)<<16),\
                     16:                                        (o)&0xFFFF0000|SEGP|SEGPL(p)|SEGCG }
                     17: #define        D16SEGM(p) (Segdesc){   0xFFFF,\
                     18:                                (0x0<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW }
                     19: #define        E16SEGM(p) (Segdesc){   0xFFFF,\
                     20:                                (0x0<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR }
                     21: #define        TSSSEGM(b,p) (Segdesc){ ((b)<<16)|sizeof(Tss),\
                     22:                                ((b)&0xFF000000)|(((b)>>16)&0xFF)|SEGTSS|SEGPL(p)|SEGP }
                     23: 
                     24: static Page    ktoppg;         /* prototype top level page table
                     25:                                 * containing kernel mappings  */
                     26: static ulong   *kpt;           /* 2nd level page tables for kernel mem */
                     27: static ulong   *upt;           /* 2nd level page table for struct User */
                     28: 
                     29: #define ROUNDUP(s,v)   (((s)+(v-1))&~(v-1))
                     30: /*
                     31:  *  offset of virtual address into
                     32:  *  top level page table
                     33:  */
                     34: #define TOPOFF(v)      (((ulong)(v))>>(2*PGSHIFT-2))
                     35: 
                     36: /*
                     37:  *  offset of virtual address into
                     38:  *  bottom level page table
                     39:  */
                     40: #define BTMOFF(v)      ((((ulong)(v))>>(PGSHIFT))&(WD2PG-1))
                     41: 
                     42: #define MAXUMEG 64     /* maximum memory per user process in megabytes */
                     43: #define ONEMEG (1024*1024)
                     44: 
                     45: enum {
                     46:        Nisa=   256,
                     47: };
                     48: struct
                     49: {
                     50:        Lock;
                     51:        ulong s[Nisa];
                     52:        ulong e[Nisa];
                     53: } isaalloc;
                     54: 
                     55: /*
                     56:  *  setup mmu for a cpu assuming we've already created the kernel
                     57:  *  page tables.
                     58:  */
                     59: void
                     60: setupmmu(void)
                     61: {
                     62:        ulong x;
                     63: 
                     64:        /*
                     65:         *  set up the global descriptor table. we make the tss entry here
                     66:         *  since it requires arithmetic on an address and hence cannot
                     67:         *  be a compile or link time constant.
                     68:         */
                     69:        x = (ulong)&m->tss;
                     70:        m->gdt[NULLSEG] = (Segdesc){0, 0};
                     71:        m->gdt[TSSSEG] = TSSSEGM(x, 0);
                     72:        m->gdt[KDSEG] = DATASEGM(0);            /* kernel data/stack */
                     73:        m->gdt[KESEG] = EXECSEGM(0);            /* kernel code */
                     74:        m->gdt[UDSEG] = DATASEGM(3);            /* user data/stack */
                     75:        m->gdt[UESEG] = EXECSEGM(3);            /* user code */
                     76:        putgdt(m->gdt, sizeof(m->gdt));
                     77: 
                     78:        /*
                     79:         *  point to kernel page table
                     80:         */
                     81:        putcr3(ktoppg.pa);
                     82: 
                     83:        /*
                     84:         *  set up the task segment
                     85:         */
                     86:        memset(&m->tss, 0, sizeof(m->tss));
                     87:        m->tss.sp0 = USERADDR+BY2PG;
                     88:        m->tss.ss0 = KDSEL;
                     89:        m->tss.cr3 = ktoppg.pa;
                     90:        puttr(TSSSEL);
                     91: }
                     92: 
                     93: /*
                     94:  *  Create a prototype page map that maps all of memory into
                     95:  *  kernel (KZERO) space.  This is the default map.  It is used
                     96:  *  whenever the processor not running a process or whenever running
                     97:  *  a process which does not yet have its own map.
                     98:  */
                     99: void
                    100: mmuinit(void)
                    101: {
                    102:        int i, nkpt, npage, nbytes;
                    103:        ulong x;
                    104:        ulong y;
                    105:        ulong *top;
                    106: 
                    107:        /*
                    108:         *  set up system page tables.
                    109:         *  map all of physical memory to start at KZERO.
                    110:         *  leave a map entry for a user area.
                    111:         */
                    112: 
                    113:        /*  allocate top level table */
                    114:        top = xspanalloc(BY2PG, BY2PG, 0);
                    115:        ktoppg.va = (ulong)top;
                    116:        ktoppg.pa = ktoppg.va & ~KZERO;
                    117: 
                    118:        /*  map all memory to KZERO */
                    119:        npage = 128*MB/BY2PG;
                    120:        nbytes = PGROUND(npage*BY2WD);          /* words of page map */
                    121:        nkpt = nbytes/BY2PG;                    /* pages of page map */
                    122:        kpt = xspanalloc(nbytes, BY2PG, 0);
                    123:        for(i = 0; i < npage; i++)
                    124:                kpt[i] = (0+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE;
                    125:        x = TOPOFF(KZERO);
                    126:        y = ((ulong)kpt)&~KZERO;
                    127:        for(i = 0; i < nkpt; i++)
                    128:                top[x+i] = (y+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE;
                    129: 
                    130:        /*  page table for u-> */
                    131:        upt = xspanalloc(BY2PG, BY2PG, 0);
                    132:        x = TOPOFF(USERADDR);
                    133:        y = ((ulong)upt)&~KZERO;
                    134:        top[x] = y | PTEVALID | PTEKERNEL | PTEWRITE;
                    135: 
                    136:        setupmmu();
                    137: }
                    138: 
                    139: /*
                    140:  *  Mark the mmu and tlb as inconsistent and call mapstack to fix it up.
                    141:  */
                    142: void
                    143: flushmmu(void)
                    144: {
                    145:        int s;
                    146: 
                    147:        s = splhi();
                    148:        if(u){
                    149:                u->p->newtlb = 1;
                    150:                mapstack(u->p);
                    151:        } else
                    152:                putcr3(ktoppg.pa);
                    153:        splx(s);
                    154: }
                    155: 
                    156: /*
                    157:  *  Switch to a process's memory map.  If the process doesn't
                    158:  *  have a map yet, just use the prototype one that contains
                    159:  *  mappings for only the kernel and the User struct.
                    160:  */
                    161: void
                    162: mapstack(Proc *p)
                    163: {
                    164:        Page *pg;
                    165:        ulong *top;
                    166: 
                    167:        if(p->upage->va != (USERADDR|(p->pid&0xFFFF)) && p->pid != 0)
                    168:                panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va);
                    169: 
                    170:        if(p->newtlb){
                    171:                /*
                    172:                 *  newtlb set means that they are inconsistent
                    173:                 *  with the segment.c data structures.
                    174:                 *
                    175:                 *  bin the current second level page tables and
                    176:                 *  the pointers to them in the top level page.
                    177:                 *  pg->daddr is used by putmmu to save the offset into
                    178:                 *  the top level page.
                    179:                 */
                    180:                if(p->mmutop && p->mmuused){
                    181:                        top = (ulong*)p->mmutop->va;
                    182:                        for(pg = p->mmuused; pg->next; pg = pg->next)
                    183:                                ilputl(&top[pg->daddr], 0);
                    184:                        ilputl(&top[pg->daddr], 0);
                    185:                        pg->next = p->mmufree;
                    186:                        p->mmufree = p->mmuused;
                    187:                        p->mmuused = 0;
                    188:                }
                    189:                p->newtlb = 0;
                    190:        }
                    191: 
                    192:        /* map in u area */
                    193:        upt[0] = PPN(p->upage->pa) | PTEVALID | PTEKERNEL | PTEWRITE;
                    194: 
                    195:        /* tell processor about new page table (flushes cached entries) */
                    196:        if(p->mmutop)
                    197:                pg = p->mmutop;
                    198:        else
                    199:                pg = &ktoppg;
                    200:        putcr3(pg->pa);
                    201: 
                    202:        u = (User*)USERADDR;
                    203: }
                    204: 
                    205: /*
                    206:  *  give all page table pages back to the free pool.  This is called in sched()
                    207:  *  with palloc locked.
                    208:  */
                    209: void
                    210: mmurelease(Proc *p)
                    211: {
                    212:        Page *pg;
                    213:        Page *next;
                    214: 
                    215:        /* point 386 to protoype page map */
                    216:        putcr3(ktoppg.pa);
                    217: 
                    218:        /* give away page table pages */
                    219:        for(pg = p->mmufree; pg; pg = next){
                    220:                next = pg->next;
                    221:                simpleputpage(pg);
                    222:        }
                    223:        p->mmufree = 0;
                    224:        for(pg = p->mmuused; pg; pg = next){
                    225:                next = pg->next;
                    226:                simpleputpage(pg);
                    227:        }
                    228:        p->mmuused = 0;
                    229:        if(p->mmutop)
                    230:                simpleputpage(p->mmutop);
                    231:        p->mmutop = 0;
                    232: }
                    233: 
                    234: /*
                    235:  *  Add an entry into the mmu.
                    236:  */
                    237: void
                    238: putmmu(ulong va, ulong pa, Page *pg)
                    239: {
                    240:        int topoff;
                    241:        ulong *top;
                    242:        ulong *pt;
                    243:        Proc *p;
                    244:        int s;
                    245: 
                    246:        if(u==0)
                    247:                panic("putmmu");
                    248:        p = u->p;
                    249: 
                    250:        /*
                    251:         *  create a top level page if we don't already have one.
                    252:         *  copy the kernel top level page into it for kernel mappings.
                    253:         */
                    254:        if(p->mmutop == 0){
                    255:                pg = newpage(0, 0, 0);
                    256:                pg->va = VA(kmap(pg));
                    257:                memmove((void*)pg->va, (void*)ktoppg.va, BY2PG);
                    258:                p->mmutop = pg;
                    259:        }
                    260:        top = (ulong*)p->mmutop->va;
                    261:        topoff = TOPOFF(va);
                    262: 
                    263:        /*
                    264:         *  if bottom level page table missing, allocate one 
                    265:         *  and point the top level page at it.
                    266:         */
                    267:        s = splhi();
                    268:        if(PPN(top[topoff]) == 0){
                    269:                if(p->mmufree == 0){
                    270:                        spllo();
                    271:                        pg = newpage(1, 0, 0);
                    272:                        pg->va = VA(kmap(pg));
                    273:                        splhi();
                    274:                } else {
                    275:                        pg = p->mmufree;
                    276:                        p->mmufree = pg->next;
                    277:                        memset((void*)pg->va, 0, BY2PG);
                    278:                }
                    279:                ilputl(&top[topoff], PPN(pg->pa) | PTEVALID | PTEUSER | PTEWRITE);
                    280:                pg->daddr = topoff;
                    281:                pg->next = p->mmuused;
                    282:                p->mmuused = pg;
                    283:        }
                    284: 
                    285:        /*
                    286:         *  put in new mmu entry
                    287:         */
                    288:        pt = (ulong*)(PPN(top[topoff])|KZERO);
                    289:        ilputl(&pt[BTMOFF(va)], pa | PTEUSER);
                    290: 
                    291:        /* flush cached mmu entries */
                    292:        putcr3(p->mmutop->pa);
                    293:        splx(s);
                    294: }
                    295: 
                    296: void
                    297: invalidateu(void)
                    298: {
                    299:        /* unmap u area */
                    300:        upt[0] = 0;
                    301: 
                    302:        /* flush cached mmu entries */
                    303:        putcr3(ktoppg.pa);
                    304: }
                    305: 
                    306: /*
                    307:  *  used to map a page into 16 meg - BY2PG for confinit(). tpt is the temporary
                    308:  *  page table set up by l.s.
                    309:  */
                    310: long*
                    311: mapaddr(ulong addr)
                    312: {
                    313:        ulong base;
                    314:        ulong off;
                    315:        static ulong *pte, top;
                    316:        extern ulong tpt[];
                    317: 
                    318:        if(pte == 0){
                    319:                top = (((ulong)tpt)+(BY2PG-1))&~(BY2PG-1);
                    320:                pte = (ulong*)top;
                    321:                top &= ~KZERO;
                    322:                top += BY2PG;
                    323:                pte += (4*1024*1024-BY2PG)>>PGSHIFT;
                    324:        }
                    325: 
                    326:        base = off = addr;
                    327:        base &= ~(KZERO|(BY2PG-1));
                    328:        off &= BY2PG-1;
                    329: 
                    330:        *pte = base|PTEVALID|PTEKERNEL|PTEWRITE; /**/
                    331:        putcr3((ulong)top);
                    332: 
                    333:        return (long*)(KZERO | 4*1024*1024-BY2PG | off);
                    334: }
                    335: 
                    336: /*
                    337:  *  make isa address space available
                    338:  */
                    339: void
                    340: putisa(ulong addr, int len)
                    341: {
                    342:        ulong e;
                    343:        int i, hole;
                    344: 
                    345:        addr &= ~KZERO;
                    346: 
                    347:        e = addr + len;
                    348:        lock(&isaalloc);
                    349:        hole = -1;
                    350:        for(i = 0; i < Nisa; i++){
                    351:                if(isaalloc.s[i] == e){
                    352:                        isaalloc.s[i] = addr;
                    353:                        break;
                    354:                }
                    355:                if(isaalloc.e[i] == addr){
                    356:                        isaalloc.e[i] = e;
                    357:                        break;
                    358:                }
                    359:                if(isaalloc.s[i] == 0)
                    360:                        hole = i;
                    361:        }
                    362:        if(i >= Nisa && hole >= 0){
                    363:                isaalloc.s[hole] = addr;
                    364:                isaalloc.e[hole] = e;
                    365:        }
                    366:        unlock(&isaalloc);
                    367: }
                    368: 
                    369: /*
                    370:  *  allocate some address space (already mapped into the kernel)
                    371:  *  for ISA bus memory.
                    372:  */
                    373: ulong
                    374: getisa(ulong addr, int len, int align)
                    375: {
                    376:        int i;
                    377:        long os, s, e;
                    378: 
                    379:        lock(&isaalloc);
                    380:        os = s = e = 0;
                    381:        for(i = 0; i < Nisa; i++){
                    382:                s = os = isaalloc.s[i];
                    383:                if(s == 0)
                    384:                        continue;
                    385:                e = isaalloc.e[i];
                    386:                if(addr && addr >= s && addr < e)
                    387:                        break;
                    388:                if(align > 0)
                    389:                        s = ((s + align - 1)/align)*align;
                    390:                if(e - s >= len)
                    391:                        break;
                    392:        }
                    393:        if(i >= Nisa){
                    394:                unlock(&isaalloc);
                    395:                return 0;
                    396:        }
                    397: 
                    398:        /* remove */
                    399:        isaalloc.s[i] = 0;
                    400:        unlock(&isaalloc);
                    401: 
                    402:        /* give back edges */
                    403:        if(s != os)
                    404:                putisa(os, s - os);
                    405:        os = s + len;
                    406:        if(os != e)
                    407:                putisa(os, e - os);
                    408: 
                    409:        return KZERO|s;
                    410: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.