|
|
1.1 root 1: /*
2:
1.1.1.3 root 3: Copyright 1990,1991,1992 Eric R. Smith.
4:
5: Copyright 1992,1993 Atari Corporation.
6:
7: All rights reserved.
1.1 root 8:
9: */
10:
11:
12:
13: /*
14:
15: * mem.c:: routines for managing memory regions
16:
17: */
18:
19:
20:
21: #include "mint.h"
22:
1.1.1.3 root 23: #include "fasttext.h" /* for line A stuff */
24:
25:
26:
27: #ifndef VgetSize
28:
29: extern long xbios();
30:
31: #define VgetSize(mode) xbios(91, (short)(mode))
32:
33: #define Vsetmode(mode) xbios(88, (short)(mode))
34:
35: #endif
36:
1.1 root 37:
38:
39: static long core_malloc P_((long, int));
40:
1.1.1.3 root 41: static void core_free P_((long));
42:
1.1 root 43:
44:
45: /* macro for testing whether a memory region is free */
46:
47: #define ISFREE(m) ((m)->links == 0)
48:
49:
50:
51: /*
52:
1.1.1.2 root 53: * list of shared text regions currently being executed
54:
55: */
56:
57: SHTEXT *text_reg = 0;
58:
59:
60:
61: /*
62:
1.1 root 63: * initialize memory routines
64:
65: */
66:
67:
68:
69: /* initial number of memory regions */
70:
71: #define NREGIONS 512
72:
73:
74:
75: /* number of new regions to allocate when the initial ones are used up */
76:
77: #define NEWREGIONS 256
78:
79:
80:
81: static MEMREGION use_regions[NREGIONS+1];
82:
83: MEMREGION *rfreelist;
84:
85:
86:
1.1.1.3 root 87: /* these variables are set in init_core(), and used in
88:
89: * init_mem()
90:
91: */
92:
93: static ulong scrnsize, scrnplace;
94:
95: static SCREEN *vscreen;
96:
97:
98:
1.1 root 99: void
100:
101: init_mem()
102:
103: {
104:
105: int i;
106:
1.1.1.3 root 107: MEMREGION *r;
108:
109: long newbase;
110:
1.1 root 111:
112:
113: use_regions[NREGIONS].next = 0;
114:
115: for (i = 0; i < NREGIONS; i++) {
116:
117: use_regions[i].next = &use_regions[i+1];
118:
119: }
120:
121: rfreelist = use_regions;
122:
123:
124:
125: init_core();
126:
127: init_swap();
128:
1.1.1.3 root 129:
130:
131: init_tables(); /* initialize MMU constants */
132:
133:
134:
135: /* mark all the regions in the core & alt lists as "invalid" */
136:
137: for (r = *core; r; r = r->next) {
138:
139: mark_region(r,PROT_I);
140:
141: }
142:
143: for (r = *alt; r; r = r->next) {
144:
145: mark_region(r,PROT_I);
146:
147: }
148:
149:
150:
151: /* make sure the screen is set up properly */
152:
153: newbase = s_realloc(scrnsize);
154:
155:
156:
157: /* if we did get a new screen, point the new screen
158:
159: * at the right place after copying the data
160:
161: * if possible, save the screen to another buffer,
162:
163: * since if the new screen and old screen overlap
164:
165: * the blit will look very ugly.
166:
167: * Note that if the screen isn't moveable, then we set
168:
169: * scrnsize to a ridiculously large value, and so the
170:
171: * s_realloc above failed.
172:
173: */
174:
175: if (newbase) {
176:
177: /* find a free region for temp storage */
178:
179: for (r = *core; r; r = r->next) {
180:
181: if (ISFREE(r) && r->len >= scrnsize)
182:
183: break;
184:
185: }
186:
187:
188:
189: if (r) {
190:
191: quickmove((char *)r->loc, (char *)scrnplace, scrnsize);
192:
193: Setscreen((void *)r->loc, (void *)r->loc, -1);
194:
195: Vsync();
196:
197: quickmove((char *)newbase, (char *)r->loc, scrnsize);
198:
199: } else {
200:
201: quickmove((char *)newbase, (char *)scrnplace, scrnsize);
202:
203: }
204:
205: Setscreen((void *)newbase, (void *)newbase, -1);
206:
207: /* fix the cursor */
208:
209: Cconws("\r\n");
210:
211: }
212:
1.1 root 213: }
214:
215:
216:
217: /*
218:
219: * init_core(): initialize the core memory map (normal ST ram) and also
220:
221: * the alternate memory map (fast ram on the TT)
222:
223: */
224:
225:
226:
227: static MEMREGION *_core_regions = 0, *_alt_regions = 0,
228:
229: *_ker_regions = 0;
230:
231:
232:
233: MMAP core = &_core_regions;
234:
235: MMAP alt = &_alt_regions;
236:
237: MMAP ker = &_ker_regions;
238:
239:
240:
241: /* note: add_region must adjust both the size and starting
242:
243: * address of the region being added so that memory is
244:
245: * always properly aligned
246:
247: */
248:
249:
250:
251: int
252:
253: add_region(map, place, size, mflags)
254:
255: MMAP map;
256:
257: ulong place, size;
258:
259: unsigned mflags; /* initial flags for region */
260:
261: {
262:
1.1.1.3 root 263: MEMREGION *m;
1.1 root 264:
1.1.1.3 root 265: ulong trimsize;
1.1 root 266:
267:
268:
1.1.1.3 root 269: TRACELOW(("add_region(map=%lx,place=%lx,size=%lx,flags=%x)",
1.1 root 270:
1.1.1.3 root 271: map,place,size,mflags));
1.1 root 272:
273:
274:
275: m = new_region();
276:
277: if (m == 0)
278:
279: return 0; /* failure */
280:
281: m->links = 0;
282:
283:
284:
1.1.1.3 root 285: if (place & MASKBITS) {
286:
287: /* increase place & shorten size by the amount we're trimming */
288:
289: trimsize = (MASKBITS+1) - (place & MASKBITS);
290:
291: if (size <= trimsize) goto lose;
292:
293: size -= trimsize;
294:
295: place += trimsize;
296:
297: }
298:
299:
300:
301: /* now trim size DOWN to a multiple of pages */
302:
303: if (size & MASKBITS) size &= ~MASKBITS;
304:
305:
306:
307: /* only add if there's anything left */
308:
309: if (size) {
310:
311: m->len = size;
1.1 root 312:
1.1.1.3 root 313: m->loc = place;
314:
315: m->next = *map;
316:
317: m->mflags = mflags;
318:
319: *map = m;
320:
321: }
322:
323: else {
1.1 root 324:
1.1.1.3 root 325: /* succeed but don't do anything; dispose of region */
326:
327: lose: dispose_region(m);
328:
329: }
1.1 root 330:
331: return 1; /* success */
332:
333: }
334:
335:
336:
337: static long
338:
339: core_malloc(amt, mode)
340:
341: long amt;
342:
343: int mode;
344:
345: {
346:
347: static int mxalloc = -1; /* does GEMDOS know about Mxalloc? */
348:
349: long ret;
350:
351:
352:
353: if (mxalloc < 0) {
354:
355: ret = (long)Mxalloc(-1L, 0);
356:
357: if (ret == -32) mxalloc = 0; /* unknown function */
358:
359: else if (ret >= 0) mxalloc = 1;
360:
361: else {
362:
363: ALERT("GEMDOS returned %ld from Mxalloc", ret);
364:
365: mxalloc = 0;
366:
367: }
368:
369: }
370:
371: if (mxalloc)
372:
1.1.1.4 ! root 373: return (long) Mxalloc(amt, mode);
1.1 root 374:
375: else if (mode == 1)
376:
377: return 0L;
378:
379: else
380:
1.1.1.4 ! root 381: return (long) Malloc(amt);
1.1 root 382:
383: }
384:
385:
386:
1.1.1.3 root 387: static void
388:
389: core_free(where)
390:
391: long where;
392:
393: {
394:
395: Mfree((void *)where);
396:
397: }
398:
399:
400:
1.1 root 401: void
402:
403: init_core()
404:
405: {
406:
1.1.1.3 root 407: extern int FalconVideo; /* set in main.c */
408:
409: int scrndone = 0;
410:
1.1 root 411: ulong size;
412:
413: ulong place;
414:
1.1.1.3 root 415: ulong temp;
416:
1.1 root 417: void *tossave;
418:
419:
420:
421: tossave = (void *)core_malloc((long)TOS_MEM, 0);
422:
423: if (!tossave) {
424:
425: FATAL("Not enough memory to run MiNT");
426:
427: }
428:
429:
430:
431: /* initialize kernel memory */
432:
433: place = (ulong)core_malloc(KERNEL_MEM, 3);
434:
435: if (place != 0) {
436:
1.1.1.3 root 437: nalloc_arena_add((void *)place,KERNEL_MEM);
438:
439: }
440:
441:
442:
443: /*
444:
445: * find out where the screen is. We want to manage the screen
446:
447: * memory along with all the other memory, so that Srealloc()
448:
449: * can be used by the XBIOS to allocate screens from the
450:
451: * end of memory -- this avoids fragmentation problems when
452:
453: * changing resolutions.
454:
455: */
456:
457: /* Note, however, that some graphics boards (e.g. Matrix)
458:
459: * are unable to change the screen address. We fake out the
460:
461: * rest of our code by pretending to have a really huge
462:
463: * screen that can't be changed.
464:
465: */
466:
467: scrnplace = (long)Physbase();
468:
469:
470:
471: vscreen = (SCREEN *)((char *)lineA0() - 346);
472:
473: if (FalconVideo) {
474:
475: /* the Falcon can tell us the screen size */
476:
477: scrnsize = VgetSize(Vsetmode(-1));
478:
479: } else {
480:
481: /* otherwise, use the line A variables */
482:
483: scrnsize = (vscreen->maxy+1)*(long)vscreen->linelen;
484:
485: }
486:
487:
488:
489: /* check for a graphics card with fixed screen location */
490:
491: #define phys_top_st (*(ulong *)0x42eL)
492:
493:
494:
495: if (scrnplace >= phys_top_st) {
496:
497: /* screen isn't in ST RAM */
498:
499: scrnsize = 0x7fffffffUL;
500:
501: scrndone = 1;
502:
503: } else {
504:
505: temp = (ulong)core_malloc(scrnsize+256L, 0);
506:
507: if (temp) {
508:
509: (void)Setscreen((void *)-1L,
510:
511: (void *)((temp+511)&(0xffffff00L)), -1);
512:
1.1.1.4 ! root 513: if ((long)Physbase() != ((temp+511)&(0xffffff00L))) {
1.1.1.3 root 514:
515: scrnsize = 0x7fffffffUL;
516:
517: scrndone = 1;
518:
519: }
520:
521: (void)Setscreen((void *)-1L, (void *)scrnplace, -1);
522:
523: core_free(temp);
524:
525: }
1.1 root 526:
527: }
528:
529:
530:
531: /* initialize ST RAM */
532:
533: size = (ulong)core_malloc(-1L, 0);
534:
535: while (size > 0) {
536:
537: place = (ulong)core_malloc(size, 0);
538:
1.1.1.3 root 539: if (place + size == scrnplace) {
540:
541: size += scrnsize;
542:
543: scrndone = 1;
544:
545: }
546:
1.1 root 547: if (!add_region(core, place, size, M_CORE))
548:
549: FATAL("init_mem: unable to add a region");
550:
551: size = (ulong)core_malloc(-1L, 0);
552:
553: }
554:
555:
556:
1.1.1.3 root 557: if (!scrndone) {
558:
559: (void)add_region(core, scrnplace, scrnsize, M_CORE);
560:
561: }
562:
563:
564:
1.1 root 565: /* initialize alternate RAM */
566:
567: size = (ulong)core_malloc(-1L, 1);
568:
569: while (size > 0) {
570:
571: place = (ulong)core_malloc(size, 1);
572:
573: if (!add_region(alt, place, size, M_ALT))
574:
575: FATAL("init_mem: unable to add a region");
576:
577: size = (ulong)core_malloc(-1L, 1);
578:
579: }
580:
581:
582:
583: (void)Mfree(tossave); /* leave some memory for TOS to use */
584:
585: }
586:
587:
588:
589: /*
590:
591: * init_swap(): initialize the swap area; for now, this does nothing
592:
593: */
594:
595:
596:
597: MEMREGION *_swap_regions = 0;
598:
599: MMAP swap = &_swap_regions;
600:
601:
602:
603: void
604:
605: init_swap()
606:
607: {
608:
609: }
610:
611:
612:
613: /*
614:
615: * routines for allocating/deallocating memory regions
616:
617: */
618:
619:
620:
621: /*
622:
623: * new_region returns a new memory region descriptor, or NULL
624:
625: */
626:
627:
628:
629: MEMREGION *
630:
631: new_region()
632:
633: {
634:
635: MEMREGION *m, *newfrees;
636:
637: int i;
638:
639:
640:
641: m = rfreelist;
642:
643: if (!m) {
644:
645: ALERT("new_region: ran out of free regions");
646:
647: return 0;
648:
649: }
650:
651: assert(ISFREE(m));
652:
653: rfreelist = m->next;
654:
655: m->next = 0;
656:
657:
658:
659: /* if we're running low on free regions, allocate some more
660:
661: * we have to do this with at least 1 free region left so that get_region
662:
663: * has a chance of working
664:
665: */
666:
667: if (rfreelist && !rfreelist->next) {
668:
669: MEMREGION *newstuff;
670:
671:
672:
1.1.1.3 root 673: TRACELOW(("get_region: getting new region descriptors"));
1.1 root 674:
1.1.1.3 root 675: newstuff = get_region(ker, NEWREGIONS*SIZEOF(MEMREGION), PROT_S);
1.1 root 676:
677: if (!newstuff)
678:
1.1.1.3 root 679: newstuff = get_region(alt,NEWREGIONS*SIZEOF(MEMREGION), PROT_S);
1.1 root 680:
681: if (!newstuff)
682:
1.1.1.3 root 683: newstuff = get_region(core, NEWREGIONS*SIZEOF(MEMREGION), PROT_S);
1.1 root 684:
685: newfrees = newstuff ? (MEMREGION *)newstuff->loc : 0;
686:
687: if (newfrees) {
688:
689: newfrees[NEWREGIONS-1].next = 0;
690:
691: newfrees[NEWREGIONS-1].links = 0;
692:
693: for (i = 0; i < NEWREGIONS-1; i++) {
694:
695: newfrees[i].next = &newfrees[i+1];
696:
697: newfrees[i].links = 0;
698:
699: }
700:
701: rfreelist = newfrees;
702:
703: } else {
704:
1.1.1.2 root 705: DEBUG(("couldn't get new region descriptors!"));
1.1 root 706:
707: }
708:
709: }
710:
711:
712:
713: return m;
714:
715: }
716:
717:
718:
719: /*
720:
721: * dispose_region destroys a memory region descriptor
722:
723: */
724:
725:
726:
727: void
728:
729: dispose_region(m)
730:
731: MEMREGION *m;
732:
733: {
734:
735: m->next = rfreelist;
736:
737: rfreelist = m;
738:
739: }
740:
741:
742:
743: /*
744:
1.1.1.3 root 745: * change_prot_status: change the status of a region to 'newmode'. We're
746:
747: * given its starting address, not its region structure pointer, so we have
748:
749: * to find the region pointer; since this is illegal if proc doesn't own
750:
751: * the region, we know we'll find the region struct pointer in proc->mem.
752:
753: *
754:
755: * If the proc doesn't own it, you get EACCDN. There are no other errors.
756:
757: * God help you if newmode isn't legal!
758:
759: */
760:
761:
762:
763: long
764:
765: change_prot_status(proc,start,newmode)
766:
767: PROC *proc;
768:
769: long start;
770:
771: int newmode;
772:
773: {
774:
775: MEMREGION **mr;
776:
777: int i;
778:
779:
780:
781: /* return EACCDN if you don't own the region in question */
782:
783: if (!proc->mem) return EACCDN;
784:
785:
786:
787: for (mr = proc->mem, i = 0; i < proc->num_reg; i++, mr++) {
788:
789: if ((*mr)->loc == start) goto found;
790:
791: }
792:
793: return EACCDN;
794:
795:
796:
797: found:
798:
799: mark_region(*mr,newmode);
800:
801: return E_OK;
802:
803: }
804:
805:
806:
807: /*
808:
1.1 root 809: * virtaddr
810:
811: * attach_region(proc, reg): attach the region to the given process:
812:
813: * returns the address at which it was attached, or NULL if the process
814:
815: * cannot attach more regions. The region link count is incremented if
816:
817: * the attachment is successful.
818:
1.1.1.3 root 819: *
820:
821: * Calls mark_region on the region to mark this process as an owner.
822:
823: * This is redundant since it executes a complicated no-op for every
824:
825: * other process in the system. Sigh.
826:
1.1 root 827: */
828:
829:
830:
831: virtaddr
832:
833: attach_region(proc, reg)
834:
835: PROC *proc;
836:
837: MEMREGION *reg;
838:
839: {
840:
841: int i;
842:
843: MEMREGION **newmem;
844:
845: virtaddr *newaddr;
846:
847:
848:
1.1.1.3 root 849: TRACELOW(("attach_region %lx len %lx to pid %d",
850:
851: reg->loc, reg->len, proc->pid));
852:
853:
854:
1.1 root 855: if (!reg || !reg->loc) {
856:
857: ALERT("attach_region: attaching a null region??");
858:
859: return 0;
860:
861: }
862:
1.1.1.3 root 863:
864:
865: again:
866:
1.1 root 867: for (i = 0; i < proc->num_reg; i++) {
868:
869: if (!proc->mem[i]) {
870:
871: assert(proc->addr[i] == 0);
872:
873: reg->links++;
874:
875: proc->mem[i] = reg;
876:
877: proc->addr[i] = (virtaddr) reg->loc;
878:
1.1.1.3 root 879: mark_region(reg,PROT_NOCHANGE);
880:
1.1 root 881: return proc->addr[i];
882:
883: }
884:
885: }
886:
887:
888:
889: /* Hmmm, OK, we have to expand the process' memory table */
890:
1.1.1.3 root 891: TRACELOW(("Expanding process memory table"));
1.1 root 892:
893: i = proc->num_reg + NUM_REGIONS;
894:
895:
896:
897: newmem = kmalloc(i * SIZEOF(MEMREGION *));
898:
899: newaddr = kmalloc(i * SIZEOF(virtaddr));
900:
901:
902:
903: if (newmem && newaddr) {
904:
1.1.1.3 root 905: /*
906:
907: * We have to use temps while allocating and freeing mem
908:
909: * and addr so the memory protection code won't walk this
910:
911: * process' memory list in the middle.
912:
913: */
914:
915: void *pmem, *paddr;
916:
917:
918:
1.1 root 919: /* copy over the old address mapping */
920:
921: for (i = 0; i < proc->num_reg; i++) {
922:
923: newmem[i] = proc->mem[i];
924:
925: newaddr[i] = proc->addr[i];
926:
927: if (newmem[i] == 0)
928:
929: assert(newaddr[i] == 0);
930:
931: }
932:
933: /* initialize the rest of the tables */
934:
935: for(; i < proc->num_reg + NUM_REGIONS; i++) {
936:
937: newmem[i] = 0;
938:
939: newaddr[i] = 0;
940:
941: }
942:
1.1.1.3 root 943: /* free the old tables (carefully! for memory protection) */
944:
945: pmem = proc->mem;
1.1 root 946:
1.1.1.3 root 947: paddr = proc->addr;
948:
949: proc->mem = NULL;
950:
951: proc->addr = NULL;
952:
953: kfree(pmem); kfree(paddr);
1.1 root 954:
955: proc->mem = newmem;
956:
957: proc->addr = newaddr;
958:
959: proc->num_reg += NUM_REGIONS;
960:
1.1.1.3 root 961: /* this time we will succeed */
1.1 root 962:
1.1.1.3 root 963: goto again;
1.1 root 964:
1.1.1.3 root 965: } else {
1.1 root 966:
1.1.1.3 root 967: if (newmem) kfree(newmem);
1.1 root 968:
1.1.1.3 root 969: if (newaddr) kfree(newaddr);
1.1 root 970:
1.1.1.3 root 971: DEBUG(("attach_region: failed"));
1.1 root 972:
1.1.1.3 root 973: return 0;
1.1 root 974:
1.1.1.3 root 975: }
1.1 root 976:
977: }
978:
979:
980:
981: /*
982:
983: * detach_region(proc, reg): remove region from the procedure's address
984:
985: * space. If no more processes reference the region, return it to the
986:
987: * system. Note that we search backwards, so that the most recent
988:
989: * attachment of memory gets detached!
990:
1.1.1.3 root 991: *
992:
993: * Calls mark_region on the region to mark this process as a non-owner.
994:
995: * This is redundant since it executes a complicated no-op for every
996:
997: * other process in the system. Sigh.
998:
1.1 root 999: */
1000:
1001:
1002:
1003: void
1004:
1005: detach_region(proc, reg)
1006:
1007: PROC *proc;
1008:
1009: MEMREGION *reg;
1010:
1011: {
1012:
1013: int i;
1014:
1015:
1016:
1017: if (!reg) return;
1018:
1.1.1.3 root 1019:
1020:
1021: TRACELOW(("detach_region %lx len %lx from pid %d",
1022:
1023: reg->loc, reg->len, proc->pid));
1024:
1025:
1026:
1.1 root 1027: for (i = proc->num_reg - 1; i >= 0; i--) {
1028:
1029: if (proc->mem[i] == reg) {
1030:
1031: reg->links--;
1032:
1033: proc->mem[i] = 0; proc->addr[i] = 0;
1034:
1035: if (reg->links == 0) {
1036:
1037: free_region(reg);
1038:
1039: }
1040:
1.1.1.3 root 1041: else {
1042:
1043: /* cause curproc's table to be updated */
1044:
1045: mark_region(reg,PROT_NOCHANGE);
1046:
1047: }
1048:
1.1 root 1049: return;
1050:
1051: }
1052:
1053: }
1054:
1.1.1.2 root 1055: DEBUG(("detach_region: region not attached"));
1.1 root 1056:
1057: }
1058:
1059:
1060:
1061: /*
1062:
1.1.1.3 root 1063: * get_region(MMAP map, ulong size, int mode) -- allocate a new region of the
1.1 root 1064:
1065: * given size in the given memory map. if no region big enough is available,
1066:
1067: * return NULL, otherwise return a pointer to the region.
1068:
1.1.1.3 root 1069: * "mode" tells us about memory protection modes
1070:
1071: *
1072:
1.1 root 1073: * the "links" field in the region is set to 1
1074:
1075: *
1076:
1077: * BEWARE: new_region may call get_region (indirectly), so we have to be
1078:
1079: * _very_ careful with re-entrancy in this function
1080:
1081: */
1082:
1083:
1084:
1085: MEMREGION *
1086:
1.1.1.3 root 1087: get_region(map, size, mode)
1.1 root 1088:
1089: MMAP map;
1090:
1091: ulong size;
1092:
1.1.1.3 root 1093: int mode;
1094:
1.1 root 1095: {
1096:
1097: MEMREGION *m, *n;
1098:
1099:
1100:
1.1.1.3 root 1101: TRACELOW(("get_region(%s,%lx,%x)",
1102:
1103: (map == ker ? "ker" : (map == core ? "core" : "alt")),
1104:
1105: size, mode));
1106:
1107:
1108:
1.1 root 1109: /* precautionary measures */
1110:
1111: if (size == 0) {
1112:
1.1.1.2 root 1113: DEBUG(("request for 0 bytes??"));
1.1 root 1114:
1115: size = 1;
1116:
1117: }
1118:
1119:
1120:
1121: size = ROUND(size);
1122:
1123:
1124:
1125: n = *map;
1126:
1127:
1128:
1129: sanity_check(map);
1130:
1131: /* exact matches are likely to be rare, so we pre-allocate a new
1132:
1133: * region here; this helps us to avoid re-entrancy problems
1134:
1135: * when new_region calls get_region
1136:
1137: */
1138:
1139: m = new_region();
1140:
1141:
1142:
1143: while (n) {
1144:
1145: if (ISFREE(n)) {
1146:
1147: if (n->len == size) {
1148:
1149: if (m) dispose_region(m);
1150:
1151: n->links++;
1152:
1.1.1.3 root 1153: goto win;
1.1 root 1154:
1155: }
1156:
1157: else if (n->len > size) {
1158:
1159: /* split a new region, 'm', which will contain the free bytes after n */
1160:
1161: if (m) {
1162:
1163: m->next = n->next;
1164:
1165: n->next = m;
1166:
1167: m->mflags = n->mflags & M_MAP;
1168:
1169: m->loc = n->loc + size;
1170:
1171: m->len = n->len - size;
1172:
1173: n->len = size;
1174:
1175: n->links++;
1176:
1.1.1.3 root 1177: goto win;
1.1 root 1178:
1179: } else {
1180:
1.1.1.2 root 1181: DEBUG(("get_region: no regions left"));
1.1 root 1182:
1183: return 0;
1184:
1185: }
1186:
1187: }
1188:
1189: }
1190:
1191: n = n->next;
1192:
1193: }
1194:
1195:
1196:
1197: if (m)
1198:
1199: dispose_region(m);
1200:
1.1.1.3 root 1201:
1202:
1203: TRACELOW(("get_region: no memory left in this map"));
1204:
1.1 root 1205: return NULL;
1206:
1.1.1.3 root 1207:
1208:
1209: win:
1210:
1211: mark_region(n, mode & PROT_PROTMODE);
1212:
1213: if (mode & M_KEEP) n->mflags |= M_KEEP;
1214:
1215:
1216:
1217: return n;
1218:
1.1 root 1219: }
1220:
1221:
1222:
1223: /*
1224:
1225: * free_region(MEMREGION *reg): free the indicated region. The map
1226:
1227: * in which the region is contained is given by reg->mflags.
1228:
1229: * the caller is responsible for making sure that the region
1230:
1231: * really should be freed, i.e. that reg->links == 0.
1232:
1.1.1.2 root 1233: *
1234:
1235: * special things to do:
1236:
1237: * if the region is a shared text region, we must close the
1238:
1239: * associated file descriptor
1240:
1.1 root 1241: */
1242:
1243:
1244:
1245: void
1246:
1247: free_region(reg)
1248:
1249: MEMREGION *reg;
1250:
1251: {
1252:
1253: MMAP map;
1254:
1255: MEMREGION *m;
1256:
1.1.1.2 root 1257: SHTEXT *s, **old;
1258:
1.1 root 1259:
1260:
1261: if (!reg) return;
1262:
1263:
1264:
1265: assert(ISFREE(reg));
1266:
1267:
1268:
1.1.1.2 root 1269: if (reg->mflags & M_SHTEXT) {
1270:
1271: TRACE(("freeing shared text region"));
1272:
1273: old = &text_reg;
1274:
1275: for(;;) {
1276:
1277: s = *old;
1278:
1279: if (!s) break;
1280:
1281: if (s->text == reg) {
1282:
1.1.1.3 root 1283: if (s->f)
1284:
1285: do_close(s->f);
1.1.1.2 root 1286:
1287: *old = s->next;
1288:
1289: kfree(s);
1290:
1291: break;
1292:
1293: }
1294:
1295: old = &s->next;
1296:
1297: }
1298:
1299: if (!s) {
1300:
1301: DEBUG(("No shared text entry for M_SHTEXT region??"));
1302:
1303: }
1304:
1305: }
1306:
1307:
1308:
1.1 root 1309: if (reg->mflags & M_CORE)
1310:
1311: map = core;
1312:
1313: else if (reg->mflags & M_ALT)
1314:
1315: map = alt;
1316:
1317: else if (reg->mflags & M_KER)
1318:
1319: map = ker;
1320:
1321: else {
1322:
1323: FATAL("free_region: region flags not valid (%x)", reg->mflags);
1324:
1325: }
1326:
1327: reg->mflags &= M_MAP;
1328:
1329:
1330:
1.1.1.3 root 1331: /* unhook any vectors pointing into this region */
1332:
1333: unlink_vectors(reg->loc, reg->loc + reg->len);
1.1 root 1334:
1335:
1.1.1.3 root 1336:
1337: /* BUG(?): should invalidate caches entries - a copyback cache could stuff
1.1.1.2 root 1338:
1339: * things into freed memory.
1340:
1.1.1.3 root 1341: * cinv(reg->loc, reg->len);
1.1.1.2 root 1342:
1343: */
1344:
1.1.1.3 root 1345: m = *map;
1346:
1347: assert(m);
1348:
1349:
1350:
1351: /* MEMPROT: invalidate */
1352:
1353: if (map == core || map == alt)
1354:
1355: mark_region(reg,PROT_I);
1356:
1357:
1358:
1.1 root 1359: if (m == reg) goto merge_after;
1360:
1361:
1362:
1363: /* merge previous region if it's free and contiguous with 'reg' */
1364:
1365:
1366:
1367: /* first, we find the region */
1368:
1369: while (m && m->next != reg)
1370:
1371: m = m->next;
1372:
1373:
1374:
1.1.1.2 root 1375: if (m == NULL) {
1376:
1377: FATAL("couldn't find region %lx: loc: %lx len: %ld",
1378:
1379: reg, reg->loc, reg->len);
1380:
1381: }
1.1 root 1382:
1383:
1384:
1385: if (ISFREE(m) && (m->loc + m->len == reg->loc)) {
1386:
1387: m->len += reg->len;
1388:
1389: assert(m->next == reg);
1390:
1391: m->next = reg->next;
1392:
1393: reg->next = 0;
1394:
1395: dispose_region(reg);
1396:
1397: reg = m;
1398:
1399: }
1400:
1401:
1402:
1403: /* merge next region if it's free and contiguous with 'reg' */
1404:
1405: merge_after:
1406:
1407: m = reg->next;
1408:
1409: if (m && ISFREE(m) && reg->loc + reg->len == m->loc) {
1410:
1411: reg->len += m->len;
1412:
1413: reg->next = m->next;
1414:
1415: m->next = 0;
1416:
1417: dispose_region(m);
1418:
1419: }
1420:
1421:
1422:
1423: sanity_check(map);
1424:
1425: }
1426:
1427:
1428:
1429: /*
1430:
1431: * shrink_region(MEMREGION *reg, ulong newsize):
1432:
1433: * shrink region 'reg', so that it is now 'newsize' bytes long.
1434:
1435: * if 'newsize' is bigger than the region's current size, return EGSBF;
1436:
1437: * otherwise return 0.
1438:
1439: */
1440:
1441:
1442:
1443: long
1444:
1445: shrink_region(reg, newsize)
1446:
1447: MEMREGION *reg;
1448:
1449: ulong newsize;
1450:
1451: {
1452:
1453: MEMREGION *n;
1454:
1455: ulong diff;
1456:
1457:
1458:
1459:
1460:
1461: newsize = ROUND(newsize);
1462:
1463:
1464:
1465: assert(reg->links > 0);
1466:
1467:
1468:
1.1.1.2 root 1469: if (!(reg->mflags & (M_CORE | M_ALT | M_KER))) {
1.1 root 1470:
1471: FATAL("shrink_region: bad region flags (%x)", reg->mflags);
1472:
1473: }
1474:
1475:
1476:
1477: /* shrinking to 0 is the same as freeing */
1478:
1479: if (newsize == 0) {
1480:
1481: detach_region(curproc, reg);
1482:
1483: return 0;
1484:
1485: }
1486:
1487:
1488:
1489: /* if new size is the same as old size, don't do anything */
1490:
1491: if (newsize == reg->len) {
1492:
1493: return 0; /* nothing to do */
1494:
1495: }
1496:
1497:
1498:
1499: if (newsize > reg->len) {
1500:
1.1.1.2 root 1501: DEBUG(("shrink_region: request to make region bigger"));
1.1 root 1502:
1503: return EGSBF; /* growth failure */
1504:
1505: }
1506:
1507:
1508:
1509: /* OK, we're going to free (reg->len - newsize) bytes at the end of
1510:
1511: this block. If the block after us is already free, simply add the
1512:
1513: space to that block.
1514:
1515: */
1516:
1517: n = reg->next;
1518:
1519: diff = reg->len - newsize;
1520:
1521:
1522:
1523: if (n && ISFREE(n) && reg->loc + reg->len == n->loc) {
1524:
1525: reg->len = newsize;
1526:
1527: n->loc -= diff;
1528:
1529: n->len += diff;
1530:
1.1.1.3 root 1531: /* MEMPROT: invalidate the second half */
1532:
1533: /* (part of it is already invalid; that's OK) */
1534:
1535: mark_region(n,PROT_I);
1536:
1537:
1538:
1.1 root 1539: return 0;
1540:
1541: }
1542:
1543: else {
1544:
1545: n = new_region();
1546:
1547: if (!n) {
1548:
1.1.1.2 root 1549: DEBUG(("shrink_region: new_region failed"));
1.1 root 1550:
1551: return EINTRN;
1552:
1553: }
1554:
1555: reg->len = newsize;
1556:
1557: n->loc = reg->loc + newsize;
1558:
1559: n->len = diff;
1560:
1561: n->mflags = reg->mflags & M_MAP;
1562:
1563: n->next = reg->next;
1564:
1565: reg->next = n;
1566:
1.1.1.3 root 1567: /* MEMPROT: invalidate the new, free region */
1568:
1569: mark_region(n,PROT_I);
1570:
1.1 root 1571: }
1572:
1573: return 0;
1574:
1575: }
1576:
1577:
1578:
1579: /*
1580:
1581: * max_rsize(map): return the length of the biggest free region
1582:
1583: * in the given memory map, or 0 if no regions remain.
1584:
1585: */
1586:
1587:
1588:
1589: long
1590:
1591: max_rsize(map)
1592:
1593: MMAP map;
1594:
1595: {
1596:
1.1.1.2 root 1597: MEMREGION *m;
1.1 root 1598:
1599: long size = 0;
1600:
1601:
1602:
1603: for (m = *map; m; m = m->next) {
1604:
1605: if (ISFREE(m)) {
1606:
1607: if (m->len > size) {
1608:
1609: size = m->len;
1610:
1611: }
1612:
1613: }
1614:
1615: }
1616:
1617: return size;
1618:
1619: }
1620:
1621:
1622:
1623: /*
1624:
1625: * tot_rsize(map, flag): if flag == 1, return the total number of bytes in
1626:
1627: * the given memory map; if flag == 0, return only the number of free
1628:
1629: * bytes
1630:
1631: */
1632:
1633:
1634:
1635: long
1636:
1637: tot_rsize(map, flag)
1638:
1639: MMAP map;
1640:
1641: int flag;
1642:
1643: {
1644:
1645: MEMREGION *m;
1646:
1647: long size = 0;
1648:
1649:
1650:
1651: for (m = *map; m; m = m->next) {
1652:
1653: if (flag || ISFREE(m)) {
1654:
1655: size += m->len;
1656:
1657: }
1658:
1659: }
1660:
1661: return size;
1662:
1663: }
1664:
1665:
1666:
1667: /*
1668:
1.1.1.3 root 1669: * alloc_region(MMAP map, ulong size, int mode): allocate a new region and
1.1 root 1670:
1.1.1.3 root 1671: * attach it to the current process; returns the address at which the region
1.1 root 1672:
1.1.1.3 root 1673: * was attached, or NULL. The mode argument is the memory protection mode to
1.1 root 1674:
1.1.1.3 root 1675: * give to get_region, and in turn to mark_region.
1.1 root 1676:
1677: */
1678:
1679:
1680:
1681: virtaddr
1682:
1.1.1.3 root 1683: alloc_region(map, size, mode)
1.1 root 1684:
1685: MMAP map;
1686:
1687: ulong size;
1688:
1.1.1.3 root 1689: int mode;
1690:
1.1 root 1691: {
1692:
1693: MEMREGION *m;
1694:
1695: PROC *proc = curproc;
1696:
1697: virtaddr v;
1698:
1699:
1700:
1.1.1.3 root 1701: TRACELOW(("alloc_region(map,size: %lx,mode: %x)",size,mode));
1702:
1703: if (!size) {
1704:
1705: DEBUG(("alloc_region of zero bytes?!"));
1706:
1707: return 0;
1708:
1709: }
1710:
1711:
1712:
1713: m = get_region(map, size, mode);
1.1 root 1714:
1715: if (!m) {
1716:
1.1.1.3 root 1717: TRACELOW(("alloc_region: get_region failed"));
1718:
1.1 root 1719: return 0;
1720:
1721: }
1722:
1723:
1724:
1.1.1.2 root 1725: /* sanity check: even addresses only, please */
1726:
1727: assert((m->loc & MASKBITS) == 0);
1728:
1729:
1730:
1.1 root 1731: v = attach_region(proc, m);
1732:
1733: /* NOTE: get_region returns a region with link count 1; since attach_region
1734:
1735: * increments the link count, we restore it after calling attach_region
1736:
1737: */
1738:
1739: m->links = 1;
1740:
1741: if (!v) {
1742:
1743: m->links = 0;
1744:
1745: free_region(m);
1746:
1.1.1.3 root 1747: TRACE(("alloc_region: attach_region failed"));
1748:
1.1 root 1749: return 0;
1750:
1751: }
1752:
1753: return v;
1754:
1755: }
1756:
1757:
1758:
1759: /*
1760:
1761: * routines for creating a copy of an environment, and a new basepage.
1762:
1763: * note that the memory regions created should immediately be attached to
1764:
1765: * a process! Also note that create_env always operates in ST RAM, but
1766:
1767: * create_base might not.
1768:
1769: */
1770:
1771:
1772:
1773: MEMREGION *
1774:
1.1.1.4 ! root 1775: create_env(env, flags)
1.1 root 1776:
1777: const char *env;
1778:
1.1.1.4 ! root 1779: ulong flags;
! 1780:
1.1 root 1781: {
1782:
1783: long size;
1784:
1785: MEMREGION *m;
1786:
1787: virtaddr v;
1788:
1789: const char *old;
1790:
1791: char *new;
1792:
1.1.1.4 ! root 1793: short protmode;
! 1794:
1.1.1.3 root 1795:
1.1 root 1796:
1797: if (!env) {
1798:
1799: env = ((BASEPAGE *)curproc->base)->p_env;
1800:
1801: /* duplicate parent's environment */
1802:
1803: }
1804:
1805: size = 2;
1806:
1807: old = env;
1808:
1809: while (*env || *(env+1))
1810:
1811: env++,size++;
1812:
1.1.1.3 root 1813:
1814:
1.1.1.4 ! root 1815: protmode = (flags & F_PROTMODE) >> F_PROTSHIFT;
! 1816:
! 1817:
! 1818:
! 1819: v = alloc_region(core, size, protmode);
1.1.1.3 root 1820:
1821: /* if core fails, try alt */
1822:
1823: if (!v)
1824:
1.1.1.4 ! root 1825: v = alloc_region(alt, size, protmode);
1.1.1.3 root 1826:
1827:
1.1 root 1828:
1829: if (!v) {
1830:
1.1.1.2 root 1831: DEBUG(("create_env: alloc_region failed"));
1.1 root 1832:
1833: return (MEMREGION *)0;
1834:
1835: }
1836:
1837: m = addr2mem(v);
1838:
1839:
1840:
1841: /* copy the old environment into the new */
1842:
1843: new = (char *) m->loc;
1844:
1.1.1.3 root 1845: TRACE(("copying environment: from %lx to %lx", old, new));
1846:
1.1 root 1847: while (size > 0) {
1848:
1849: *new++ = *old++;
1850:
1851: --size;
1852:
1853: }
1854:
1.1.1.3 root 1855: TRACE(("finished copying environment"));
1856:
1857:
1858:
1.1 root 1859: return m;
1860:
1861: }
1862:
1863:
1864:
1865: MEMREGION *
1866:
1867: create_base(cmd, env, flags, prgsize)
1868:
1869: const char *cmd;
1870:
1871: MEMREGION *env;
1872:
1873: ulong flags, prgsize;
1874:
1875: {
1876:
1877: long len, coresize, altsize;
1878:
1879: MMAP map;
1880:
1881: MEMREGION *m;
1882:
1883: BASEPAGE *b;
1884:
1.1.1.3 root 1885: short protmode;
1886:
1.1 root 1887:
1888:
1889: /* if flags & F_ALTLOAD == 1, then we might decide to load in alternate
1890:
1891: RAM if enough is available. "enough" is: if more alt ram than ST ram,
1892:
1893: load there; otherwise, if more than (minalt+1)*128K alt ram available
1894:
1895: for heap space, load in alt ram ("minalt" is the high byte of flags)
1896:
1897: */
1898:
1899: if (flags & F_ALTLOAD) {
1900:
1901: coresize = max_rsize(core);
1902:
1903: altsize = max_rsize(alt);
1904:
1905: if (altsize >= coresize)
1906:
1907: map = alt;
1908:
1909: else {
1910:
1.1.1.2 root 1911: len = (flags & F_MINALT) >> 28L;
1.1 root 1912:
1913: len = (len+1)*128*1024L + prgsize + 256;
1914:
1915: if (altsize >= len)
1916:
1917: map = alt;
1918:
1919: else
1920:
1921: map = core;
1922:
1923: }
1924:
1925: }
1926:
1927: else
1928:
1929: map = core;
1930:
1931:
1932:
1933: len = max_rsize(map);
1934:
1.1.1.3 root 1935: if (len < prgsize) {
1936:
1937: /* can't possibly load this file in its eligible regions */
1938:
1939: DEBUG(("create_base: max_rsize smaller than prgsize"));
1940:
1941: return 0;
1942:
1943: }
1944:
1.1 root 1945:
1946:
1947: /* make sure that a little bit of memory is left over */
1948:
1949: if (len > 2*KEEP_MEM) {
1950:
1951: len -= KEEP_MEM;
1952:
1953: }
1954:
1.1.1.3 root 1955:
1956:
1957: protmode = (flags & F_PROTMODE) >> F_PROTSHIFT;
1958:
1959:
1960:
1961: m = addr2mem(alloc_region(map, len, protmode));
1.1 root 1962:
1963: if (!m) {
1964:
1.1.1.2 root 1965: DEBUG(("create_base: alloc_region failed"));
1.1 root 1966:
1967: return 0;
1968:
1969: }
1970:
1971: b = (BASEPAGE *)(m->loc);
1972:
1973:
1974:
1975: zero((char *)b, (long)sizeof(BASEPAGE));
1976:
1977: b->p_lowtpa = (long)b;
1978:
1979: b->p_hitpa = m->loc + m->len;
1980:
1981: b->p_env = (char *)env->loc;
1982:
1983: b->p_flags = flags;
1984:
1985:
1986:
1987: if (cmd)
1988:
1989: strncpy(b->p_cmdlin, cmd, 126);
1990:
1991: return m;
1992:
1993: }
1994:
1995:
1996:
1997: /*
1998:
1.1.1.2 root 1999: * load_region(): loads the program with the given file name
1.1 root 2000:
1.1.1.2 root 2001: * into a new region, and returns a pointer to that region. On
1.1 root 2002:
1.1.1.2 root 2003: * an error, returns 0 and leaves the error number in mint_errno.
1.1 root 2004:
1.1.1.2 root 2005: * "env" points to an already set up environment region, as returned
1.1 root 2006:
1.1.1.3 root 2007: * by create_env. On success, "xp" points to the file attributes, which
2008:
2009: * Pexec has already determined, and "fp" points to the programs
1.1 root 2010:
1.1.1.3 root 2011: * prgflags. "text" is a pointer to a MEMREGION
1.1 root 2012:
1.1.1.2 root 2013: * pointer, which will be set to the region occupied by the shared
1.1 root 2014:
1.1.1.2 root 2015: * text segment of this program (if applicable).
1.1 root 2016:
1.1.1.2 root 2017: */
1.1 root 2018:
2019:
2020:
2021: MEMREGION *
2022:
1.1.1.3 root 2023: load_region(filename, env, cmdlin, xp, text, fp)
1.1 root 2024:
2025: const char *filename;
2026:
2027: MEMREGION *env;
2028:
2029: const char *cmdlin;
2030:
2031: XATTR *xp; /* attributes for the file just loaded */
2032:
1.1.1.2 root 2033: MEMREGION **text; /* set to point to shared text region,
2034:
2035: if any */
2036:
1.1.1.3 root 2037: long *fp; /* prgflags for this file */
2038:
1.1 root 2039: {
2040:
2041: FILEPTR *f;
2042:
2043: DEVDRV *dev;
2044:
1.1.1.2 root 2045: MEMREGION *reg, *shtext;
1.1 root 2046:
2047: BASEPAGE *b;
2048:
1.1.1.2 root 2049: long size, start;
1.1 root 2050:
1.1.1.2 root 2051: FILEHEAD fh;
1.1 root 2052:
2053:
2054:
1.1.1.2 root 2055: /* bug: this should be O_DENYW mode, not O_DENYNONE */
1.1 root 2056:
1.1.1.2 root 2057: /* we must use O_DENYNONE because of the desktop and because of the
1.1 root 2058:
1.1.1.2 root 2059: * TOS file system brain-damage
1.1 root 2060:
1.1.1.2 root 2061: */
1.1 root 2062:
2063: f = do_open(filename, O_DENYNONE | O_EXEC, 0, xp);
2064:
2065: if (!f) {
2066:
2067: return 0; /* mint_errno set by do_open */
2068:
2069: }
2070:
2071:
2072:
1.1.1.2 root 2073: dev = f->dev;
1.1 root 2074:
1.1.1.2 root 2075: size = (*dev->read)(f, (void *)&fh, (long)sizeof(fh));
1.1 root 2076:
1.1.1.2 root 2077: if (fh.fmagic != GEMDOS_MAGIC || size != (long)sizeof(fh)) {
1.1 root 2078:
1.1.1.2 root 2079: DEBUG(("load_region: file not executable"));
1.1 root 2080:
2081: mint_errno = ENOEXEC;
2082:
2083: failed:
2084:
2085: do_close(f);
2086:
2087: return 0;
2088:
2089: }
2090:
2091:
2092:
1.1.1.3 root 2093: *fp = fh.flag;
2094:
2095:
2096:
1.1.1.2 root 2097: if (fh.flag & F_SHTEXT) {
2098:
2099: TRACE(("loading shared text segment"));
2100:
2101: shtext = get_text_seg(f, &fh, xp);
2102:
2103: if (!shtext) {
2104:
2105: DEBUG(("load_region: unable to get shared text segment"));
2106:
2107: /* mint_errno set in get_text_seg */
2108:
2109: goto failed;
2110:
2111: }
2112:
2113: size = fh.fdata + fh.fbss;
2114:
2115: } else {
2116:
2117: size = fh.ftext + fh.fdata + fh.fbss;
2118:
2119: shtext = 0;
2120:
2121: }
2122:
2123:
1.1 root 2124:
1.1.1.3 root 2125: reg = create_base(cmdlin, env, fh.flag, size);
1.1 root 2126:
1.1.1.3 root 2127: if (reg && size+1024L > reg->len) {
1.1 root 2128:
1.1.1.3 root 2129: DEBUG(("load_region: insufficient memory to load"));
1.1 root 2130:
1.1.1.3 root 2131: detach_region(curproc, reg);
1.1 root 2132:
1.1.1.3 root 2133: reg = 0;
1.1 root 2134:
2135: }
2136:
2137:
2138:
2139: if (reg == 0) {
2140:
1.1.1.2 root 2141: if (shtext) {
2142:
2143: detach_region(curproc, shtext);
2144:
2145: }
2146:
1.1 root 2147: mint_errno = ENSMEM;
2148:
2149: goto failed;
2150:
2151: }
2152:
2153:
2154:
2155: b = (BASEPAGE *)reg->loc;
2156:
2157: b->p_flags = fh.flag;
2158:
1.1.1.2 root 2159: if (shtext) {
2160:
2161: b->p_tbase = shtext->loc;
1.1 root 2162:
1.1.1.2 root 2163: b->p_tlen = 0;
1.1 root 2164:
1.1.1.2 root 2165: b->p_dbase = b->p_lowtpa + 256;
2166:
2167: } else {
2168:
2169: b->p_tbase = b->p_lowtpa + 256;
2170:
2171: b->p_tlen = fh.ftext;
2172:
2173: b->p_dbase = b->p_tbase + b->p_tlen;
2174:
2175: }
1.1 root 2176:
2177: b->p_dlen = fh.fdata;
2178:
2179: b->p_bbase = b->p_dbase + b->p_dlen;
2180:
1.1.1.2 root 2181: b->p_blen = fh.fbss;
1.1 root 2182:
2183:
2184:
1.1.1.2 root 2185: /* if shared text, then we start loading at the end of the
1.1 root 2186:
1.1.1.2 root 2187: * text region, since that is already set up
2188:
2189: */
2190:
2191: if (shtext) {
2192:
2193: /* skip over text info */
2194:
2195: size = fh.fdata;
2196:
2197: start = fh.ftext;
2198:
2199: } else {
2200:
2201: size = fh.ftext + fh.fdata;
2202:
2203: start = 0;
2204:
2205: }
2206:
2207:
2208:
2209: mint_errno = (int)load_and_reloc(f, &fh, (char *)b+256, start,
2210:
2211: size, b);
2212:
2213:
2214:
2215: if (mint_errno) {
1.1 root 2216:
2217: detach_region(curproc, reg);
2218:
1.1.1.2 root 2219: if (shtext) detach_region(curproc, shtext);
2220:
1.1 root 2221: goto failed;
2222:
2223: }
2224:
2225:
2226:
2227: if (fh.flag & F_FASTLOAD) /* fastload bit */
2228:
2229: size = b->p_blen;
2230:
2231: else
2232:
2233: size = b->p_hitpa - b->p_bbase;
2234:
2235: zero((char *)b->p_bbase, size);
2236:
2237:
2238:
1.1.1.2 root 2239: do_close(f);
1.1 root 2240:
1.1.1.2 root 2241: *text = shtext;
1.1 root 2242:
1.1.1.2 root 2243: return reg;
1.1 root 2244:
1.1.1.2 root 2245: }
2246:
2247:
2248:
2249: /*
2250:
2251: * load_and_reloc(f, fh, where, start, nbytes): load and relocate from
2252:
2253: * the open GEMDOS executable file f "nbytes" bytes starting at offset
2254:
2255: * "start" (relative to the end of the file header, i.e. from the first
2256:
2257: * byte of the actual program image in the file). "where" is the address
2258:
2259: * in (physical) memory into which the loaded image must be placed; it is
2260:
2261: * assumed that "where" is big enough to hold "nbytes" bytes!
1.1 root 2262:
2263: */
2264:
2265:
2266:
1.1.1.2 root 2267: long
2268:
2269: load_and_reloc(f, fh, where, start, nbytes, base)
2270:
2271: FILEPTR *f;
2272:
2273: FILEHEAD *fh;
2274:
2275: char *where;
2276:
2277: long start;
2278:
2279: long nbytes;
2280:
2281: BASEPAGE *base;
2282:
2283: {
2284:
2285: unsigned char c, *next;
2286:
2287: long r;
2288:
2289: DEVDRV *dev;
2290:
2291: #define LRBUFSIZ 8196
2292:
2293: static unsigned char buffer[LRBUFSIZ];
2294:
2295: long fixup, size, bytes_read;
2296:
2297: long reloc;
2298:
2299:
2300:
2301:
2302:
2303: TRACE(("load_and_reloc: %ld to %ld at %lx", start, nbytes+start, where));
2304:
2305: dev = f->dev;
2306:
2307:
2308:
2309: r = (*dev->lseek)(f, start+sizeof(FILEHEAD), SEEK_SET);
2310:
2311: if (r < 0) return r;
2312:
2313: r = (*dev->read)(f, where, nbytes);
2314:
2315: if (r != nbytes) {
2316:
2317: DEBUG(("load_region: unexpected EOF"));
2318:
2319: return ENOEXEC;
2320:
2321: }
2322:
2323:
2324:
2325: /* now do the relocation */
2326:
2327: /* skip over symbol table, etc. */
2328:
2329: r = (*dev->lseek)(f, sizeof(FILEHEAD) + fh->ftext + fh->fdata +
2330:
2331: fh->fsym, SEEK_SET);
2332:
2333: if (r < 0) return ENOEXEC;
2334:
2335:
2336:
2337: if (fh->reloc != 0 || (*dev->read)(f, (char *)&fixup, 4L) != 4L
2338:
2339: || fixup == 0) {
2340:
2341: return 0; /* no relocation to be performed */
2342:
2343: }
2344:
2345:
2346:
2347: size = LRBUFSIZ;
2348:
2349: bytes_read = 0;
2350:
2351: next = buffer;
2352:
1.1 root 2353:
2354:
1.1.1.2 root 2355: do {
2356:
2357: if (fixup >= nbytes + start) {
2358:
2359: TRACE(("load_region: end of relocation at %ld", fixup));
2360:
2361: break;
2362:
2363: }
2364:
2365: else if (fixup >= start) {
1.1 root 2366:
1.1.1.2 root 2367: reloc = *((long *)(where + fixup - start));
2368:
2369: if (reloc < fh->ftext) {
2370:
2371: reloc += base->p_tbase;
2372:
2373: } else if (reloc < fh->ftext + fh->fdata && base->p_dbase) {
2374:
2375: reloc += base->p_dbase - fh->ftext;
2376:
2377: } else if (reloc < fh->ftext + fh->fdata + fh->fbss && base->p_bbase) {
2378:
2379: reloc += base->p_bbase - (fh->ftext + fh->fdata);
2380:
2381: } else {
2382:
2383: DEBUG(("load_region: bad relocation: %ld", reloc));
2384:
2385: if (base->p_dbase)
2386:
2387: reloc += base->p_dbase - fh->ftext; /* assume data reloc */
2388:
2389: else if (base->p_bbase)
2390:
2391: reloc += base->p_bbase - (fh->ftext + fh->fdata);
2392:
2393: else
2394:
2395: return ENOEXEC;
2396:
2397: }
2398:
2399: *((long *)(where + fixup - start)) = reloc;
2400:
2401: }
1.1 root 2402:
2403: do {
2404:
1.1.1.2 root 2405: if (!bytes_read) {
1.1 root 2406:
1.1.1.2 root 2407: bytes_read =
1.1 root 2408:
1.1.1.2 root 2409: (*dev->read)(f,(char *)buffer,size);
2410:
2411: next = buffer;
1.1 root 2412:
2413: }
2414:
1.1.1.2 root 2415: if (bytes_read < 0) {
1.1 root 2416:
1.1.1.2 root 2417: DEBUG(("load_region: EOF in relocation"));
1.1 root 2418:
1.1.1.2 root 2419: return ENOEXEC;
1.1 root 2420:
1.1.1.2 root 2421: }
1.1 root 2422:
1.1.1.2 root 2423: else if (bytes_read == 0)
1.1 root 2424:
1.1.1.2 root 2425: c = 0;
1.1 root 2426:
1.1.1.2 root 2427: else {
1.1 root 2428:
1.1.1.2 root 2429: c = *next++; bytes_read--;
1.1 root 2430:
1.1.1.2 root 2431: }
1.1 root 2432:
1.1.1.2 root 2433: if (c == 1) fixup += 254;
1.1 root 2434:
1.1.1.2 root 2435: } while (c == 1);
1.1 root 2436:
1.1.1.2 root 2437: fixup += ( (unsigned) c) & 0xff;
1.1 root 2438:
1.1.1.2 root 2439: } while (c);
1.1 root 2440:
2441:
2442:
1.1.1.2 root 2443: return 0;
1.1 root 2444:
1.1.1.2 root 2445: }
2446:
2447:
2448:
2449: /*
2450:
2451: * function to check for existence of a shared text region
2452:
2453: * corresponding to file "f", and if none is found, to create one
2454:
2455: * the memory region being returned is attached to the current
2456:
2457: * process
2458:
2459: */
2460:
2461:
2462:
2463: MEMREGION *
2464:
2465: get_text_seg(f, fh, xp)
2466:
2467: FILEPTR *f;
2468:
2469: FILEHEAD *fh;
2470:
2471: XATTR *xp;
2472:
2473: {
2474:
2475: SHTEXT *s;
1.1 root 2476:
1.1.1.2 root 2477: MEMREGION *m;
2478:
2479: long r;
2480:
2481: BASEPAGE b;
2482:
2483:
2484:
2485: s = text_reg;
2486:
2487:
2488:
2489: while(s) {
2490:
1.1.1.3 root 2491: if (s->f && samefile(&f->fc, &s->f->fc) &&
1.1.1.2 root 2492:
2493: xp->mtime == s->mtime &&
2494:
2495: xp->mdate == s->mdate)
2496:
2497: {
1.1 root 2498:
1.1.1.2 root 2499: m = s->text;
1.1 root 2500:
1.1.1.2 root 2501: if (attach_region(curproc, m)) {
1.1 root 2502:
1.1.1.2 root 2503: TRACE(("re-using shared text region %lx", m));
2504:
2505: return m;
2506:
2507: }
2508:
2509: else {
2510:
2511: mint_errno = ENSMEM;
2512:
2513: return 0;
2514:
2515: }
2516:
2517: }
2518:
2519: s = s->next;
1.1 root 2520:
2521: }
2522:
2523:
2524:
1.1.1.2 root 2525: /* hmmm, not found; OK, we'll have to create a new text region */
2526:
2527:
2528:
2529: s = kmalloc(SIZEOF(SHTEXT));
2530:
2531: if (!s) {
2532:
2533: mint_errno = ENSMEM;
2534:
2535: return 0;
2536:
2537: }
2538:
2539: m = 0;
2540:
2541: /* actually, I can't see why loading in TT RAM is ever undesireable,
2542:
2543: * since shared text programs should be very clean (and since only
2544:
2545: * the text segment is going in there). But better safe than sorry.
2546:
2547: */
2548:
2549: if (fh->flag & F_ALTLOAD) {
2550:
1.1.1.3 root 2551: m = addr2mem(alloc_region(alt, fh->ftext, PROT_P));
1.1.1.2 root 2552:
2553: }
2554:
2555: if (!m)
2556:
1.1.1.3 root 2557: m = addr2mem(alloc_region(core, fh->ftext, PROT_P));
1.1.1.2 root 2558:
2559:
2560:
2561: if (!m) {
2562:
2563: kfree(s);
2564:
2565: mint_errno = ENSMEM;
2566:
2567: return 0;
2568:
2569: }
2570:
2571:
2572:
2573: /* set up a fake "basepage" for load_and_reloc
2574:
2575: * note: the 0 values should make load_and_reloc
2576:
2577: * barf on any attempts at data relocation, since we have
2578:
2579: * no data segment
2580:
2581: */
2582:
2583: TRACE(("attempting to create shared text region"));
2584:
2585:
2586:
2587: b.p_tbase = m->loc;
2588:
2589: b.p_tlen = fh->ftext;
2590:
2591: b.p_dbase = 0;
2592:
2593: b.p_dlen = 0;
2594:
2595: b.p_bbase = b.p_blen = 0;
2596:
1.1 root 2597:
1.1.1.2 root 2598:
2599: r = load_and_reloc(f, fh, (char *)m->loc, 0, fh->ftext, &b);
2600:
2601: if (r) {
2602:
2603: detach_region(curproc, m);
2604:
2605: kfree(s);
2606:
2607: return 0;
2608:
2609: }
2610:
2611:
2612:
2613: /* region has valid shared text data */
2614:
2615: m->mflags |= M_SHTEXT;
2616:
2617:
2618:
2619: /*
2620:
2621: * KLUDGE: to make sure we always have up to date shared text
2622:
2623: * info, even across a network, we leave the file passed
2624:
2625: * to us open with DENYWRITE mode, so that nobody will
2626:
2627: * modify it.
2628:
2629: */
2630:
2631: f->links++; /* keep the file open longer */
2632:
2633:
2634:
2635: /* BUG: what if someone already has the file open for
2636:
2637: * writing? Then we could get screwed...
2638:
2639: */
2640:
2641: f->flags = (f->flags & ~O_SHMODE) | O_DENYW;
2642:
2643: s->f = f;
2644:
2645: s->text = m;
2646:
2647: s->next = text_reg;
2648:
2649: s->mtime = xp->mtime;
2650:
2651: s->mdate = xp->mdate;
2652:
2653: text_reg = s;
2654:
2655: TRACE(("shared text region %lx created", m));
2656:
2657: return m;
1.1 root 2658:
2659: }
2660:
2661:
2662:
2663: /*
2664:
2665: * exec_region(p, mem, thread): create a child process out of a mem region
2666:
2667: * "p" is the process structure set up by the parent; it may be "curproc",
2668:
2669: * if we're overlaying. "mem" is the loaded memory region returned by
2670:
2671: * "load region". Any open files (other than the standard handles) owned
2672:
2673: * by "p" are closed, and if thread !=0 all memory is released; the caller
2674:
2675: * must explicitly attach the environment and base region. The caller must
2676:
2677: * also put "p" on the appropriate queue (most likely READY_Q).
2678:
2679: */
2680:
2681:
2682:
2683: extern long mint_dos(), mint_bios();
2684:
2685:
2686:
2687: void rts() {} /* dummy termination routine */
2688:
2689:
2690:
2691: PROC *
2692:
2693: exec_region(p, mem, thread)
2694:
2695: PROC *p;
2696:
2697: MEMREGION *mem;
2698:
2699: int thread;
2700:
2701: {
2702:
2703: BASEPAGE *b;
2704:
2705: FILEPTR *f;
2706:
2707: int i;
2708:
2709: MEMREGION *m;
2710:
2711:
2712:
1.1.1.2 root 2713: TRACE(("exec_region"));
1.1 root 2714:
2715:
2716:
2717: b = (BASEPAGE *) mem->loc;
2718:
2719:
2720:
1.1.1.2 root 2721: cpush((void *)b->p_tbase, b->p_tlen); /* flush cached versions of the text */
2722:
2723:
2724:
1.1 root 2725: /* set some (undocumented) variables in the basepage */
2726:
2727: b->p_defdrv = p->curdrv;
2728:
2729: for (i = 0; i < 6; i++)
2730:
2731: b->p_devx[i] = i;
2732:
2733:
2734:
2735: p->dta = (DTABUF *)(b->p_dta = &b->p_cmdlin[0]);
2736:
2737: p->base = b;
2738:
2739:
2740:
2741: /* close extra open files */
2742:
2743: for (i = MIN_OPEN; i < MAX_OPEN; i++) {
2744:
1.1.1.2 root 2745: if ( (f = p->handle[i]) != 0 && (p->fdflags[i] & FD_CLOEXEC) ) {
1.1 root 2746:
2747: do_pclose(p, f);
2748:
2749: p->handle[i] = 0;
2750:
2751: }
2752:
2753: }
2754:
2755:
2756:
2757: /* initialize memory */
2758:
2759: recalc_maxmem(p);
2760:
2761: if (p->maxmem) {
2762:
2763: shrink_region(mem, p->maxmem);
2764:
2765: b->p_hitpa = b->p_lowtpa + mem->len;
2766:
2767: }
2768:
2769:
2770:
2771: p->memflags = b->p_flags;
2772:
2773:
2774:
2775: if (!thread) {
2776:
2777: for (i = 0; i < p->num_reg; i++) {
2778:
2779: m = p->mem[i];
2780:
2781: if (m) {
2782:
2783: m->links--;
2784:
2785: if (m->links <= 0)
2786:
2787: free_region(m);
2788:
2789: }
2790:
2791: }
2792:
2793: if (p->num_reg > NUM_REGIONS) {
2794:
1.1.1.3 root 2795: /*
2796:
2797: * If the proc struct has a larger mem array than
2798:
2799: * the default, then free it and allocate a
2800:
2801: * default-sized one.
2802:
2803: */
1.1 root 2804:
2805:
2806:
1.1.1.3 root 2807: /*
1.1 root 2808:
1.1.1.3 root 2809: * hoo ha! Memory protection problem here. Use
2810:
2811: * temps and pre-clear p->mem so memprot doesn't try
2812:
2813: * to walk these structures as we're freeing and
2814:
2815: * reallocating them! (Calling kmalloc can cause
2816:
2817: * a table walk if the alloc results in calling
2818:
2819: * get_region.)
2820:
2821: */
2822:
2823: void *pmem, *paddr;
2824:
2825:
2826:
2827: pmem = p->mem;
2828:
2829: paddr = p->addr;
2830:
2831: p->mem = NULL; p->addr = NULL;
2832:
2833: kfree(pmem); kfree(paddr);
2834:
2835:
2836:
2837: pmem = kmalloc(NUM_REGIONS * SIZEOF(MEMREGION *));
2838:
2839: paddr = kmalloc(NUM_REGIONS * SIZEOF(virtaddr));
2840:
2841: assert(pmem && paddr);
2842:
2843: p->mem = pmem;
2844:
2845: p->addr = paddr;
1.1 root 2846:
2847: p->num_reg = NUM_REGIONS;
2848:
2849: }
2850:
2851: zero((char *)p->mem, (p->num_reg)*SIZEOF(MEMREGION *));
2852:
2853: zero((char *)p->addr, (p->num_reg)*SIZEOF(virtaddr));
2854:
2855: }
2856:
2857:
2858:
2859: /* initialize signals */
2860:
2861: p->sigmask = 0;
2862:
2863: for (i = 0; i < NSIG; i++) {
2864:
2865: if (p->sighandle[i] != SIG_IGN) {
2866:
2867: p->sighandle[i] = SIG_DFL;
2868:
2869: p->sigflags[i] = 0;
2870:
2871: p->sigextra[i] = 0;
2872:
2873: }
2874:
2875: }
2876:
2877:
2878:
2879: /* zero the user registers, and set the FPU in a "clear" state */
2880:
2881: for (i = 0; i < 15; i++)
2882:
2883: p->ctxt[CURRENT].regs[i] = 0;
2884:
2885: p->ctxt[CURRENT].sr = 0;
2886:
2887: p->ctxt[CURRENT].fstate[0] = 0;
2888:
2889:
2890:
2891: /* set PC, stack registers, etc. appropriately */
2892:
2893: p->ctxt[CURRENT].pc = b->p_tbase;
2894:
2895:
2896:
2897: /* The "-0x20" is to make sure that syscall.s won't run past the end of
2898:
2899: * memory when the user makes a system call and doesn't push very many
2900:
2901: * parameters -- syscall always tries to copy the maximum possible number
2902:
2903: * of parms.
2904:
2905: *
2906:
2907: * NOTE: there's a sanity check here in case programs Mshrink a basepage
2908:
2909: * without fixing the p_hitpa field in the basepage; this is to ensure
2910:
2911: * compatibility with older versions of MiNT, which ignore p_hitpa.
2912:
2913: */
2914:
2915: if (valid_address(b->p_hitpa - 0x20))
2916:
2917: p->ctxt[CURRENT].usp = b->p_hitpa - 0x20;
2918:
2919: else
2920:
2921: p->ctxt[CURRENT].usp = mem->loc + mem->len - 0x20;
2922:
2923:
2924:
2925: p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
2926:
2927: p->ctxt[CURRENT].term_vec = (long)rts;
2928:
2929:
2930:
2931: /* set up stack for process */
2932:
2933: *((long *)(p->ctxt[CURRENT].usp + 4)) = (long) b;
2934:
2935:
2936:
2937: /* check for a valid text region. some compilers (e.g. Lattice 3) just throw
2938:
2939: everything into the text region, including data; fork() must be careful
2940:
2941: to save the whole region, then. We assume that if the compiler (or
2942:
2943: assembler, or whatever) goes to the trouble of making separate text, data,
2944:
2945: and bss regions, then the text region is code and isn't modified and
2946:
2947: fork doesn't have to save it.
2948:
2949: */
2950:
1.1.1.2 root 2951: if (b->p_blen != 0 || b->p_dlen != 0)
1.1 root 2952:
2953: p->txtsize = b->p_tlen;
2954:
2955: else
2956:
2957: p->txtsize = 0;
2958:
2959:
2960:
2961: /*
2962:
2963: * An ugly hack: dLibs tries to poke around in the parent's address space
2964:
2965: * to find stuff. For now, we'll allow this by faking a pointer into
2966:
2967: * the parent's address space in the place in the basepage where dLibs is
2968:
2969: * expecting it. This ugly hack only works correctly if the Pexec'ing
2970:
2971: * program (i.e. curproc) is in user mode.
2972:
2973: */
2974:
1.1.1.2 root 2975: if (curproc != rootproc)
2976:
2977: curproc->base->p_usp = curproc->ctxt[SYSCALL].usp - 0x32;
1.1 root 2978:
2979:
2980:
2981: return p;
2982:
2983: }
2984:
2985:
2986:
2987: /*
2988:
2989: * misc. utility routines
2990:
2991: */
2992:
2993:
2994:
2995: /*
2996:
2997: * long memused(p): return total memory allocated to process p
2998:
2999: */
3000:
3001:
3002:
3003: long
3004:
3005: memused(p)
3006:
3007: PROC *p;
3008:
3009: {
3010:
3011: int i;
3012:
3013: long size;
3014:
3015:
3016:
1.1.1.3 root 3017: /* a ZOMBIE owns no memory and its mem array ptr is zero */
3018:
3019: if (p->mem == NULL) return 0;
3020:
3021:
3022:
1.1 root 3023: size = 0;
3024:
3025: for (i = 0; i < p->num_reg; i++) {
3026:
3027: if (p->mem[i])
3028:
3029: size += p->mem[i]->len;
3030:
3031: }
3032:
3033: return size;
3034:
3035: }
3036:
3037:
3038:
3039: /*
3040:
3041: * recalculate the maximum memory limit on a process; this limit depends
3042:
3043: * on the max. allocated memory and max. total memory limits set by
3044:
3045: * p_setlimit (see dos.c), and (perhaps) on the size of the program
3046:
3047: * that the process is executing. whenever any of these things
3048:
3049: * change (through p_exec or p_setlimit) this routine must be called
3050:
3051: */
3052:
3053:
3054:
3055: void
3056:
3057: recalc_maxmem(p)
3058:
3059: PROC *p;
3060:
3061: {
3062:
3063: BASEPAGE *b;
3064:
3065: long siz;
3066:
3067:
3068:
3069: b = (BASEPAGE *)p->base;
3070:
3071: if (b)
3072:
3073: siz = b->p_tlen + b->p_dlen + b->p_blen;
3074:
3075: else
3076:
3077: siz = 0;
3078:
3079: p->maxmem = 0;
3080:
3081: if (p->maxdata) {
3082:
3083: p->maxmem = p->maxdata + siz;
3084:
3085: }
3086:
3087:
3088:
3089: if (p->maxcore) {
3090:
3091: if (p->maxmem == 0 || p->maxmem > p->maxcore)
3092:
3093: p->maxmem = p->maxcore;
3094:
3095: }
3096:
3097: if (p->maxmem && p->maxmem < siz)
3098:
3099: p->maxmem = siz;
3100:
3101: }
3102:
3103:
3104:
3105: /*
3106:
3107: * valid_address: checks to see if the indicated address falls within
3108:
3109: * memory attached to the current process
3110:
3111: */
3112:
3113:
3114:
3115: int
3116:
3117: valid_address(addr)
3118:
3119: long addr;
3120:
3121: {
3122:
3123: int i;
3124:
3125: MEMREGION *m;
3126:
3127:
3128:
3129: for (i = 0; i < curproc->num_reg; i++) {
3130:
3131: if ((m = curproc->mem[i]) != 0) {
3132:
3133: if (addr >= m->loc && addr <= m->loc + m->len)
3134:
3135: return 1;
3136:
3137: }
3138:
3139: }
3140:
3141: return 0;
3142:
3143: }
3144:
3145:
3146:
3147: /*
3148:
1.1.1.3 root 3149: * convert an address to a memory region; this works only in
3150:
3151: * the ST RAM and TT RAM maps, and will fail for memory that
3152:
3153: * MiNT doesn't own or which is virtualized
3154:
3155: */
3156:
3157:
3158:
3159: MEMREGION *
3160:
3161: addr2region(addr)
3162:
3163: long addr;
3164:
3165: {
3166:
3167: unsigned long ua = (unsigned long) addr;
3168:
3169:
3170:
3171: extern ulong mint_top_st, mint_top_tt;
3172:
3173: MEMREGION *r;
3174:
3175: MMAP map;
3176:
3177:
3178:
3179: if (ua < mint_top_st) {
3180:
3181: map = core;
3182:
3183: } else if (ua < mint_top_tt) {
3184:
3185: map = alt;
3186:
3187: } else {
3188:
3189: return 0;
3190:
3191: }
3192:
3193:
3194:
3195: for (r = *map; r; r = r->next) {
3196:
3197: if (addr >= r->loc && addr < r->loc + r->len)
3198:
3199: return r;
3200:
3201: }
3202:
3203: return 0;
3204:
3205: }
3206:
3207:
3208:
3209: /*
3210:
1.1 root 3211: * some debugging stuff
3212:
3213: */
3214:
3215:
3216:
3217: void
3218:
1.1.1.3 root 3219: DUMP_ALL_MEM()
3220:
3221: {
3222:
3223: DUMPMEM(ker);
3224:
3225: DUMPMEM(core);
3226:
3227: DUMPMEM(alt);
3228:
3229: }
3230:
3231:
3232:
3233: void
3234:
1.1 root 3235: DUMPMEM(map)
3236:
3237: MMAP map;
3238:
3239: {
3240:
1.1.1.4 ! root 3241: #ifdef DEBUG_INFO
1.1.1.2 root 3242:
1.1 root 3243: MEMREGION *m;
3244:
3245:
3246:
3247: m = *map;
3248:
1.1.1.3 root 3249: FORCE("%s memory dump: starting at region %lx",
3250:
3251: (map == ker ? "ker" : (map == core ? "core" : "alt")), m);
1.1 root 3252:
3253: while (m) {
3254:
1.1.1.3 root 3255: FORCE("%ld bytes at %lx (%d links); next region %lx", m->len, m->loc,
1.1 root 3256:
1.1.1.3 root 3257: m->links, m->next);
1.1 root 3258:
1.1.1.3 root 3259: m = m->next;
1.1 root 3260:
3261: }
3262:
1.1.1.4 ! root 3263: #else
! 3264:
! 3265: UNUSED(map);
! 3266:
1.1.1.2 root 3267: #endif
3268:
1.1 root 3269: }
3270:
3271:
3272:
3273: void
3274:
3275: sanity_check(map)
3276:
3277: MMAP map;
3278:
3279: {
3280:
3281: #ifdef SANITY_CHECK
3282:
3283: MEMREGION *m, *nxt;
3284:
3285: long end;
3286:
3287:
3288:
3289: m = *map;
3290:
3291: while (m) {
3292:
3293: nxt = m->next;
3294:
3295: if (nxt) {
3296:
3297: end = m->loc + m->len;
3298:
3299: if (m->loc < nxt->loc && end > nxt->loc) {
3300:
3301: FATAL("MEMORY CHAIN CORRUPTED");
3302:
3303: }
3304:
3305: else if (end == nxt->loc && ISFREE(m) && ISFREE(nxt)) {
3306:
3307: ALERT("Continguous memory regions not merged!");
3308:
3309: }
3310:
3311: }
3312:
3313: m = nxt;
3314:
3315: }
3316:
1.1.1.2 root 3317: #else
3318:
3319: UNUSED(map);
3320:
1.1 root 3321: #endif
3322:
3323: }
3324:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.