|
|
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.