|
|
1.1 root 1: /* $Header: /src386/kernel/coh.386/RCS/seg.c,v 1.6 93/06/14 13:35:09 bin Exp Locker: bin $ */
2: /* (lgl-
3: * The information contained herein is a trade secret of Mark Williams
4: * Company, and is confidential information. It is provided under a
5: * license agreement, and may be copied or disclosed only under the
6: * terms of that agreement. Any reproduction or disclosure of this
7: * material without the express written authorization of Mark Williams
8: * Company or persuant to the license agreement is unlawful.
9: *
10: * COHERENT Version 2.3.37
11: * Copyright (c) 1982, 1983, 1984.
12: * An unpublished work by Mark Williams Company, Chicago.
13: * All rights reserved.
14: -lgl) */
15: /*
16: * Coherent.
17: * Segment manipulation.
18: *
19: */
20: #include <sys/coherent.h>
21: #include <sys/buf.h>
22: #include <errno.h>
23: #include <sys/ino.h>
24: #include <sys/inode.h>
25: #include <sys/proc.h>
26: #include <sys/sched.h>
27: #include <sys/seg.h>
28: #include <a.out.h>
29:
30:
31: #define min(a, b) ((a) < (b) ? (a) : (b))
32:
33: /*
34: * Initialisation code.
35: */
36: seginit()
37: {
38: /*
39: * Create empty circular-list of memory segments.
40: */
41: segmq.s_forw = &segmq;
42: segmq.s_back = &segmq;
43:
44: /*
45: * Create empty circular-list of disk segments.
46: */
47: segdq.s_forw = &segdq;
48: segdq.s_back = &segdq;
49: }
50:
51: /*
52: * Given an inode, `ip', and flags, `ff', describing a segment associated
53: * with the inode, see if the segment already exists and if so, return a
54: * copy. If the segment does not exist, allocate the segment having size
55: * `ss', and read the segment using the inode at seek offset `dq' with a
56: * size of `ds'.
57: */
58: SEG *
59: ssalloc(ip, ff, ss)
60: register INODE *ip;
61: {
62: register SEG *sp;
63: register int f;
64:
65: lock(seglink);
66: f = ff & (SFSHRX|SFTEXT);
67:
68: /*
69: * Look for the segment in the memory queue.
70: */
71: for (sp=segmq.s_forw; sp!=&segmq; sp=sp->s_forw) {
72: if (sp->s_ip==ip && (sp->s_flags&(SFSHRX|SFTEXT))==f) {
73: unlock(seglink);
74: if (sp = segdupl(sp))
75: segfinm(sp);
76: return (sp);
77: }
78: }
79:
80: /*
81: * Look for the segment on the disk queue.
82: */
83: for (sp=segdq.s_forw; sp!=&segdq; sp=sp->s_forw) {
84: if (sp->s_ip==ip && (sp->s_flags&(SFSHRX|SFTEXT))==f) {
85: unlock(seglink);
86: if (sp = segdupl(sp))
87: segfinm(sp);
88: return (sp);
89: }
90: }
91: unlock(seglink);
92:
93: /*
94: * Allocate and create the segment.
95: */
96: return salloc(roundu(ss, NBPC), ff);
97: }
98:
99: /*
100: * Given a pointer to a newly created process, copy all of our segments
101: * into the given process.
102: *
103: * Return nonzero if successful.
104: */
105: int
106: segadup(cpp)
107: register PROC *cpp;
108: {
109: register SEG *sp;
110: register int n;
111: register PROC *pp;
112:
113: pp = SELF;
114: cpp->p_flags |= PFSWIO;
115: for (n=0; n<NUSEG; n++) {
116: if ((sp=pp->p_segp[n]) == NULL)
117: continue;
118: if ((sp=segdupl(sp)) == NULL)
119: break;
120: cpp->p_segp[n] = sp;
121: if ((sp->s_flags&SFCORE) == 0)
122: cpp->p_flags &= ~PFCORE;
123: }
124:
125: /*
126: * One of the calls to segdupl() failed.
127: * Undo any that succeeded.
128: */
129: if (n < NUSEG) {
130: while (n > 0) {
131: if (sp=cpp->p_segp[--n]) {
132: cpp->p_segp[n] = NULL;
133: sfree(sp);
134: }
135: }
136: }
137: cpp->p_flags &= ~PFSWIO;
138: return n;
139: }
140:
141: /*
142: * Duplicate a segment.
143: */
144: SEG *
145: segdupl(sp)
146: register SEG *sp;
147: {
148: register SEG *sp1;
149:
150: if (sp->s_flags & SFSHRX) {
151: sp->s_urefc++;
152: sp->s_lrefc++;
153: return (sp);
154: }
155: if ((sp->s_flags&SFCORE) == 0)
156: panic("Cannot duplicate non shared swapped segment");
157: if ((sp1=salloc(sp->s_size, sp->s_flags|SFNSWP|SFNCLR)) == NULL)
158: sp1 = segdupd(sp);
159: else {
160: sp1->s_flags = sp->s_flags;
161: dmacopy( btoc(sp->s_size), sp->s_vmem, sp1->s_vmem) ;
162: }
163: return sp1;
164: }
165:
166: /*
167: * Allocate a segment `bytes_wanted' bytes long.
168: * `flags' contains some pseudo flags.
169: */
170: SEG *
171: salloc(bytes_wanted, flags)
172: int bytes_wanted, flags;
173: {
174: register SEG *sp;
175: register int r;
176:
177: r = (flags & (SFSYST|SFTEXT|SFSHRX|SFDOWN)) | SFCORE;
178:
179: /*
180: #ifdef _I386
181: bytes_wanted += (sizeof(char *) - 1);
182: bytes_wanted &= ~(sizeof(char *) - 1);
183: #else
184: bytes_wanted += (BSIZE - 1);
185: bytes_wanted &= ~(BSIZE - 1);
186: #endif
187: */
188:
189: lock(seglink);
190: sp = smalloc(bytes_wanted);
191: unlock(seglink);
192:
193: if (sp) {
194: sp->s_flags = r;
195: } else {
196: #if 0
197: /* no room now - let the swapper try to grow it */
198: if (flags & SFNSWP)
199: return 0;
200: if ((sp=kalloc(sizeof(SEG))) == NULL)
201: return 0;
202: sp->s_forw = sp;
203: sp->s_back = sp;
204: sp->s_flags = r;
205: sp->s_urefc = 1;
206: sp->s_lrefc = 1;
207: if (segsext(sp, bytes_wanted) == NULL) {
208: kfree(sp);
209: return 0;
210: }
211: #else
212: return 0;
213: #endif
214: }
215: if ((flags&SFNCLR) == 0)
216: dmaclear(sp->s_size, MAPIO(sp->s_vmem, 0), 0L);
217: return sp;
218: }
219:
220: /*
221: * Free the given segment pointer.
222: */
223: sfree(sp)
224: register SEG *sp;
225: {
226: register INODE *ip;
227:
228: if ( sp->s_urefc != 1 ) {
229: sp->s_urefc--;
230: sp->s_lrefc--;
231: return;
232: }
233:
234: lock(seglink);
235:
236: --sp->s_lrefc;
237:
238: sp->s_back->s_forw = sp->s_forw;
239: sp->s_forw->s_back = sp->s_back;
240:
241: c_free(sp->s_vmem, btoc(sp->s_size));
242:
243: unlock(seglink);
244: if (sp->s_lrefc)
245: panic("Bad segment count");
246:
247: /*
248: * Check if inode is ilocked, in order to allow the process
249: * to exec itself (file with the same inode as parent). Vlad.
250: */
251: if ((ip=sp->s_ip) && !ilocked(ip)) {
252: ldetach(ip);
253: }
254: kfree(sp);
255: }
256:
257: /*
258: * Grow or shrink the segment `sp' so that it has size `new_bytes' bytes.
259: *
260: * downward growing segments not done yet!
261: */
262: seggrow(sp, new_bytes)
263: register SEG *sp;
264: unsigned int new_bytes;
265: {
266: register SEG *sp1;
267: register int dowflag;
268: unsigned int old_bytes, common_clicks;
269:
270: dowflag = sp->s_flags & SFDOWN;
271: old_bytes = sp->s_size;
272:
273: /*
274: * If we want a larger segment AND c_grow() succeeds
275: * boost segment size to new_bytes
276: */
277: if (new_bytes >= old_bytes && c_grow(sp, new_bytes)==0) {
278: T_HAL(0x100, printf("c_grow(%d) ", new_bytes));
279: sp->s_size = new_bytes;
280: dmaclear(new_bytes - old_bytes,
281: MAPIO(sp->s_vmem, old_bytes), 0);
282: return 1;
283: }
284: dont_c_grow:
285:
286: if (sp1 = salloc(new_bytes, (sp->s_flags|SFNSWP|SFNCLR))) {
287: T_HAL(0x100, printf("salloc(%d) ", new_bytes));
288: if (dowflag == 0) {
289: common_clicks = btoc(min(new_bytes, old_bytes));
290: dmacopy(common_clicks, sp->s_vmem, sp1->s_vmem);
291: if (new_bytes > old_bytes) {
292: dmaclear(new_bytes - old_bytes,
293: MAPIO(sp1->s_vmem, old_bytes), 0);
294: }
295: } else
296: panic("downflag");
297: lock(seglink);
298: c_free(sp->s_vmem, btoc(old_bytes));
299: satcopy(sp, sp1);
300: unlock(seglink);
301:
302: return 1;
303: }
304:
305: #if 1
306: return 0;
307: #else
308: /*
309: * Last chance. Extend the segment by swapping it.
310: */
311: if (!segsext(sp, new_bytes))
312: return 0;
313:
314: if (dowflag == 0) {
315: if (new_bytes > old_bytes)
316: dmaclear(new_bytes - old_bytes, MAPIO(sp->s_vmem,old_bytes), 0);
317: } else
318: panic("downflag");
319:
320: return (1);
321: #endif
322: }
323:
324: /*
325: * Given a segment pointer, `sp' and a segment size, grow the given segment
326: * to the given size.
327: */
328: segsize(sp, s2)
329: register SEG *sp;
330: caddr_t s2;
331: {
332: register caddr_t s1;
333:
334: s1 = (caddr_t) sp->s_size;
335: if (s2 == 0 || seggrow(sp, (off_t)s2) == 0) {
336: SET_U_ERROR( ENOMEM, "can not grow segment" );
337: return;
338: }
339: if (sproto(0) == 0) {
340: if (seggrow(sp, (off_t)s1)==0 || sproto(0)==0) {
341: T_PIGGY( 0x2000000, printf("auto SEGV\n"); );
342: sendsig(SIGSEGV, SELF);
343: }
344: }
345: segload();
346: }
347:
348: /*
349: * Grow the segment `sp1' to the size `s' in bytes by swapping it out
350: * and back in. The segment may not be locked.
351: */
352: SEG *
353: segsext(sp1, s)
354: register SEG *sp1;
355: register off_t s;
356: {
357: #if 0
358: register SEG *sp2;
359:
360: #if MONITOR
361: if (swmflag)
362: printf("Segsext(%p, %u)\n", SELF, SELF->p_pid);
363: #endif
364: if (sexflag == 0) {
365: SET_U_ERROR( ENOMEM, "can not extend, swapping is off" );
366: return (NULL);
367: }
368: lock(seglink);
369: if ((sp2=sdalloc(s)) == NULL) {
370: unlock(seglink);
371: return (NULL);
372: }
373: unlock(seglink);
374: sp1->s_lrefc++;
375: if (sp1->s_size != 0)
376: swapio(1, MAPIO(sp1->s_vmem, 0), sp2->s_daddr, sp1->s_size);
377: lock(seglink);
378: satcopy(sp1, sp2);
379: unlock(seglink);
380: sp1->s_flags &= ~SFCORE;
381: sp1->s_lrefc--;
382: segfinm(sp1);
383: return (sp1);
384: #else
385: return 0;
386: #endif
387: }
388:
389: /*
390: * Force the given segment to be in memory. One can only force
391: * one segment to be in memory at a time.
392: */
393: segfinm(sp)
394: register SEG *sp;
395: {
396: register PROC *pp;
397: register int s;
398:
399: if (sp->s_flags&SFCORE)
400: return;
401: pp = SELF;
402: sp->s_urefc++;
403: sp->s_lrefc++;
404: pp->p_segp[SIAUXIL] = sp;
405: pp->p_flags &= ~PFCORE;
406: #ifndef QWAKEUP
407: s = sphi();
408: #endif
409: setrun(pp);
410: dispatch();
411: #ifndef QWAKEUP
412: spl(s);
413: #endif
414: pp->p_segp[SIAUXIL] = NULL;
415: sfree(sp);
416: }
417:
418: /*
419: * Make a copy of the segment `sp1' which is in memory by writing
420: * it out to disk.
421: */
422: SEG *
423: segdupd(sp1)
424: register SEG *sp1;
425: {
426: register SEG *sp2;
427:
428: if (sexflag == 0)
429: return (NULL);
430: lock(seglink);
431: if ((sp2=sdalloc(sp1->s_size)) == NULL) {
432: unlock(seglink);
433: return (NULL);
434: }
435: sp1->s_lrefc++;
436: unlock(seglink);
437: swapio(1, MAPIO(sp1->s_vmem, 0), sp2->s_daddr, sp1->s_size);
438: sp1->s_lrefc--;
439: sp2->s_flags = sp1->s_flags & ~SFCORE;
440: sp2->s_size = sp1->s_size;
441: return (sp2);
442: }
443:
444: /*
445: * Given a flag, a physical core address, a disk address and a count in
446: * bytes, perform an I/O operation between core and disk. If `flag' is
447: * set, the transfer is to the disk otherwise it is to memory. As you may
448: * have guessed, this is used by the swapper.
449: *
450: */
451: swapio(f, p, d, n)
452: paddr_t p;
453: daddr_t d;
454: off_t n;
455: {
456: register BUF * bp;
457: register SEG * sp;
458: register int s;
459: register int nb;
460:
461: #if MONITOR
462: if (swmflag > 1)
463: printf("swapio(%s,%x,%x,%x)\n",f?"out":"in",(int)p,(int)d,n);
464: #endif
465: if (d < swapbot || d+(n/BSIZE) > swaptop)
466: panic("Swapio bad parameter");
467:
468: bp = &swapbuf;
469: lock(bp->b_gate);
470: SELF->p_flags |= PFSWIO;
471: bp->b_paddr = p;
472:
473: while (n) {
474: nb = (n > SCHUNK) ? SCHUNK : n;
475: /*
476: * Prevent I/O transfer from crossing 64 Kbyte boundary.
477: */
478: if ( (p & 0xFFFF0000L) != ((p+nb) & 0xFFFF0000L) )
479: nb = 0x10000L - (p & 0x0000FFFFL);
480: bp->b_flag = BFNTP;
481: bp->b_req = f ? BWRITE : BREAD;
482: bp->b_dev = swapdev;
483: bp->b_bno = d;
484: bp->b_paddr = p;
485: bp->b_count = nb;
486: s = sphi();
487: dblock(swapdev, bp);
488: while ((bp->b_flag&BFNTP) != 0) {
489: x_sleep((char *)bp, pridisk, slpriNoSig, "swap");
490: /* Sleeping in the swapper. */
491: }
492: spl(s);
493: if ((bp->b_flag&BFERR) != 0)
494: panic("Swapio error");
495: bp->b_vaddr += nb;
496: p += nb;
497: d += nb / BSIZE;
498: n -= nb;
499: }
500: unlock(bp->b_gate);
501: SELF->p_flags &= ~PFSWIO;
502: }
503:
504: /*
505: * Make the segment descriptor pointed to by `sp1' have the attributes
506: * of `sp2' including it's position in the segment queue and release
507: * `sp2'. `seglink' must be locked when this routine is called.
508: */
509: satcopy(sp1, sp2)
510: register SEG *sp1;
511: register SEG *sp2;
512: {
513: sp1->s_back->s_forw = sp1->s_forw;
514: sp1->s_forw->s_back = sp1->s_back;
515: sp2->s_back->s_forw = sp1;
516: sp1->s_back = sp2->s_back;
517: sp2->s_forw->s_back = sp1;
518: sp1->s_forw = sp2->s_forw;
519: sp1->s_daddr = sp2->s_daddr;
520: sp1->s_size = sp2->s_size;
521: sp1->s_vmem = sp2->s_vmem;
522: kfree(sp2);
523: }
524:
525: /*
526: * Allocate a segment on disk that is `n' bytes long.
527: * The `seglink' gate should be locked before this routine is called.
528: */
529: SEG *
530: sdalloc( s )
531: off_t s;
532: {
533: register SEG *sp1;
534: register SEG *sp2;
535: register daddr_t d;
536: register daddr_t d1;
537: register daddr_t d2;
538:
539: d = s / BSIZE;
540: d1 = swapbot;
541: sp1 = &segdq;
542: do {
543: if (d1 >= swaptop)
544: return (NULL);
545: if ((sp1=sp1->s_forw) != &segdq)
546: d2 = sp1->s_daddr;
547: else
548: d2 = swaptop;
549: if (d2-d1 >= d) {
550: if ((sp2=kalloc(sizeof(SEG))) == NULL)
551: return (NULL);
552: sp1->s_back->s_forw = sp2;
553: sp2->s_back = sp1->s_back;
554: sp1->s_back = sp2;
555: sp2->s_forw = sp1;
556: sp2->s_urefc = 1;
557: sp2->s_lrefc = 1;
558: sp2->s_size = s;
559: sp2->s_daddr = d1;
560: return (sp2);
561: }
562: d1 = sp1->s_daddr + (sp1->s_size / BSIZE);
563: } while (sp1 != &segdq);
564: return (NULL);
565: }
566:
567: /*
568: * Allocate a segment in memory that is `bytes_wanted' bytes long.
569: * The `seglink' gate should be locked before this routine is called.
570: *
571: * if successful, return allocated SEG *
572: * else, return 0
573: */
574: SEG *
575: smalloc(bytes_wanted)
576: off_t bytes_wanted;
577: {
578: register SEG *sp1;
579: register SEG *new_seg;
580: unsigned clicks_wanted;
581:
582: clicks_wanted = btoc(bytes_wanted);
583:
584: /*
585: * Estimate space needed for new segment and its overhead.
586: * Fail if not enough free RAM available.
587: */
588: if (countsize(clicks_wanted) > allocno())
589: return 0;
590: /*
591: * Allocate a new SEG struct to keep track of the segment, if possible.
592: */
593: if ((new_seg = kalloc(sizeof (SEG))) == NULL)
594: return 0;
595:
596: if ((new_seg->s_vmem = c_alloc(clicks_wanted)) == 0) {
597: kfree(new_seg);
598: return 0;
599: }
600:
601: /* link new_seg in at start of segmq */
602: sp1 = segmq.s_forw;
603: sp1->s_back->s_forw = new_seg;
604: new_seg->s_back = sp1->s_back;
605: sp1->s_back = new_seg;
606: new_seg->s_forw = sp1;
607:
608: new_seg->s_urefc = 1;
609: new_seg->s_lrefc = 1;
610: new_seg->s_size = bytes_wanted;
611:
612: return new_seg;
613: }
614:
615: /*
616: * Set up `SR' structure in user area from segments descriptors in
617: * process structure. Also set up the user segmentation registers.
618: */
619: sproto(xhp)
620: struct xechdr *xhp;
621: {
622: register int n;
623: register SEG *sp;
624:
625: for (n=0; n<NUSEG; n++) {
626: u.u_segl[n].sr_flag = u.u_segl[n].sr_size = 0;
627: u.u_segl[n].sr_segp = 0;
628: if ((sp=SELF->p_segp[n]) == NULL)
629: continue;
630: if (n == SIUSERP)
631: u.u_segl[n].sr_base = &u;
632: else {
633: if (xhp)
634: u.u_segl[n].sr_base = xhp->segs[n].mbase;
635: u.u_segl[n].sr_flag |= SRFPMAP;
636: }
637: if (n!=SISTEXT)
638: u.u_segl[n].sr_flag |= SRFDUMP;
639: if (n!=SIUSERP && n!=SISTEXT)
640: u.u_segl[n].sr_flag |= SRFDATA;
641: u.u_segl[n].sr_size = sp->s_size;
642: u.u_segl[n].sr_segp = sp;
643: }
644: return (mproto());
645: }
646:
647: /*
648: * Search for a busy text inode.
649: */
650: sbusy(ip)
651: register INODE *ip;
652: {
653: register SEG *sp;
654:
655: lock(seglink);
656: /*
657: * Look for the segment in the memory queue.
658: */
659: for (sp=segmq.s_forw; sp!=&segmq; sp=sp->s_forw) {
660: if (sp->s_ip==ip
661: && (sp->s_flags&(SFSHRX|SFTEXT))==(SFSHRX|SFTEXT)) {
662: unlock(seglink);
663: return (1);
664: }
665: }
666:
667: /*
668: * Look for the segment on the disk queue.
669: */
670: for (sp=segdq.s_forw; sp!=&segdq; sp=sp->s_forw) {
671: if (sp->s_ip==ip
672: && (sp->s_flags&(SFSHRX|SFTEXT))==(SFSHRX|SFTEXT)) {
673: unlock(seglink);
674: return (1);
675: }
676: }
677: unlock(seglink);
678: return 0;
679: }
680:
681: /*
682: * Segment consistency checks for the paranoid.
683: segchk()
684: {
685: register SEG *sp;
686: register int nbad;
687: off_t s;
688: daddr_t d;
689:
690: nbad = 0;
691: sp = &segdq;
692: d = swapbot;
693: while ((sp=sp->s_forw) != &segdq) {
694: if (sp->s_daddr < d)
695: nbad += badseg("disk", (int)sp->s_daddr, 0);
696: d = sp->s_daddr + (sp->s_size / BSIZE);
697: }
698: if (swaptop < d)
699: nbad += badseg("disk", sp->s_back->s_daddr, sp->s_back->s_size);
700: }
701:
702: badseg(t, b, s)
703: char *t;
704: daddr_t b;
705: off_t s;
706: {
707: printf( "Bad %s segment at %X of len %X\n", t, b, s );
708: return (1);
709: }
710: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.