|
|
1.1 ! root 1: /* ! 2: * MMU dependent code for Coherent 386 ! 3: * ! 4: * Copyright (c) Ciaran O'Donnell, Bievres (FRANCE), 1991 ! 5: */ ! 6: ! 7: #include <sys/coherent.h> ! 8: #include <sys/clist.h> ! 9: #include <errno.h> ! 10: #include <sys/inode.h> ! 11: #include <sys/seg.h> ! 12: #include <signal.h> ! 13: #include <sys/buf.h> ! 14: #include <sys/alloc.h> ! 15: #include <l.out.h> ! 16: #include <ieeefp.h> ! 17: ! 18: /* These defines belong somewhere else: */ ! 19: #define LOMEM 0x15 /* CMOS address of size in K of memory below 1MB. */ ! 20: #define EXTMEM 0x17 /* CMOS address of size in K of memory above 1MB. */ ! 21: #define ONE_K 1024 ! 22: #define ONE_MEG 1048576 ! 23: #define USE_NDATA 1 ! 24: ! 25: /* ! 26: * DMA will not work to memory above 16M, so limit the amount of memory ! 27: * above 1M to 15M. A much cleverer scheme should be implemented. ! 28: */ ! 29: int HACK_LIMIT = (15*ONE_MEG); ! 30: ! 31: /* ! 32: * For 0 < i < 64, buddysize[i] is log(base 2) of nearest power of two ! 33: * which is greater than or equal to i. ! 34: */ ! 35: char buddysize[64] = { ! 36: -1, 0, 1, 2, 2, 3, 3, 3, ! 37: 3, 4, 4, 4, 4, 4, 4, 4, ! 38: 4, 5, 5, 5, 5, 5, 5, 5, ! 39: 5, 5, 5, 5, 5, 5, 5, 5, ! 40: 5, 6, 6, 6, 6, 6, 6, 6, ! 41: 6, 6, 6, 6, 6, 6, 6, 6, ! 42: 6, 6, 6, 6, 6, 6, 6, 6, ! 43: 6, 6, 6, 6, 6, 6, 6, 6 }; ! 44: ! 45: #define min(a, b) ((a) < (b) ? (a) : (b)) ! 46: ! 47: /* ! 48: * Functions. ! 49: * Import. ! 50: * Export. ! 51: * Local. ! 52: */ ! 53: void areacheck(); ! 54: void areafree(); ! 55: void areainit(); ! 56: BLOCKLIST * arealloc(); ! 57: int areasize(); ! 58: cseg_t * c_alloc(); ! 59: cseg_t * c_extend(); ! 60: void c_free(); ! 61: int c_grow(); ! 62: int countsize(); ! 63: void doload(); ! 64: char * getPhysMem(); ! 65: void i8086(); ! 66: void idtinit(); ! 67: void init_phy_seg(); ! 68: void mchinit(); ! 69: void msigend(); ! 70: void msigstart(); ! 71: void physMemInit(); ! 72: SR *loaded(); ! 73: unsigned int read16_cmos(); ! 74: void segload(); ! 75: void sunload(); ! 76: void unload(); ! 77: void valloc(); ! 78: ! 79: #define zero_fill(from, len) memset(from, 0, len) ! 80: ! 81: /* ! 82: * "load" a handle "hp" to a segment into the space tree for a process ! 83: */ ! 84: void ! 85: doload(srp) ! 86: register SR *srp; ! 87: { ! 88: register int n; ! 89: register cseg_t *pp; ! 90: register int base1, flags; ! 91: register int akey; ! 92: ! 93: pp = srp->sr_segp->s_vmem; ! 94: flags = srp->sr_segp->s_flags; ! 95: base1 = btocrd(srp->sr_base); ! 96: n = btoc(srp->sr_size); ! 97: ! 98: /* ! 99: * we load all pages ! 100: */ ! 101: /* a shm segment ref may be Read-Write or Read-Only */ ! 102: if (srp->sr_flag & SRFRODT) ! 103: akey = SEG_RO; ! 104: else { ! 105: switch (flags&(SFSYST|SFTEXT)) { ! 106: case SFTEXT: akey = SEG_RO; break; ! 107: case SFSYST: akey = SEG_SRW; break; ! 108: default: akey = SEG_RW; break; ! 109: } ! 110: } ! 111: ! 112: do ! 113: ptable1_v[base1++] = (*pp++ & ~SEG_NPL) | akey; ! 114: while (--n); ! 115: mmuupd(); ! 116: } ! 117: ! 118: /* ! 119: * unload a handle key "key" to a segment from the MMU hardware ! 120: */ ! 121: void ! 122: unload(srp) ! 123: register SR *srp; ! 124: { ! 125: register int n, base1; ! 126: ! 127: base1 = btocrd(srp->sr_base); ! 128: ! 129: n = btoc(srp->sr_size); ! 130: do { ! 131: ptable1_v[base1++] = SEG_ILL; ! 132: } while (--n); ! 133: mmuupd(); ! 134: } ! 135: ! 136: /* ! 137: * Allocate 'clicks_wanted' clicks of core space. ! 138: * Returns physical segment descriptor if success, else NULL. ! 139: * The physical segment descriptor is a table of page table entries ! 140: * suitable for insertion into a page table. ! 141: */ ! 142: cseg_t * ! 143: c_alloc(clicks_wanted) ! 144: unsigned clicks_wanted; ! 145: { ! 146: unsigned pno; ! 147: cseg_t *pp; ! 148: register cseg_t *qp; ! 149: ! 150: /* Do we have enough free physical clicks for this request? */ ! 151: if (clicks_wanted > allocno()) ! 152: goto no_c_alloc; ! 153: ! 154: /* Allocate some space for the table to return. */ ! 155: if ((pp = (cseg_t *)arealloc(clicks_wanted)) == 0) ! 156: goto no_c_alloc; ! 157: qp = pp; ! 158: ! 159: /* fill in entries in the requested table */ ! 160: do { ! 161: pno = *--sysmem.pfree; ! 162: if (!pvalid(pno)) ! 163: panic("c_alloc"); ! 164: *qp++ = (clickseg(pno) & ~SEG_BITS) | SEG_PRE; ! 165: } while (--clicks_wanted); ! 166: return pp; ! 167: ! 168: no_c_alloc: ! 169: return 0; ! 170: } ! 171: ! 172: /* ! 173: * Given an array "pp" containing "numClicks" click descriptors, ! 174: * if "pp" is the click list for a user segment currently loaded ! 175: * invalidate click entries for "pp" in the current page table ! 176: * return each click in "pp" to the sysmem pool, if it came from there. ! 177: * return the array "pp" to the buddy pool. ! 178: */ ! 179: void ! 180: c_free(pp, numClicks) ! 181: cseg_t *pp; ! 182: unsigned numClicks; ! 183: { ! 184: unsigned pno; ! 185: register cseg_t *qp; ! 186: register int sz; ! 187: SR *srp; ! 188: ! 189: if (srp = loaded(pp)) { ! 190: unload(srp); ! 191: srp->sr_segp = 0; ! 192: } ! 193: sz = numClicks; ! 194: if (&sysmem.pfree[sz] > sysmem.efree) ! 195: panic("c_free - nalloc"); ! 196: qp = pp; ! 197: do { ! 198: if ((*qp & SEG_NPL) == 0) { ! 199: pno = segclick(*qp); ! 200: if (!pvalid(pno)) ! 201: panic("c_free"); ! 202: *sysmem.pfree++ = pno; ! 203: } else { ! 204: T_HAL(0x40000, printf("c_free NPL %x ", *qp)); ! 205: } ! 206: qp++; ! 207: } while (--sz); ! 208: areafree((BLOCKLIST *)pp, numClicks); ! 209: } ! 210: ! 211: /* ! 212: * Given a user virtual address, a physical address, and a byte ! 213: * count, map the specified virtual address into the user data ! 214: * page table for the current process. ! 215: * ! 216: * This is meant to be called from the console ioctl, KDMAPDISP. ! 217: * The user virtual address must be click aligned. ! 218: * The range of physical addresses must lie outside installed RAM ! 219: * or within the "PHYS_MEM" pool. ! 220: * ! 221: * Return 1 on success, else 0. ! 222: */ ! 223: int ! 224: mapPhysUser(virtAddr, physAddr, numBytes) ! 225: { ! 226: int ret = 0; ! 227: SR * srp = u.u_segl + SIPDATA; ! 228: SEG * sp = srp->sr_segp; ! 229: cseg_t * pp = sp->s_vmem, * qp; ! 230: int pno, clickOffset, numClicks, i; ! 231: ! 232: /* Check alignment. */ ! 233: if ((virtAddr & (NBPC-1)) || (physAddr & (NBPC-1))) { ! 234: T_HAL(0x40000, printf("mPU: failed alignment ")); ! 235: goto mPUdone; ! 236: } ! 237: ! 238: /* Check validity of range of virtual addresses. */ ! 239: if (virtAddr < srp->sr_base || ! 240: (virtAddr + numBytes) >= (srp->sr_base + srp->sr_size)) { ! 241: T_HAL(0x40000, printf("mPU: bad vaddr ")); ! 242: goto mPUdone; ! 243: } ! 244: ! 245: /* Check validity of range of physical addresses. */ ! 246: /* if not in PHYS_MEM pool... */ ! 247: if (!physValid(physAddr, numBytes)) { ! 248: ! 249: /* get installed RAM physical addresses */ ! 250: unsigned int physLow = ctob((read16_cmos(LOMEM) + 3) >> 2); ! 251: unsigned int physHigh = ctob((read16_cmos(EXTMEM) + 3) >> 2) ! 252: + ONE_MEG; ! 253: ! 254: T_HAL(0x40000, printf("physLow=%x physHigh=%x ", ! 255: physLow, physHigh)); ! 256: ! 257: /* Fail if physical range overlaps installed base RAM. */ ! 258: if (physAddr < physLow) { ! 259: T_HAL(0x40000, printf("mPU: overlap base RAM ")); ! 260: goto mPUdone; ! 261: } ! 262: ! 263: /* Fail if physical range overlaps installed extended RAM. */ ! 264: if (physAddr < physHigh && (physAddr + numBytes) >= ONE_MEG) { ! 265: T_HAL(0x40000, printf("mPU: overlap extended RAM ")); ! 266: goto mPUdone; ! 267: } ! 268: } ! 269: ! 270: /* ! 271: * For each click in user data segment which is to be remapped ! 272: * if current click was taken from sysmem pool ! 273: * return current click to sysmem pool ! 274: * write new physical address into current click entry ! 275: * mark current click as not coming from sysmem pool ! 276: * map current click into page table ! 277: */ ! 278: clickOffset = btocrd(virtAddr - srp->sr_base); ! 279: numClicks = numBytes >> BPCSHIFT; ! 280: for (qp = pp + clickOffset, i = 0; i < numClicks; i++, qp++) { ! 281: if ((*qp & SEG_NPL) == 0) { ! 282: pno = segclick(*qp); ! 283: if (!pvalid(pno)) { ! 284: T_HAL(0x40000, printf("mPU: bad release ")); ! 285: } else { ! 286: *sysmem.pfree++ = pno; ! 287: T_HAL(0x40000, ! 288: printf("mPU: freeing virtual click %x ", ! 289: virtAddr + ctob(i))); ! 290: } ! 291: } else { ! 292: T_HAL(0x40000, ! 293: printf("mPU: rewriting virtual NPL click %x ", ! 294: virtAddr + ctob(i))); ! 295: } ! 296: *qp = (physAddr + ctob(i)) | (SEG_RW | SEG_NPL); ! 297: ptable1_v[btocrd(virtAddr) + i] = *qp; ! 298: } ! 299: mmuupd(); ! 300: ret = 1; ! 301: ! 302: mPUdone: ! 303: return ret; ! 304: } ! 305: ! 306: /* ! 307: * Add a click to a segment. ! 308: * Enlarge buddy table for segment, if needed. ! 309: * ! 310: * Arguments: ! 311: * pp points to segment reference table (segp->s_vmem, e.g.) ! 312: * osz is old segment size, in clicks ! 313: * ! 314: * Return pointer to enlarged segment reference table, or NULL if failed. ! 315: */ ! 316: cseg_t * ! 317: c_extend(pp, osz) ! 318: register cseg_t *pp; ! 319: int osz; ! 320: { ! 321: register cseg_t *pp1; ! 322: register unsigned pno; ! 323: register int i; ! 324: SR *srp; ! 325: ! 326: /* Fail if no more free clicks available. */ ! 327: if (sysmem.pfree < &sysmem.tfree[1]) ! 328: goto no_c_extend; ! 329: ! 330: /* Don't grow segment beyond hardware segment size (4 megabytes). */ ! 331: if (osz >= (NBPS/NBPC)) ! 332: goto no_c_extend; ! 333: ! 334: if (srp = loaded(pp)) { ! 335: unload(srp); ! 336: srp->sr_segp = 0; ! 337: } ! 338: ! 339: /* ! 340: * If the old size was a power of 2, it has used up an entire ! 341: * buddy area, so we will need to allocate more space. ! 342: */ ! 343: if (IS_POW2(osz)) { ! 344: if ((pp1 = (cseg_t*) arealloc(osz+1))==0) ! 345: goto no_c_extend; ! 346: for (i=0; i < osz; i++) ! 347: pp1[i] = pp[i]; ! 348: areafree(pp, osz); ! 349: pp = pp1; ! 350: } ! 351: ! 352: for (i=osz; --i >= 0;) ! 353: pp[i+1] = pp[i]; ! 354: ! 355: pno = *--sysmem.pfree; ! 356: if (!pvalid(pno)) ! 357: panic("c_extend"); ! 358: pp[0] = clickseg(pno) | SEG_RW; ! 359: return pp; ! 360: ! 361: no_c_extend: ! 362: return 0; ! 363: } ! 364: ! 365: /* ! 366: * Given segment size in bytes, estimate total space needed ! 367: * to keep track of the segment (I think - hws). ! 368: * ! 369: * return value is num_bytes plus some overhead... ! 370: */ ! 371: int ! 372: countsize(num_bytes) ! 373: int num_bytes; ! 374: { ! 375: int ret; ! 376: ! 377: if (num_bytes <= NBPC/sizeof(long)) ! 378: ret = num_bytes+1; ! 379: else ! 380: ret = num_bytes ! 381: + ((num_bytes + NBPC/sizeof(long) - 1) >> BPC1SHIFT) + 1; ! 382: return ret; ! 383: } ! 384: ! 385: /* ! 386: * buddy allocation ! 387: */ ! 388: ! 389: /* ! 390: * Deallocate a segment descriptor area. ! 391: * "sp" is not really a BLOCKLIST*, rather a cseg_t *. ! 392: * "numClicks" is the number of clicks referenced in the area. ! 393: */ ! 394: void ! 395: areafree(sp, numClicks) ! 396: BLOCKLIST *sp; ! 397: int numClicks; ! 398: { ! 399: register int n; /* adresse du buddy, taille du reste */ ! 400: register int ix, nx; ! 401: register BLOCKLIST *buddy; ! 402: ! 403: areacheck(2, sp); ! 404: ! 405: /* ! 406: * Pointer "sp" points to an element in the sysmem table of ! 407: * free clicks. ! 408: * Integer "ix" is the index of "sp" into that table. ! 409: * Will use "ix" to index into one or more buddy tables. ! 410: */ ! 411: ix = sp - sysmem.u.budtab; ! 412: n = areasize(numClicks); ! 413: do { ! 414: /* "nx" is index of buddy element to the one at "ix". */ ! 415: nx = BUDDY(ix, n); ! 416: if (sysmem.budfree[nx>>WSHIFT] & 1<<(nx&(WCOUNT-1))) { ! 417: /* coalesce two buddies */ ! 418: buddy = sysmem.u.budtab + nx; ! 419: if (buddy->kval != n) ! 420: break; ! 421: sysmem.budfree[nx>>WSHIFT] &= ~ (1<<(nx & (WCOUNT-1))); ! 422: DELETE2(buddy); ! 423: if (nx < ix) ! 424: ix = nx; ! 425: } else ! 426: break; ! 427: } while (++n < NBUDDY); ! 428: sysmem.budfree[ix>>WSHIFT] |= 1 << (ix & (WCOUNT-1)); ! 429: buddy = sysmem.u.budtab + ix; ! 430: INSERT2(BLOCKLIST, buddy, &sysmem.bfree[n]); ! 431: buddy->kval = n; ! 432: areacheck(3, buddy); ! 433: } ! 434: ! 435: /* ! 436: * arealloc() ! 437: * ! 438: * Given size in "clicks" of a segment to manage, ! 439: * return pointer to an array of enough descriptors. ! 440: * If not enough free descriptors available, return 0. ! 441: */ ! 442: BLOCKLIST * ! 443: arealloc(clicks) ! 444: register int clicks; ! 445: { ! 446: register BLOCKLIST *sp; ! 447: register BLOCKLIST *p, *q; ! 448: register int size; ! 449: BLOCKLIST *rsp; ! 450: register int nx; ! 451: ! 452: areacheck(0, 0); ! 453: size = areasize(clicks); ! 454: /* ! 455: * 1. Find little end, bloc p, free >= size ! 456: */ ! 457: for (q = p = sysmem.bfree + size;p->forw == p; size++, p++) ! 458: if (p >= sysmem.bfree + NBUDDY - 1) { ! 459: return(0); /* y en a pas */ ! 460: } ! 461: ! 462: rsp = p->forw; ! 463: DELETE2(rsp); ! 464: nx = rsp - sysmem.u.budtab; ! 465: sysmem.budfree[nx>>WSHIFT] &= ~(1 << (nx & (WCOUNT-1))); ! 466: size = 1<<size; ! 467: sp = rsp + size; /* buddy address */ ! 468: while (p-- != q) { ! 469: /* ! 470: * 2.1 The block is too big, uncouple & free buddy ! 471: */ ! 472: sp -= (size >>= 1); ! 473: nx = sp - sysmem.u.budtab; ! 474: sysmem.budfree[nx>>WSHIFT] |= 1 << (nx & (WCOUNT-1)); ! 475: INSERT2(BLOCKLIST, sp, p); ! 476: sp->kval = p - sysmem.bfree; ! 477: } ! 478: areacheck(1, rsp); ! 479: return rsp; ! 480: } ! 481: ! 482: void ! 483: areainit(n) ! 484: { ! 485: extern char __end[]; ! 486: register int i; ! 487: ! 488: for (i=0; i < (1<<(NBUDDY-WSHIFT)); i++) ! 489: sysmem.budfree[i] = 0; ! 490: for (i=0; i<NBUDDY; i++) ! 491: INIT2(&sysmem.bfree[i]); ! 492: sysmem.u.budtab = (BLOCKLIST *)__end; ! 493: n /= sizeof(BLOCKLIST); ! 494: if (n > (1 << NBUDDY)) ! 495: panic("areainit"); ! 496: for (i=0; i<n; i++) ! 497: areafree(&sysmem.u.budtab[i], sizeof(BLOCKLIST)/sizeof(long)); ! 498: } ! 499: ! 500: /* ! 501: * areasize() ! 502: * ! 503: * Do a log(base 2) calculation on n. ! 504: * If n is zero, return -1. ! 505: * ! 506: * Else, consider the nearest power of two which is greater than or ! 507: * equal to n ! 508: * p/2 < n <= p ! 509: * Then set p = 4 * (2**x). Note BLKSZ is 2. ! 510: * Return max(x,0). ! 511: * ! 512: * If n is too large (more than 3F00), we will go beyond the limits of ! 513: * table buddysize[]. ! 514: * ! 515: * In practice, n is the total number of clicks needed in a segment, ! 516: * and the return value will be used to access a buddy system list. ! 517: */ ! 518: int ! 519: areasize(n) ! 520: register unsigned int n; ! 521: { ! 522: register int m; ! 523: #ifdef FROTZ ! 524: int ret, oldn = n; ! 525: #endif ! 526: ! 527: if (n > 0x3F00) ! 528: panic("areasize"); ! 529: ! 530: n = (n + (1 << BLKSZ) - 1) >> BLKSZ; ! 531: m = n & 0x3F; ! 532: #ifdef FROTZ ! 533: if ((n >>= 6) == 0) ! 534: ret = buddysize[m]; ! 535: else { ! 536: int index; ! 537: ! 538: index = n; ! 539: if (m) ! 540: index++; ! 541: ret = buddysize[index] + 6; ! 542: } ! 543: return ret; ! 544: #else ! 545: if ((n >>= 6) == 0) ! 546: return buddysize[m]; ! 547: return buddysize[n + ((m!=0)?1:0)] + 6; ! 548: #endif ! 549: } ! 550: ! 551: #define MAXBUDDY 2048 ! 552: #define CHECK(p) ((p>=&sysmem.bfree[0] && p<&sysmem.bfree[NBUDDY]) || \ ! 553: (p>=sysmem.u.budtab && p<&sysmem.u.budtab[1<<NBUDDY])) ! 554: void ! 555: areacheck(flag, sp) ! 556: register BLOCKLIST *sp; ! 557: { ! 558: register BLOCKLIST *next, *start; ! 559: register int i, nx; ! 560: ! 561: if (sp) { ! 562: if (&sysmem.u.budtab[sp-sysmem.u.budtab] != sp) ! 563: printf("*check* %d %x %x\n", flag, sp, sysmem.u.budtab); ! 564: } ! 565: ! 566: for (i=0; i<NBUDDY; i++) { ! 567: start = next = &sysmem.bfree[i]; ! 568: do { ! 569: next = next->forw; ! 570: if (!CHECK(next)) ! 571: printf("next = %x (%d)\n", next, flag); ! 572: if (next->back != start) ! 573: printf("%x->forw->back != %x\n", next, start); ! 574: if (next != &sysmem.bfree[i]) { ! 575: if (next->kval != i) ! 576: printf("bad kval %x, %d (%d)\n", ! 577: next, next->kval, flag); ! 578: nx = next - sysmem.u.budtab; ! 579: if ((sysmem.budfree[nx>>WSHIFT] & (1 << (nx & (WCOUNT-1)))) == 0) ! 580: printf("in bfree but not budfree %x (%d)\n", next, flag); ! 581: } ! 582: start = next; ! 583: } while (next != &sysmem.bfree[i]); ! 584: } ! 585: } ! 586: ! 587: MAKESR(physMem, _physMem); ! 588: int PHYS_MEM = 0; /* Number of bytes of contiguous RAM needed */ ! 589: ! 590: /* ! 591: * A block of contiguous physical memory has been allocated for special ! 592: * i/o devices. ! 593: * Problem: clicks of physical memory are in reverse order in the ! 594: * page table. ! 595: * This routine reverses the page table entries for the pages ! 596: * involved. It relies *heavily* on all pages having virtual addresses ! 597: * in the FFCx xxxx segment. ! 598: * ! 599: * If all goes well, assign physAvailStart to the virtual address of ! 600: * the beginning of the region, and physAvailBytes to the number of bytes ! 601: * in the region. Otherwise, leave physAvailStart and physAvailBytes at 0. ! 602: * ! 603: * As memory is allocated, physAvailStart advances to point to the next ! 604: * available byte of contiguous memory, physAvailBytes is decremented, ! 605: * and physPoolStart remains set to the virtual address of the start of ! 606: * the contiguous pool. ! 607: */ ! 608: static int physPoolStart; /* start of contiguous memory area */ ! 609: static int physAvailStart; /* next free byte in contiguous memory area */ ! 610: static int physAvailBytes; /* number of bytes in contiguous memory area */ ! 611: ! 612: /* ! 613: * Check whether a range of physical addresses lies within the ! 614: * pool of contiguous physical memory. ! 615: */ ! 616: int ! 617: physValid(base, numBytes) ! 618: unsigned int base, numBytes; ! 619: { ! 620: int vpool; ! 621: int ret = 0; ! 622: ! 623: if (PHYS_MEM) { ! 624: vpool = vtop(physPoolStart); ! 625: T_HAL(0x40000, printf("PHYS_MEM phys addrs %x to %x ", ! 626: vpool, vpool + PHYS_MEM)); ! 627: if (base >= vpool && (base + numBytes) <= (vpool + PHYS_MEM)) ! 628: ret = 1; ! 629: } else { ! 630: T_HAL(0x40000, printf("No PHYS_MEM ")); ! 631: } ! 632: ! 633: T_HAL(0x40000, printf("physValid(%x, %x) = %d ", base, numBytes, ret)); ! 634: return ret; ! 635: } ! 636: ! 637: void ! 638: physMemInit() ! 639: { ! 640: int m, vaddr; ! 641: int err = 0, num_clicks = btoc(PHYS_MEM); ! 642: int prevPaddr, paddr; ! 643: ! 644: /* ! 645: * Going half way into page table for physMem ! 646: * If entry and its complementary entry aren't both in top segment ! 647: * Error exit (no phys mem will be available). ! 648: * Get page table entries and swap them. ! 649: */ ! 650: for (m = 0; m < num_clicks/2; m++) { ! 651: int m2 = num_clicks - 1 - m; /* complementary index */ ! 652: ! 653: /* compute virtual addresses */ ! 654: int lo_addr = physMem.sr_base + ctob(m); ! 655: int hi_addr = physMem.sr_base + ctob(m2); ! 656: ! 657: /* compute indices into page table (ptable1_v) */ ! 658: int lo_p1ix = btocrd(lo_addr); ! 659: int hi_p1ix = btocrd(hi_addr); ! 660: ! 661: /* fetch physical addresses from page table */ ! 662: int lo_paddr = ptable1_v[lo_p1ix]; ! 663: int hi_paddr = ptable1_v[hi_p1ix]; ! 664: ! 665: /* abort if either address is not in top segment */ ! 666: if (btosrd(lo_addr) != 0x3FF) { ! 667: err = 1; ! 668: break; ! 669: } ! 670: if (btosrd(hi_addr) != 0x3FF) { ! 671: err = 1; ! 672: break; ! 673: } ! 674: ! 675: /* exchange page table entries */ ! 676: ptable1_v[lo_p1ix] = hi_paddr; ! 677: ptable1_v[hi_p1ix] = lo_paddr; ! 678: } ! 679: ! 680: /* ! 681: * Final sanity check. ! 682: * In case someone gets creative with startup code, check ! 683: * again here that the memory is actually contiguous. ! 684: */ ! 685: prevPaddr = vtop(physMem.sr_base); ! 686: for (m = 0; m < num_clicks - 1; m++) { ! 687: paddr = vtop(physMem.sr_base + ctob(m + 1)); ! 688: if (paddr - prevPaddr != NBPC) { ! 689: err = 1; ! 690: break; ! 691: } ! 692: prevPaddr = paddr; ! 693: } ! 694: ! 695: if (!err) { ! 696: physPoolStart = physAvailStart = physMem.sr_base; ! 697: physAvailBytes = PHYS_MEM; ! 698: } ! 699: } ! 700: ! 701: /* ! 702: * Return virtual address of block of contiguous physical memory. ! 703: * If request cannot be granted, return 0. ! 704: * ! 705: * Expect physMem resource to be granted during load routine of device ! 706: * drivers. Once allocated, memory is not returned to the physMem pool. ! 707: */ ! 708: char * ! 709: getPhysMem(numBytes) ! 710: unsigned int numBytes; ! 711: { ! 712: char * ret = NULL; ! 713: ! 714: if (numBytes <= physAvailBytes) { ! 715: ret = (char *)physAvailStart; ! 716: physAvailStart += numBytes; ! 717: physAvailBytes -= numBytes; ! 718: } else ! 719: printf("getPhysMem failed - %d additional bytes " ! 720: "PHYS_MEM needed\n", physAvailBytes - numBytes); ! 721: return ret; ! 722: } ! 723: ! 724: /* ! 725: * Return virtual address of aligned block of contiguous physical memory. ! 726: * Mainly for devices using the stupid Intel DMA hardware without ! 727: * scatter/gather. ! 728: * If request cannot be granted, return 0. ! 729: * ! 730: * Argument "align" says what physical boundary we need alignment on. ! 731: * It must be a power of 2. ! 732: * For 4k alignment, align = 4k, etc. ! 733: * Sorry, but will throw away memory to get to the next acceptable address. ! 734: * ! 735: * Once allocated, memory is not returned to the physMem pool. ! 736: */ ! 737: char * ! 738: getDmaMem(numBytes, align) ! 739: unsigned int numBytes; ! 740: unsigned int align; ! 741: { ! 742: char * ret = NULL; ! 743: int wastedBytes, neededBytes; ! 744: ! 745: if (align == 0) { ! 746: printf("getDmaMem(0) (?)\n"); ! 747: goto getDmaMemDone; ! 748: } ! 749: ! 750: if (!IS_POW2(align)) { ! 751: printf("getDmaMem(%x) (?)\n", align); ! 752: goto getDmaMemDone; ! 753: } ! 754: ! 755: /* ! 756: * Waste RAM from bottom of pool up to physical ! 757: * address with desired alignment. ! 758: */ ! 759: wastedBytes = align - (vtop(physAvailStart) % align); ! 760: neededBytes = numBytes + wastedBytes; ! 761: ! 762: if (neededBytes <= physAvailBytes) { ! 763: ret = (char *)physAvailStart + wastedBytes; ! 764: physAvailStart += neededBytes; ! 765: physAvailBytes -= neededBytes; ! 766: } else ! 767: printf("getDmaMem failed - %d additional bytes " ! 768: "PHYS_MEM needed\n", physAvailBytes - neededBytes); ! 769: ! 770: getDmaMemDone: ! 771: return ret; ! 772: } ! 773: /***************/ ! 774: ! 775: #undef ptable1_v ! 776: ! 777: /* ! 778: * pageDir is the physical address of the click in use for the page ! 779: * directory, offset by ctob(SBASE - PBASE) ! 780: */ ! 781: #define pageDir ((long *)(&stext[ctob(-1)])) ! 782: ! 783: int total_clicks; /* How many clicks did we start with? */ ! 784: ! 785: void ! 786: mchinit() ! 787: { ! 788: extern char __end[], __end_data[], stext[], __end_text[], sdata[]; ! 789: extern int RAM0, RAMSIZE; ! 790: ! 791: int lo; /* Number of bytes of physical memory below 640K. */ ! 792: int hi; /* Number of bytes of physical memory above 1M. */ ! 793: register char *pe; ! 794: register int zero = 0; ! 795: register int i; ! 796: register long *ptable1_v; ! 797: register unsigned short base; ! 798: int sysseg, codeseg, stackseg, ramseg, ptable1; ! 799: int ptoff; /* An offset into pageDir[] */ ! 800: #if USE_NDATA ! 801: int dataseg[NDATA]; ! 802: #else ! 803: int dataseg; ! 804: #endif ! 805: int nalloc; ! 806: extern char digtab[]; ! 807: static SEG uinit; ! 808: int budArenaBytes; /* number of bytes in buddy pool */ ! 809: int kerBytes; /* number of bytes in kernel text and data */ ! 810: ! 811: /* ! 812: * 1. ! 813: * a. Relocate the data on a page boundary (4K bytes) the ! 814: * bootstrap relocates it on a paragraph boundary (16 bytes) ! 815: * ! 816: * b. Verify that the data has been relocated correctly ! 817: */ ! 818: pe = __end_data; /* 1.a */ ! 819: i = (((unsigned)__end_text+15) & ~15) - (unsigned)sdata; ! 820: do { ! 821: pe--; ! 822: pe[0] = pe[i]; ! 823: } while (pe != sdata); /* 1.b */ ! 824: ! 825: /* ! 826: * Can now access the .data segment from C. ! 827: * If not, next loop will hang the kernel. ! 828: */ ! 829: CHIRP('A'); ! 830: while (digtab[0]!='0'); ! 831: CHIRP('*'); ! 832: ! 833: /* Zero the bss. */ ! 834: pe = __end_data; ! 835: do ! 836: *pe++ = zero; ! 837: while (pe != __end); ! 838: ! 839: /* ! 840: * Zero the level 0 page directory, which occupies the click ! 841: * of virtual space immediately below kernel text. ! 842: */ ! 843: pe = (char *) pageDir; ! 844: do ! 845: *pe++ = zero; ! 846: while (pe != stext); ! 847: ! 848: CHIRP('2'); ! 849: ! 850: /* ! 851: * 3. Calculate total system memory. ! 852: * Count the space used by the system and the page ! 853: * descriptors, the interrupt stack, and the refresh work area ! 854: * ! 855: * a. initialize allocation area and adjust system size ! 856: * to take allocation area and free page area into account ! 857: */ ! 858: ! 859: /* ! 860: * btoc(__end) - SBASE is the number of clicks in kernel text ! 861: * plus data, rounded up. ! 862: * PBASE is the starting physical click number of the kernel. ! 863: * ! 864: * Set sysmem.lo to the physical click address just past the kernel. ! 865: */ ! 866: DV(__end); ! 867: ! 868: kerBytes = __end - ((SBASE - PBASE)<<BPCSHIFT); ! 869: DV(kerBytes); ! 870: ! 871: sysmem.lo = btoc(kerBytes); ! 872: DV(sysmem.lo); ! 873: ! 874: /* ! 875: * lo is the size in bytes of memory between the end of the kernel ! 876: * and the end of memory below 640K. ! 877: * hi is the size in bytes of memory over 1 Megabyte (Extended memory). ! 878: * ! 879: * Round the sizes from the CMOS down to the next click. This ! 880: * compensates for systems where the CMOS reports sizes that are ! 881: * not multiples of 4K. ! 882: */ ! 883: DV(read16_cmos(LOMEM)); ! 884: lo = ctob(read16_cmos(LOMEM) >> 2) - ctob(sysmem.lo); ! 885: DV(lo); ! 886: ! 887: DV(read16_cmos(EXTMEM)); ! 888: hi = ctob(read16_cmos(EXTMEM) >> 2); ! 889: DV(hi); ! 890: ! 891: /* ! 892: * Sometimes, we die horribly if there is too much memory. ! 893: * Artificially limit hi to HACK_LIMIT. ! 894: */ ! 895: if (hi > HACK_LIMIT) ! 896: hi = HACK_LIMIT; ! 897: ! 898: /* clear base memory above the kernel */ ! 899: CHIRP('z'); ! 900: zero_fill(ctob(sysmem.lo+SBASE-PBASE), lo); ! 901: CHIRP('Z'); ! 902: ! 903: /* clear extended memory */ ! 904: zero_fill(ONE_MEG+ctob(SBASE-PBASE), hi); ! 905: CHIRP('Y'); ! 906: ! 907: /* Record total memory for later use. */ ! 908: total_mem = ctob(sysmem.lo) + lo + hi; ! 909: DV(total_mem); ! 910: ! 911: /* ! 912: * sysmem.pfree and relatives will keep track of a pool of 4k pages ! 913: * assigned to processes, hereinafter known as the sysmem pool. ! 914: * How many clicks can go into this pool? nalloc. ! 915: * Allow NBPC for the click itself, a short for the sysmem pointer, ! 916: * and SPLASH*sizeof(long) for buddy system overhead. ! 917: */ ! 918: nalloc = (lo+hi) / (sizeof(short) + SPLASH*sizeof(long) + NBPC); ! 919: DV(nalloc); ! 920: ! 921: /* ! 922: * ASSERT: ! 923: * For the moment we want only to assure that the ! 924: * BUDDY arena and the stack of free pages will fit below ! 925: * 640K. ! 926: */ ! 927: budArenaBytes = SPLASH*nalloc*sizeof(long); ! 928: DV(budArenaBytes); ! 929: ! 930: #define SIZEOF_FREE_PAGES ((btoc(hi) + btoc(lo))* sizeof(short)) ! 931: T_PIGGY(0x800, { ! 932: if (budArenaBytes + SIZEOF_FREE_PAGES >= lo) { ! 933: panic("Too much memory"); ! 934: } ! 935: }); ! 936: ! 937: /* ! 938: * Initialize the buddy system arena. This memory is used ! 939: * for the compressed page tables. ! 940: */ ! 941: areainit(budArenaBytes); ! 942: ! 943: /* ! 944: * Initialize the stack of free pages. ! 945: * __end is the virtual address just past kernel data ! 946: * Point sysmem.tfree to the lowest virtual address just above ! 947: * the buddy pool, and initialize sysmem.pfree there. ! 948: */ ! 949: sysmem.tfree = sysmem.pfree = ! 950: (unsigned short *)(__end + budArenaBytes); ! 951: DV(sysmem.tfree); ! 952: ! 953: /* sysmem.hi is the physical click number just past high RAM */ ! 954: sysmem.hi = btoc(hi+ONE_MEG); ! 955: DV(sysmem.hi); ! 956: ! 957: /* base is the physical click number just past base RAM */ ! 958: base = sysmem.lo + (lo>>BPCSHIFT); ! 959: DV(base); ! 960: ! 961: /* ! 962: * Adjust sysmem.lo to be the physical click number just above ! 963: * not just the kernel, but above sysmem overhead as well. ! 964: */ ! 965: sysmem.lo = btoc(kerBytes + budArenaBytes + nalloc*sizeof(short)); ! 966: DV(sysmem.lo); ! 967: ! 968: /* ! 969: * sysmem.vaddre is the virtual address of the next click after the ! 970: * kernel. ! 971: */ ! 972: sysmem.vaddre = ctob(sysmem.lo+SBASE-PBASE); ! 973: DV(sysmem.vaddre); ! 974: ! 975: /* include in system area pages for arena, free area */ ! 976: ! 977: CHIRP('3'); ! 978: ! 979: /* ! 980: * 4. ! 981: * Free the memory from [end, 640) kilobytes ! 982: * Free the memory from [1024, 16*1024) kilobytes ! 983: * ! 984: * We are building a stack of free pages bounded below ! 985: * by sysmem.tfree and above by sysmem.efree. sysmem.pfree ! 986: * is the top of the stack. The stack grows upwards. ! 987: */ ! 988: total_clicks = 0; ! 989: ! 990: /* ! 991: * Initialize the sysmem table (phase 1 - base RAM). ! 992: * Put base RAM above the kernel and sysmem overhead area into ! 993: * sysmem pool. ! 994: */ ! 995: while (base > sysmem.lo) { ! 996: *sysmem.pfree++ = --base; ! 997: ++total_clicks; ! 998: } ! 999: ! 1000: /* ! 1001: * Initialize the sysmem table (phase 2 - extended RAM). ! 1002: * Put all extended RAM into the sysmem pool. ! 1003: */ ! 1004: base = btoc(ONE_MEG); ! 1005: while (base < sysmem.hi && total_clicks < nalloc) { ! 1006: *sysmem.pfree++ = base++; ! 1007: ++total_clicks; ! 1008: } ! 1009: DV(total_clicks); ! 1010: ! 1011: /* ! 1012: * Roundoff error may have made nalloc smaller than necessary. ! 1013: */ ! 1014: while(base < sysmem.hi) { ! 1015: if (sysmem.pfree + 1 >= sysmem.vaddre) ! 1016: break; ! 1017: *sysmem.pfree++ = base++; ! 1018: ++total_clicks; ! 1019: nalloc++; ! 1020: } ! 1021: DV(total_clicks); ! 1022: DV(nalloc); ! 1023: ! 1024: /* ! 1025: * sysmem.efree points just past the last pointer in the sysmem ! 1026: * table. ! 1027: */ ! 1028: sysmem.efree = sysmem.pfree; ! 1029: DV(sysmem.efree); ! 1030: DV(allocno()); ! 1031: ! 1032: T_PIGGY(0x800, { ! 1033: /* ! 1034: * ASSERT: The stack of free pages should end within a click ! 1035: * of the lowest available memory. ! 1036: */ ! 1037: if ((cseg_t *)ctob(sysmem.lo+SBASE-PBASE) < sysmem.efree) { ! 1038: panic("sysmem.lo is too low"); ! 1039: } ! 1040: ! 1041: if (sysmem.efree < (cseg_t *)ctob(sysmem.lo+SBASE-PBASE - 1)){ ! 1042: panic("sysmem.efree is too low"); ! 1043: } ! 1044: ! 1045: /* ! 1046: * ASSERT: There should be nalloc total_clicks. ! 1047: */ ! 1048: if (nalloc != total_clicks) { ! 1049: panic("nalloc != total_clicks "); ! 1050: } ! 1051: }); ! 1052: ! 1053: CHIRP('4'); ! 1054: ! 1055: /* ! 1056: * 5. allocate page entries and initialize level 0 ^'s ! 1057: * a. [ 00000000 .. 003FFFFF) user code segment ! 1058: * b. [ 00400000 .. 007FFFFF) user data & bss ! 1059: * c. [ 7FC00000 .. 7FFFFFFF) user stack ! 1060: *c.i.[ 80000000 .. 80FFFFFF) ram disk ! 1061: * d. [ FF800000 .. FFBFFFFF) pointers to level 1 page table ! 1062: * e. [ FFC00000 .. FFFFFFFF) system process addresses ! 1063: */ ! 1064: codeseg = clickseg(*--sysmem.pfree); /* 5.a */ ! 1065: pageDir[0x000] = codeseg | DIR_RW; ! 1066: ! 1067: #if USE_NDATA ! 1068: for (i = 0; i < NDATA; i++) { ! 1069: dataseg[i] = clickseg(*--sysmem.pfree); /* 5.b */ ! 1070: pageDir[0x001+i] = dataseg[i] | DIR_RW; ! 1071: } ! 1072: #else ! 1073: dataseg = clickseg(*--sysmem.pfree); /* 5.b */ ! 1074: pageDir[0x001] = dataseg | DIR_RW; ! 1075: #endif ! 1076: ! 1077: stackseg = clickseg(*--sysmem.pfree); /* 5.c */ ! 1078: pageDir[0x1FF] = stackseg | DIR_RW; ! 1079: ! 1080: /* ! 1081: * ptable1 is a handle for the click containing page table ! 1082: * entries for the page table. ! 1083: * ! 1084: * allocate a click for ptable1 ! 1085: * Then point at it from the page directory. ! 1086: */ ! 1087: ptable1 = clickseg(*--sysmem.pfree); /* 5.d */ ! 1088: pageDir[0x3FE] = ptable1 | DIR_RW; ! 1089: ! 1090: sysseg = clickseg(*--sysmem.pfree); /* 5.e */ ! 1091: pageDir[0x3FF] = sysseg | DIR_RW; ! 1092: ! 1093: CHIRP('5'); ! 1094: ! 1095: /* ! 1096: * 6. initialize level 2 ^'s to [5.d] ! 1097: */ ! 1098: ! 1099: ptable1_v = (long *)(ptable1 + ctob(SBASE-PBASE)); ! 1100: DV(pageDir); ! 1101: DV(ptable1_v); ! 1102: ptable1_v[0x000] = codeseg | SEG_SRW; ! 1103: #if USE_NDATA ! 1104: for (i = 0; i < NDATA; i++) ! 1105: ptable1_v[0x001+i] = dataseg[i] | SEG_SRW; ! 1106: #else ! 1107: ptable1_v[0x001] = dataseg | SEG_SRW; ! 1108: #endif ! 1109: ptable1_v[0x1FF] = stackseg| SEG_SRW; ! 1110: ! 1111: /* ! 1112: * This ram disk stuff should go away once the scheme ! 1113: * for allocating pieces of virtual memory space is in place. ! 1114: */ ! 1115: for (ptoff = btosrd(RAM0) & 0x3ff; ! 1116: ptoff < (btosrd(RAM0 + 2 * RAMSIZE) & 0x3ff); ++ptoff) { ! 1117: ramseg = clickseg(*--sysmem.pfree); /* 5.c.i */ ! 1118: pageDir[ptoff] = ramseg | DIR_RW; ! 1119: ptable1_v[ptoff] = ramseg | SEG_SRW; ! 1120: } ! 1121: ! 1122: ptable1_v[0x3FF] = sysseg | SEG_SRW; ! 1123: ! 1124: CHIRP('6'); ! 1125: ! 1126: /* ! 1127: * 7. ! 1128: * b. map kernel code and data ! 1129: * map ^ to: ! 1130: * c. level 0 page table ! 1131: * d. level 1 page table ! 1132: * e. I/O segments (video RAM, ...) ! 1133: */ ! 1134: ! 1135: ptable1_v = (long *)(sysseg + ctob(SBASE-PBASE)); /* 7.b */ ! 1136: DV(ptable1_v); ! 1137: for (i = PBASE; i <sysmem.lo; i++) ! 1138: ptable1_v[i-PBASE] = clickseg(i) | SEG_SRW; ! 1139: ! 1140: ptable1_v[0x3FE] = clickseg(PTABLE0_P) | SEG_SRW; /* 7.c */ ! 1141: ptable1_v[0x3FD] = ptable1 | SEG_SRW; /* 7.d */ ! 1142: ! 1143: init_phy_seg(ptable1_v, ROM-SBASE, 0x0000F0000); /* 7.e. */ ! 1144: init_phy_seg(ptable1_v, VIDEOa-SBASE,0x0000B0000); ! 1145: init_phy_seg(ptable1_v, VIDEOb-SBASE,0x0000B8000); ! 1146: ! 1147: CHIRP('7'); ! 1148: ! 1149: /* ! 1150: * 8. allocate and map U area ! 1151: */ ! 1152: ! 1153: uinit.s_flags = SFSYST|SFCORE; ! 1154: uinit.s_size = UPASIZE; ! 1155: uinit.s_vmem = c_alloc(btoc(UPASIZE)); ! 1156: ptable1_v[0x3FF] = *uinit.s_vmem | SEG_SRW; ! 1157: procq.p_segp[SIUSERP] = &uinit; ! 1158: ! 1159: CHIRP('8'); ! 1160: ! 1161: /* ! 1162: * 9. make FFC00000 and 00002000 map to the same address ! 1163: * to prevent the prefetch after the instruction turning on ! 1164: * paging from causing a page fault ! 1165: */ ! 1166: ptable1_v = (long *)(codeseg + ctob(SBASE-PBASE)); ! 1167: DV(ptable1_v); ! 1168: ptable1_v[PBASE] = clickseg(PBASE) | SEG_SRW; ! 1169: ! 1170: CHIRP('9'); ! 1171: ! 1172: /* ! 1173: * 10. load page table base address into MMU ! 1174: * fix up the interrupt vectors ! 1175: */ ! 1176: mmuupdnR0(); ! 1177: CHIRP('U'); ! 1178: idtinit(); ! 1179: CHIRP('I'); ! 1180: } ! 1181: ! 1182: typedef struct ! 1183: { ! 1184: unsigned short off_lo; ! 1185: unsigned short seg; ! 1186: unsigned short flags; ! 1187: unsigned short off_hi; ! 1188: } IDT; ! 1189: ! 1190: /* ! 1191: * ldtinit() ! 1192: * ! 1193: * Fix up descriptors which are hard to create properly at compile/link time. ! 1194: * Apply to idt and ldt. ! 1195: * ! 1196: * Swap 16-bit words at descriptor+2, descriptor+6. ! 1197: */ ! 1198: void ! 1199: idtinit() ! 1200: { ! 1201: extern IDT idt[], idtend[]; ! 1202: extern IDT ldt[], ldtend[]; ! 1203: extern IDT gdtFixBegin[], gdtFixEnd[]; ! 1204: ! 1205: register IDT *ip; ! 1206: register unsigned short tmp; ! 1207: ! 1208: for (ip = idt; ip < idtend; ip++) { ! 1209: tmp = ip->off_hi; ! 1210: ip->off_hi = ip->seg; ! 1211: ip->seg = tmp; ! 1212: } ! 1213: ! 1214: for (ip = ldt; ip < ldtend; ip++) { ! 1215: tmp = ip->off_hi; ! 1216: ip->off_hi = ip->seg; ! 1217: ip->seg = tmp; ! 1218: } ! 1219: ! 1220: for (ip = gdtFixBegin; ip < gdtFixEnd; ip++) { ! 1221: tmp = ip->off_hi; ! 1222: ip->off_hi = ip->seg; ! 1223: ip->seg = tmp; ! 1224: } ! 1225: } ! 1226: ! 1227: void ! 1228: init_phy_seg(ptable1_v, addr, base) ! 1229: long *ptable1_v; ! 1230: { ! 1231: register int i; ! 1232: ! 1233: for (i=0; i<btoc(0x10000); i++) { ! 1234: ptable1_v[addr+i] = base | SEG_SRW; ! 1235: base += NBPC; ! 1236: } ! 1237: } ! 1238: ! 1239: /* ! 1240: * Load up segmentation registers. ! 1241: */ ! 1242: SR ugmtab[NUSEG]; ! 1243: ! 1244: void ! 1245: segload() ! 1246: { ! 1247: register int i; ! 1248: register SR *start; ! 1249: ! 1250: /* ! 1251: * 1. unprogram the currently active UGM user segments ! 1252: * reset ugmtab ! 1253: */ ! 1254: for (start = &ugmtab[1]; start < &ugmtab[NUSEG]; start++) { ! 1255: if (start->sr_segp) ! 1256: unload(start); ! 1257: start->sr_segp = 0; ! 1258: } ! 1259: ! 1260: /* ! 1261: * 2. Load each segment in the p->p_region list into the MMU ! 1262: * Remember values in ugmtab. ! 1263: */ ! 1264: start = &ugmtab[1]; ! 1265: for (i = 1; i < NUSEG; i++) { ! 1266: if (u.u_segl[i].sr_segp) { ! 1267: *start = u.u_segl[i]; ! 1268: switch (i) { ! 1269: case SIPDATA: ! 1270: if (u.u_segl[SISTACK].sr_base) ! 1271: start->sr_size = min(start->sr_size, ! 1272: (long)u.u_segl[SISTACK].sr_base- ! 1273: u.u_segl[SISTACK].sr_size); ! 1274: break; ! 1275: case SISTACK: ! 1276: start->sr_base -= start->sr_size; ! 1277: break; ! 1278: } ! 1279: ! 1280: start->sr_segp = 0; ! 1281: if (SELF->p_segp[i]) { ! 1282: start->sr_segp = SELF->p_segp[i]; ! 1283: doload(start); ! 1284: } ! 1285: start++; ! 1286: } ! 1287: } ! 1288: ! 1289: /* 3. Update shm segment information. */ ! 1290: shmLoad(); ! 1291: } ! 1292: ! 1293: SR * ! 1294: loaded(pp) ! 1295: register cseg_t *pp; ! 1296: { ! 1297: register SR *start; ! 1298: ! 1299: for (start = ugmtab; start < ugmtab + NUSEG; start++) { ! 1300: if (start->sr_segp && start->sr_segp->s_vmem == pp) { ! 1301: return start; ! 1302: } ! 1303: } ! 1304: return 0; ! 1305: } ! 1306: ! 1307: MAKESR(r0stk, _r0stk); ! 1308: extern int tss_sp0; ! 1309: ! 1310: /* ! 1311: * General initialization ! 1312: */ ! 1313: void ! 1314: i8086() ! 1315: { ! 1316: unsigned csize, isize, ssize, allsize; ! 1317: caddr_t base; ! 1318: unsigned int calc_mem, boost; ! 1319: ! 1320: /* This is the first C code executed after paging is turned on. */ ! 1321: ! 1322: workPoolInit(); ! 1323: ! 1324: /* ! 1325: * Allocate contiguous physical memory if PHYS_MEM is patched ! 1326: * to a nonzero value. ! 1327: */ ! 1328: if (PHYS_MEM) { ! 1329: physMem.sr_size = (PHYS_MEM+NBPC-1)&~(NBPC-1); ! 1330: valloc(&physMem); ! 1331: physMemInit(); ! 1332: } ! 1333: ! 1334: /* ! 1335: * Allocate a click for ring 0 stack. ! 1336: */ ! 1337: r0stk.sr_size = NBPC; ! 1338: valloc(&r0stk); ! 1339: tss_sp0 = r0stk.sr_base + NBPC; ! 1340: ! 1341: /* ! 1342: * calc_mem is used for autosizing buffer cache and kalloc pool. ! 1343: * It is total_mem, limited below by 1 meg and above by 12 meg. ! 1344: * The upper limit is a temporary move to allow booting on 16 Meg ! 1345: * systems. ! 1346: * ! 1347: * "boost" is used in autosizing buffer cache and kalloc pool. ! 1348: * It is the number of megabytes of calc_mem above 1 meg, i.e., ! 1349: * a number between 0 and 11. ! 1350: */ ! 1351: if (total_mem < ONE_MEG) ! 1352: calc_mem = ONE_MEG; ! 1353: else if (total_mem > 12 * ONE_MEG) ! 1354: calc_mem = 12 * ONE_MEG; ! 1355: else ! 1356: calc_mem = total_mem; ! 1357: ! 1358: boost = (calc_mem - ONE_MEG) / ONE_MEG; ! 1359: ! 1360: /* ! 1361: * If the number of cache buffers was not explicitly set (i.e., !0) ! 1362: * then calculate the number of buffers using the simple heuristic: ! 1363: * 128 minimum + 400 per MB of available RAM (i.e., after 1MB) ! 1364: */ ! 1365: if (NBUF == 0) ! 1366: NBUF = 128 + (400 * boost); ! 1367: ! 1368: /* ! 1369: * If the amount of kalloc() space was not explicitly set (i.e., !0) ! 1370: * then calculate using the simple heuristic: ! 1371: * 64k minimum + 32k per MB of available RAM (i.e., after 1MB) ! 1372: */ ! 1373: if (ALLSIZE == 0) ! 1374: ALLSIZE = 65536 + (32768 * boost); ! 1375: ! 1376: blockp.sr_size = NBUF*BSIZE; ! 1377: valloc(&blockp); ! 1378: ! 1379: allocp.sr_size= allsize = NBUF*sizeof(BUF) + ALLSIZE; ! 1380: #if USE_SLOT ! 1381: allocp.sr_size += ssize = NSLOT * (sizeof(int) + slotsz); ! 1382: #else ! 1383: ssize = 0; ! 1384: #endif ! 1385: allocp.sr_size += isize = NINODE* sizeof(INODE); ! 1386: allocp.sr_size += csize = NCLIST* sizeof(CLIST); ! 1387: valloc(&allocp); ! 1388: base = allocp.sr_base; ! 1389: allkp = setarena(base, allsize); ! 1390: base += allsize; ! 1391: #if USE_SLOT ! 1392: slotp = (int *)base; ! 1393: base += ssize; ! 1394: #endif ! 1395: inodep = (INODE*) base; ! 1396: base += isize; ! 1397: clistp = (paddr_t)base; ! 1398: } ! 1399: ! 1400: /* ! 1401: * Allocate srp->sr_size bytes of physical memory, and map it into ! 1402: * virtual memory space. At the end, the struct at srp will describe ! 1403: * the new segment. ! 1404: */ ! 1405: void ! 1406: valloc(srp) ! 1407: SR *srp; ! 1408: { ! 1409: register int npage; ! 1410: ! 1411: /* ! 1412: * If we've run out of virtual memory space, panic(). ! 1413: * ! 1414: * A more graceful solution is needed, but valloc() does ! 1415: * not provide a return value. ! 1416: */ ! 1417: if (sysmem.vaddre + srp->sr_size > MAX_VADDR) { ! 1418: panic("valloc: out of virtual memory space"); ! 1419: } ! 1420: ! 1421: npage = btoc(srp->sr_size); ! 1422: ! 1423: srp->sr_base = sysmem.vaddre; ! 1424: srp->sr_segp->s_size = srp->sr_size; ! 1425: srp->sr_segp->s_vmem = c_alloc(npage); ! 1426: srp->sr_segp->s_flags = SFSYST|SFCORE; ! 1427: doload(srp); ! 1428: ! 1429: sysmem.vaddre += ctob(npage); ! 1430: } ! 1431: ! 1432: /* ! 1433: * See if the given process may fit in core. ! 1434: */ ! 1435: int ! 1436: testcore(pp) ! 1437: register PROC *pp; ! 1438: { ! 1439: return 1; ! 1440: } ! 1441: ! 1442: /* ! 1443: * Calculate segmentation for a ! 1444: * new program. If there is a stack segment ! 1445: * present merge it into the data segment and ! 1446: * relocate the argument list. ! 1447: * Make sure that the changes are reflected in the u.u_segl array ! 1448: * which sproto sets up. ! 1449: */ ! 1450: int ! 1451: mproto() ! 1452: { ! 1453: return 1; ! 1454: } ! 1455: ! 1456: int ! 1457: accdata(base, count) ! 1458: unsigned base, count; ! 1459: { ! 1460: SR *srp; ! 1461: ! 1462: srp = &u.u_segl[SIPDATA]; ! 1463: return base>=srp->sr_base && base+count <= srp->sr_base+srp->sr_size; ! 1464: } ! 1465: ! 1466: int ! 1467: accstack(base, count) ! 1468: unsigned base; ! 1469: { ! 1470: SR *srp; ! 1471: ! 1472: srp = &u.u_segl[SISTACK]; ! 1473: return base>=srp->sr_base-srp->sr_size && base+count<=srp->sr_base; ! 1474: } ! 1475: ! 1476: int ! 1477: acctext(base, count) ! 1478: unsigned base; ! 1479: { ! 1480: SR *srp; ! 1481: ! 1482: srp = &u.u_segl[SISTEXT]; ! 1483: return base>=srp->sr_base && base+count <= srp->sr_base+srp->sr_size; ! 1484: } ! 1485: ! 1486: printhex(v, max) ! 1487: unsigned long v; ! 1488: { ! 1489: register int i; ! 1490: ! 1491: for (i = max-1; i>=0; --i) ! 1492: putchar(digtab[(v >> (i*4)) & 0xF]); ! 1493: } ! 1494: ! 1495: /* Read a 16 byte number from the CMOS. */ ! 1496: unsigned int ! 1497: read16_cmos(addr) ! 1498: unsigned int addr; ! 1499: { ! 1500: unsigned char read_cmos(); ! 1501: ! 1502: return((read_cmos(addr+1)<<8) + read_cmos(addr)); ! 1503: } /* read16_cmos() */ ! 1504: ! 1505: int ! 1506: c_grow(sp, new_bytes) ! 1507: SEG *sp; ! 1508: int new_bytes; ! 1509: { ! 1510: register int i; ! 1511: register cseg_t *pp; ! 1512: int new_clicks, pno, nsize, old_clicks; ! 1513: SR *srp; ! 1514: ! 1515: T_PIGGY(0x8000000, printf("c_grow(sp: %x, new: %x)", sp, new_bytes);); ! 1516: ! 1517: new_clicks = btoc(new_bytes); ! 1518: old_clicks = btoc(sp->s_size); ! 1519: ! 1520: if (new_clicks == old_clicks) { ! 1521: goto ok_c_grow; ! 1522: } ! 1523: ! 1524: if (new_clicks < old_clicks) { ! 1525: printf("%s:can't contract segment\n",u.u_comm); ! 1526: goto no_c_grow; ! 1527: } ! 1528: ! 1529: if (new_clicks - old_clicks > allocno()) { ! 1530: goto no_c_grow; ! 1531: } ! 1532: ! 1533: T_PIGGY(0x8000000, printf("nc: %x, oc: %x,",new_clicks,old_clicks);); ! 1534: ! 1535: /* ! 1536: * Allocate a new descriptor vector if necessary. ! 1537: * pp is the element corresponding to the virtual address ! 1538: * "0"(sr_base) ! 1539: */ ! 1540: pp = sp->s_vmem; ! 1541: nsize = areasize(new_clicks); ! 1542: if (nsize != areasize(old_clicks) ! 1543: && !(pp = (cseg_t*)arealloc(new_clicks))) { ! 1544: T_PIGGY(0x8000000, ! 1545: printf("Can not allocate new descriptor.");); ! 1546: goto no_c_grow; ! 1547: } ! 1548: ! 1549: T_PIGGY(0x8000000, printf("new pp: %x", pp);); ! 1550: ! 1551: if (0 != (srp = loaded(sp->s_vmem))) { ! 1552: T_PIGGY(0x8000000, printf("unloading srp: %x, ", srp);); ! 1553: unload(srp); ! 1554: srp->sr_segp = 0; ! 1555: } ! 1556: ! 1557: /* ! 1558: * Allocate new descriptors. ! 1559: */ ! 1560: T_PIGGY(0x8000000, printf("new desc: [");); ! 1561: for (i = old_clicks; i < new_clicks; i++) { ! 1562: pno = *--sysmem.pfree; ! 1563: pp[i] = clickseg(pno) | SEG_RW; ! 1564: T_PIGGY(0x8000000, printf("%x, ", pp[i]);); ! 1565: } ! 1566: T_PIGGY(0x8000000, printf("]");); ! 1567: ! 1568: /* ! 1569: * Copy unchanged descriptors and free old vector if necessary. ! 1570: */ ! 1571: if (pp != sp->s_vmem) { ! 1572: T_PIGGY(0x8000000, printf("old desc: [");); ! 1573: for (i = 0; i < old_clicks; i++) { ! 1574: pp[i] = sp->s_vmem[i]; ! 1575: T_PIGGY(0x8000000, printf("%x, ", pp[i]);); ! 1576: } ! 1577: T_PIGGY(0x8000000, printf("]");); ! 1578: areafree((BLOCKLIST*)sp->s_vmem, old_clicks); ! 1579: } ! 1580: ! 1581: sp->s_vmem = pp; ! 1582: ! 1583: /* ! 1584: * clear the added clicks ! 1585: * ! 1586: * MAPIO macro - convert array of page descriptors, offset ! 1587: * into system global address. ! 1588: */ ! 1589: T_PIGGY(0x8000000, printf("dmaclear(%x, %x, 0)", ! 1590: ctob(new_clicks - old_clicks), ! 1591: MAPIO(sp->s_vmem, ctob(old_clicks)) ! 1592: ); ! 1593: ); /* T_PIGGY() */ ! 1594: ! 1595: dmaclear(ctob(new_clicks - old_clicks), ! 1596: MAPIO(sp->s_vmem, ctob(old_clicks)), 0); ! 1597: ! 1598: ok_c_grow: ! 1599: return 0; ! 1600: ! 1601: no_c_grow: ! 1602: return -1; ! 1603: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.