| plan 9 kernel history: overview | file list | diff list |
2001/0727/alphapc/mmu.c (diff list | history)
| 2001/0727/sys/src/9/alphapc/mmu.c:1,272 – 2001/0728/sys/src/9/alphapc/mmu.c:1,259 (short | long | prev | next) | ||
| 1999/0415 | #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "/sys/src/boot/alphapc/conf.h" static uvlong origlvl1; /* physical address */ static uvlong klvl2; /* physical, as created by boot loader */ static uchar *nextio; /* next virtual address to be allocated by kmapv */ extern Bootconf *bootconf; #define LVL2OFF(v) ((((long)(v))>>(2*PGSHIFT-3))&(PTE2PG-1)) #define LVL3OFF(v) ((((long)(v))>>(PGSHIFT))&(PTE2PG-1)) static void setptb(ulong pa) { m->ptbr = (uvlong)pa>>PGSHIFT; swpctx(m); } void mmuinit(void) { uvlong *plvl2; /* set PCB to new one in mach structure before stomping on old one */ m->usp = 0; m->fen = 1; m->ptbr = bootconf->pcb->ptbr; origlvl1 = (m->ptbr << PGSHIFT); setpcb(m); plvl2 = (uvlong*) (KZERO|origlvl1|(BY2PG-8)); klvl2 = (*plvl2 >> 32)<<PGSHIFT; nextio = (uchar*) (KZERO|bootconf->maxphys); } | |
| 2001/0728 | static void mmuptefree(Proc* proc) | |
| 1999/0415 | { | |
| 2001/0728 | Page **last, *page; | |
| 1999/0415 |
| |
| 2001/0728 | if(proc->mmutop && proc->mmuused){ lvl2 = (uvlong*)proc->mmulvl2->va; last = &proc->mmuused; for(page = *last; page; page = page->next){ lvl2[page->daddr] = 0; last = &page->next; | |
| 1999/0415 | } | |
| 2001/0728 | *last = proc->mmufree; proc->mmufree = proc->mmuused; proc->mmuused = 0; | |
| 1999/0415 | } | |
| 2001/0728 | } | |
| 1999/0415 | ||
| 2001/0728 | void mmuswitch(Proc *proc) { if(proc->newtlb){ mmuptefree(proc); proc->newtlb = 0; } | |
| 1999/0415 | /* tell processor about new page table and flush cached entries */ | |
| 2001/0728 | if(proc->mmutop == 0) | |
| 1999/0415 | setptb(origlvl1); else | |
| 2001/0728 | setptb(proc->mmutop->pa); | |
| 1999/0415 | tlbflush(-1, 0); icflush(); } /* * give all page table pages back to the free pool. This is called in sched() * with palloc locked. */ void | |
| 2001/0728 | mmurelease(Proc *proc) | |
| 1999/0415 | { | |
| 2001/0728 | Page *page, *next; | |
| 1999/0415 |
| |
| 2001/0728 | mmuptefree(proc); proc->mmuused = 0; if(proc->mmutop) { proc->mmutop->next = proc->mmufree; proc->mmufree = proc->mmutop; proc->mmutop = 0; | |
| 1999/0415 | } | |
| 2001/0728 | if(proc->mmulvl2) { proc->mmulvl2->next = proc->mmufree; proc->mmufree = proc->mmulvl2; proc->mmulvl2 = 0; | |
| 1999/0415 | } | |
| 2001/0728 | for(page = proc->mmufree; page; page = next){ next = page->next; if(--page->ref) panic("mmurelease: page->ref %d\n", page->ref); pagechainhead(page); | |
| 1999/0415 | } | |
| 2001/0728 | if(proc->mmufree && palloc.r.p) | |
| 1999/0415 | wakeup(&palloc.r); | |
| 2001/0728 | proc->mmufree = 0; | |
| 1999/0415 | } void mmunewtop(void) { Page *top, *lvl2; uvlong *ppte; top = newpage(1, 0, 0); top->va = VA(kmap(top)); lvl2 = newpage(1, 0, 0); lvl2->va = VA(kmap(lvl2)); ppte = (uvlong *)top->va; ppte[0] = PTEPFN(lvl2->pa) | PTEKVALID; ppte[PTE2PG-2] = PTEPFN(top->pa) | PTEKVALID; ppte[PTE2PG-1] = PTEPFN(klvl2) | PTEKVALID; up->mmutop = top; up->mmulvl2 = lvl2; setptb(top->pa); tlbflush(-1, 0); icflush(); } void putmmu(ulong va, ulong pa, Page *pg) { int lvl2off; uvlong *lvl2, *pt; int s; if(up->mmutop == 0) mmunewtop(); lvl2 = (uvlong*)up->mmulvl2->va; lvl2off = LVL2OFF(va); /* * if bottom level page table missing, allocate one * and point the top level page at it. */ s = splhi(); if(lvl2[lvl2off] == 0){ if(up->mmufree == 0){ spllo(); pg = newpage(1, 0, 0); pg->va = VA(kmap(pg)); splhi(); } else { pg = up->mmufree; up->mmufree = pg->next; memset((void*)pg->va, 0, BY2PG); } lvl2[lvl2off] = PTEPFN(pg->pa) | PTEVALID; pg->daddr = lvl2off; pg->next = up->mmuused; up->mmuused = pg; } /* * put in new mmu entry */ pt = (uvlong*)(((lvl2[lvl2off] >> 32)<<PGSHIFT)|KZERO); pt[LVL3OFF(va)] = FIXPTE(pa); /* flush cached mmu entries */ tlbflush(3, va); icflush(); splx(s); } void * kmapv(uvlong pa, int size) { void *va, *new; int lvl2off, i, npage, offset; uvlong *lvl2, *pt; offset = pa&(BY2PG-1); npage = ((size+offset+BY2PG-1)>>PGSHIFT); va = nextio+offset; lvl2 = (uvlong*)(KZERO|klvl2); for (i = 0; i < npage; i++) { lvl2off = LVL2OFF(nextio); if (lvl2[lvl2off] == 0) { new = xspanalloc(BY2PG, BY2PG, 0); memset(new, 0, BY2PG); lvl2[lvl2off] = PTEPFN(PADDR(new)) | PTEKVALID | PTEASM; } pt = (uvlong*)(((lvl2[lvl2off] >> 32)<<PGSHIFT)|KZERO); pt[LVL3OFF(nextio)] = PTEPFN(pa) | PTEKVALID | PTEASM; nextio += BY2PG; pa += BY2PG; } return va; } void flushmmu(void) { int s; s = splhi(); up->newtlb = 1; mmuswitch(up); splx(s); } ulong | |
| 1999/0511 | upamalloc(ulong pa, int size, int align) | |
| 1999/0415 | { | |
| 1999/0511 | void *va; /* | |
| 2000/0517 | * Viability hack. Only for PCI framebuffers. | |
| 1999/0511 | */ | |
| 1999/0512 | if(pa == 0) return 0; | |
| 1999/0511 | USED(align); va = kmapv(((uvlong)0x88<<32LL)|pa, size); if(va == nil) return 0; return PADDR(va); | |
| 1999/0415 | } void | |
| 2000/0401 | upafree(ulong, int) | |
| 1999/0415 | { | |
| 2000/0401 | print("upafree: virtual mapping not freed\n"); | |
| 1999/0415 | } | |
| 2001/0727 | void mmudump(void) { Page *top, *lvl2; iprint("ptbr %lux up %lux\n", (ulong)m->ptbr, up); if(up) { top = up->mmutop; if(top != nil) iprint("top %lux top[N-1] %lux\n", top->va, ((uvlong *)top->va)[PTE2PG-1]); lvl2 = up->mmulvl2; if(lvl2 != nil) iprint("lvl2 %lux\n", lvl2->va); } } | |