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