|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.