|
|
1.1 root 1: /*
2:
3: Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
4:
5: */
6:
7:
8:
9: /*
10:
11: * mem.c:: routines for managing memory regions
12:
13: */
14:
15:
16:
17: #include "mint.h"
18:
19:
20:
21: static long core_malloc P_((long, int));
22:
23:
24:
25: /* macro for testing whether a memory region is free */
26:
27: #define ISFREE(m) ((m)->links == 0)
28:
29:
30:
31: /*
32:
33: * initialize memory routines
34:
35: */
36:
37:
38:
39: /* initial number of memory regions */
40:
41: #define NREGIONS 512
42:
43:
44:
45: /* number of new regions to allocate when the initial ones are used up */
46:
47: #define NEWREGIONS 256
48:
49:
50:
51: static MEMREGION use_regions[NREGIONS+1];
52:
53: MEMREGION *rfreelist;
54:
55:
56:
57: void
58:
59: init_mem()
60:
61: {
62:
63: int i;
64:
65:
66:
67: use_regions[NREGIONS].next = 0;
68:
69: for (i = 0; i < NREGIONS; i++) {
70:
71: use_regions[i].next = &use_regions[i+1];
72:
73: }
74:
75: rfreelist = use_regions;
76:
77:
78:
79: init_core();
80:
81: init_swap();
82:
83: }
84:
85:
86:
87: /*
88:
89: * init_core(): initialize the core memory map (normal ST ram) and also
90:
91: * the alternate memory map (fast ram on the TT)
92:
93: */
94:
95:
96:
97: static MEMREGION *_core_regions = 0, *_alt_regions = 0,
98:
99: *_ker_regions = 0;
100:
101:
102:
103: MMAP core = &_core_regions;
104:
105: MMAP alt = &_alt_regions;
106:
107: MMAP ker = &_ker_regions;
108:
109:
110:
111: /* note: add_region must adjust both the size and starting
112:
113: * address of the region being added so that memory is
114:
115: * always properly aligned
116:
117: */
118:
119:
120:
121: int
122:
123: add_region(map, place, size, mflags)
124:
125: MMAP map;
126:
127: ulong place, size;
128:
129: unsigned mflags; /* initial flags for region */
130:
131: {
132:
133: MEMREGION *m;
134:
135: ulong newplace;
136:
137:
138:
139: newplace = ROUND(place);
140:
141: size = (place + size) - newplace;
142:
143: size &= ~MASKBITS;
144:
145: if (size <= 0) /* region too small to use */
146:
147: return 1;
148:
149:
150:
151: m = new_region();
152:
153: if (m == 0)
154:
155: return 0; /* failure */
156:
157: m->links = 0;
158:
159: m->len = size;
160:
161: m->loc = newplace;
162:
163: m->next = *map;
164:
165: m->mflags = mflags;
166:
167: *map = m;
168:
169: return 1; /* success */
170:
171: }
172:
173:
174:
175: static long
176:
177: core_malloc(amt, mode)
178:
179: long amt;
180:
181: int mode;
182:
183: {
184:
185: static int mxalloc = -1; /* does GEMDOS know about Mxalloc? */
186:
187: long ret;
188:
189:
190:
191: if (mxalloc < 0) {
192:
193: ret = (long)Mxalloc(-1L, 0);
194:
195: if (ret == -32) mxalloc = 0; /* unknown function */
196:
197: else if (ret >= 0) mxalloc = 1;
198:
199: else {
200:
201: ALERT("GEMDOS returned %ld from Mxalloc", ret);
202:
203: mxalloc = 0;
204:
205: }
206:
207: }
208:
209: if (mxalloc)
210:
211: return Mxalloc(amt, mode);
212:
213: else if (mode == 1)
214:
215: return 0L;
216:
217: else
218:
219: return Malloc(amt);
220:
221: }
222:
223:
224:
225: void
226:
227: init_core()
228:
229: {
230:
231: #ifdef JUNK_MEM
232:
233: extern void fillwjunk();
234:
235: #endif
236:
237: ulong size;
238:
239: ulong place;
240:
241: void *tossave;
242:
243:
244:
245: tossave = (void *)core_malloc((long)TOS_MEM, 0);
246:
247: if (!tossave) {
248:
249: FATAL("Not enough memory to run MiNT");
250:
251: }
252:
253:
254:
255: /* initialize kernel memory */
256:
257: place = (ulong)core_malloc(KERNEL_MEM, 3);
258:
259: if (place != 0) {
260:
261: (void)add_region(ker, place, KERNEL_MEM, M_KER);
262:
263: #ifdef JUNK_MEM
264:
265: fillwjunk(place, (long)KERNEL_MEM);
266:
267: #endif
268:
269: }
270:
271:
272:
273: /* initialize ST RAM */
274:
275: size = (ulong)core_malloc(-1L, 0);
276:
277: while (size > 0) {
278:
279: place = (ulong)core_malloc(size, 0);
280:
281: if (!add_region(core, place, size, M_CORE))
282:
283: FATAL("init_mem: unable to add a region");
284:
285: #ifdef JUNK_MEM
286:
287: fillwjunk(place, size);
288:
289: #endif
290:
291: size = (ulong)core_malloc(-1L, 0);
292:
293: }
294:
295:
296:
297: /* initialize alternate RAM */
298:
299: size = (ulong)core_malloc(-1L, 1);
300:
301: while (size > 0) {
302:
303: place = (ulong)core_malloc(size, 1);
304:
305: if (!add_region(alt, place, size, M_ALT))
306:
307: FATAL("init_mem: unable to add a region");
308:
309: size = (ulong)core_malloc(-1L, 1);
310:
311: }
312:
313:
314:
315: (void)Mfree(tossave); /* leave some memory for TOS to use */
316:
317: }
318:
319:
320:
321: /*
322:
323: * init_swap(): initialize the swap area; for now, this does nothing
324:
325: */
326:
327:
328:
329: MEMREGION *_swap_regions = 0;
330:
331: MMAP swap = &_swap_regions;
332:
333:
334:
335: void
336:
337: init_swap()
338:
339: {
340:
341: }
342:
343:
344:
345: /*
346:
347: * routines for allocating/deallocating memory regions
348:
349: */
350:
351:
352:
353: /*
354:
355: * new_region returns a new memory region descriptor, or NULL
356:
357: */
358:
359:
360:
361: MEMREGION *
362:
363: new_region()
364:
365: {
366:
367: MEMREGION *m, *newfrees;
368:
369: int i;
370:
371:
372:
373: m = rfreelist;
374:
375: if (!m) {
376:
377: ALERT("new_region: ran out of free regions");
378:
379: return 0;
380:
381: }
382:
383: assert(ISFREE(m));
384:
385: rfreelist = m->next;
386:
387: m->next = 0;
388:
389:
390:
391: /* if we're running low on free regions, allocate some more
392:
393: * we have to do this with at least 1 free region left so that get_region
394:
395: * has a chance of working
396:
397: */
398:
399: if (rfreelist && !rfreelist->next) {
400:
401: MEMREGION *newstuff;
402:
403:
404:
405: TRACE("get_region: getting new region descriptors");
406:
407: newstuff = get_region(ker, NEWREGIONS*SIZEOF(MEMREGION));
408:
409: if (!newstuff)
410:
411: newstuff = get_region(alt,NEWREGIONS*SIZEOF(MEMREGION));
412:
413: if (!newstuff)
414:
415: newstuff = get_region(core, NEWREGIONS*SIZEOF(MEMREGION));
416:
417: newfrees = newstuff ? (MEMREGION *)newstuff->loc : 0;
418:
419: if (newfrees) {
420:
421: newfrees[NEWREGIONS-1].next = 0;
422:
423: newfrees[NEWREGIONS-1].links = 0;
424:
425: for (i = 0; i < NEWREGIONS-1; i++) {
426:
427: newfrees[i].next = &newfrees[i+1];
428:
429: newfrees[i].links = 0;
430:
431: }
432:
433: rfreelist = newfrees;
434:
435: } else {
436:
437: DEBUG("couldn't get new region descriptors!");
438:
439: }
440:
441: }
442:
443:
444:
445: return m;
446:
447: }
448:
449:
450:
451: /*
452:
453: * dispose_region destroys a memory region descriptor
454:
455: */
456:
457:
458:
459: void
460:
461: dispose_region(m)
462:
463: MEMREGION *m;
464:
465: {
466:
467: assert(ISFREE(m));
468:
469: m->next = rfreelist;
470:
471: rfreelist = m;
472:
473: }
474:
475:
476:
477: /*
478:
479: * virtaddr
480:
481: * attach_region(proc, reg): attach the region to the given process:
482:
483: * returns the address at which it was attached, or NULL if the process
484:
485: * cannot attach more regions. The region link count is incremented if
486:
487: * the attachment is successful.
488:
489: */
490:
491:
492:
493: virtaddr
494:
495: attach_region(proc, reg)
496:
497: PROC *proc;
498:
499: MEMREGION *reg;
500:
501: {
502:
503: int i;
504:
505: MEMREGION **newmem;
506:
507: virtaddr *newaddr;
508:
509:
510:
511: if (!reg || !reg->loc) {
512:
513: ALERT("attach_region: attaching a null region??");
514:
515: return 0;
516:
517: }
518:
519: for (i = 0; i < proc->num_reg; i++) {
520:
521: if (!proc->mem[i]) {
522:
523: assert(proc->addr[i] == 0);
524:
525: reg->links++;
526:
527: proc->mem[i] = reg;
528:
529: proc->addr[i] = (virtaddr) reg->loc;
530:
531: return proc->addr[i];
532:
533: }
534:
535: }
536:
537:
538:
539: /* Hmmm, OK, we have to expand the process' memory table */
540:
541: TRACE("Expanding process memory table");
542:
543: i = proc->num_reg + NUM_REGIONS;
544:
545:
546:
547: newmem = kmalloc(i * SIZEOF(MEMREGION *));
548:
549: newaddr = kmalloc(i * SIZEOF(virtaddr));
550:
551:
552:
553: if (newmem && newaddr) {
554:
555: /* copy over the old address mapping */
556:
557: for (i = 0; i < proc->num_reg; i++) {
558:
559: newmem[i] = proc->mem[i];
560:
561: newaddr[i] = proc->addr[i];
562:
563: if (newmem[i] == 0)
564:
565: assert(newaddr[i] == 0);
566:
567: }
568:
569: /* initialize the rest of the tables */
570:
571: for(; i < proc->num_reg + NUM_REGIONS; i++) {
572:
573: newmem[i] = 0;
574:
575: newaddr[i] = 0;
576:
577: }
578:
579: /* free the old tables */
580:
581: kfree(proc->mem); kfree(proc->addr);
582:
583: proc->mem = newmem;
584:
585: proc->addr = newaddr;
586:
587: proc->num_reg += NUM_REGIONS;
588:
589: /* this call will succeed */
590:
591: TRACE("recursively calling attach_region");
592:
593: return attach_region(proc, reg);
594:
595: }
596:
597:
598:
599: DEBUG("attach_region: failed");
600:
601: return 0;
602:
603: }
604:
605:
606:
607: /*
608:
609: * detach_region(proc, reg): remove region from the procedure's address
610:
611: * space. If no more processes reference the region, return it to the
612:
613: * system. Note that we search backwards, so that the most recent
614:
615: * attachment of memory gets detached!
616:
617: */
618:
619:
620:
621: void
622:
623: detach_region(proc, reg)
624:
625: PROC *proc;
626:
627: MEMREGION *reg;
628:
629: {
630:
631: int i;
632:
633:
634:
635: if (!reg) return;
636:
637: for (i = proc->num_reg - 1; i >= 0; i--) {
638:
639: if (proc->mem[i] == reg) {
640:
641: reg->links--;
642:
643: proc->mem[i] = 0; proc->addr[i] = 0;
644:
645: if (reg->links == 0) {
646:
647: free_region(reg);
648:
649: }
650:
651: return;
652:
653: }
654:
655: }
656:
657: DEBUG("detach_region: region not attached");
658:
659: }
660:
661:
662:
663: /*
664:
665: * get_region(MMAP map, ulong size) -- allocate a new region of the
666:
667: * given size in the given memory map. if no region big enough is available,
668:
669: * return NULL, otherwise return a pointer to the region.
670:
671: * the "links" field in the region is set to 1
672:
673: *
674:
675: * BEWARE: new_region may call get_region (indirectly), so we have to be
676:
677: * _very_ careful with re-entrancy in this function
678:
679: */
680:
681:
682:
683: MEMREGION *
684:
685: get_region(map, size)
686:
687: MMAP map;
688:
689: ulong size;
690:
691: {
692:
693: MEMREGION *m, *n;
694:
695:
696:
697: /* precautionary measures */
698:
699: if (size == 0) {
700:
701: DEBUG("request for 0 bytes??");
702:
703: size = 1;
704:
705: }
706:
707:
708:
709: size = ROUND(size);
710:
711:
712:
713: n = *map;
714:
715:
716:
717: sanity_check(map);
718:
719: /* exact matches are likely to be rare, so we pre-allocate a new
720:
721: * region here; this helps us to avoid re-entrancy problems
722:
723: * when new_region calls get_region
724:
725: */
726:
727: m = new_region();
728:
729:
730:
731: while (n) {
732:
733: if (ISFREE(n)) {
734:
735: if (n->len == size) {
736:
737: if (m) dispose_region(m);
738:
739: n->links++;
740:
741: return n;
742:
743: }
744:
745: else if (n->len > size) {
746:
747: /* split a new region, 'm', which will contain the free bytes after n */
748:
749: if (m) {
750:
751: m->next = n->next;
752:
753: n->next = m;
754:
755: m->mflags = n->mflags & M_MAP;
756:
757: m->loc = n->loc + size;
758:
759: m->len = n->len - size;
760:
761: n->len = size;
762:
763: n->links++;
764:
765: return n;
766:
767: } else {
768:
769: DEBUG("get_region: no regions left");
770:
771: return 0;
772:
773: }
774:
775: }
776:
777: }
778:
779: n = n->next;
780:
781: }
782:
783:
784:
785: if (m)
786:
787: dispose_region(m);
788:
789: return NULL;
790:
791: }
792:
793:
794:
795: /*
796:
797: * free_region(MEMREGION *reg): free the indicated region. The map
798:
799: * in which the region is contained is given by reg->mflags.
800:
801: * the caller is responsible for making sure that the region
802:
803: * really should be freed, i.e. that reg->links == 0.
804:
805: */
806:
807:
808:
809: void
810:
811: free_region(reg)
812:
813: MEMREGION *reg;
814:
815: {
816:
817: MMAP map;
818:
819: MEMREGION *m;
820:
821:
822:
823: if (!reg) return;
824:
825:
826:
827: assert(ISFREE(reg));
828:
829:
830:
831: if (reg->mflags & M_CORE)
832:
833: map = core;
834:
835: else if (reg->mflags & M_ALT)
836:
837: map = alt;
838:
839: else if (reg->mflags & M_KER)
840:
841: map = ker;
842:
843: else {
844:
845: FATAL("free_region: region flags not valid (%x)", reg->mflags);
846:
847: }
848:
849: reg->mflags &= M_MAP;
850:
851: m = *map;
852:
853: assert(m);
854:
855:
856:
857: if (m == reg) goto merge_after;
858:
859:
860:
861: /* merge previous region if it's free and contiguous with 'reg' */
862:
863:
864:
865: /* first, we find the region */
866:
867: while (m && m->next != reg)
868:
869: m = m->next;
870:
871:
872:
873: assert(m != NULL);
874:
875:
876:
877: if (ISFREE(m) && (m->loc + m->len == reg->loc)) {
878:
879: m->len += reg->len;
880:
881: assert(m->next == reg);
882:
883: m->next = reg->next;
884:
885: reg->next = 0;
886:
887: dispose_region(reg);
888:
889: reg = m;
890:
891: }
892:
893:
894:
895: /* merge next region if it's free and contiguous with 'reg' */
896:
897: merge_after:
898:
899: m = reg->next;
900:
901: if (m && ISFREE(m) && reg->loc + reg->len == m->loc) {
902:
903: reg->len += m->len;
904:
905: reg->next = m->next;
906:
907: m->next = 0;
908:
909: dispose_region(m);
910:
911: }
912:
913:
914:
915: sanity_check(map);
916:
917: }
918:
919:
920:
921: /*
922:
923: * shrink_region(MEMREGION *reg, ulong newsize):
924:
925: * shrink region 'reg', so that it is now 'newsize' bytes long.
926:
927: * if 'newsize' is bigger than the region's current size, return EGSBF;
928:
929: * otherwise return 0.
930:
931: */
932:
933:
934:
935: long
936:
937: shrink_region(reg, newsize)
938:
939: MEMREGION *reg;
940:
941: ulong newsize;
942:
943: {
944:
945: MMAP map;
946:
947: MEMREGION *n;
948:
949: ulong diff;
950:
951:
952:
953:
954:
955: newsize = ROUND(newsize);
956:
957:
958:
959: assert(reg->links > 0);
960:
961:
962:
963: if (reg->mflags & M_CORE)
964:
965: map = core;
966:
967: else if (reg->mflags & M_ALT)
968:
969: map = alt;
970:
971: else if (reg->mflags & M_KER)
972:
973: map = ker;
974:
975: else {
976:
977: FATAL("shrink_region: bad region flags (%x)", reg->mflags);
978:
979: }
980:
981:
982:
983: /* shrinking to 0 is the same as freeing */
984:
985: if (newsize == 0) {
986:
987: detach_region(curproc, reg);
988:
989: return 0;
990:
991: }
992:
993:
994:
995: /* if new size is the same as old size, don't do anything */
996:
997: if (newsize == reg->len) {
998:
999: return 0; /* nothing to do */
1000:
1001: }
1002:
1003:
1004:
1005: if (newsize > reg->len) {
1006:
1007: DEBUG("shrink_region: request to make region bigger");
1008:
1009: return EGSBF; /* growth failure */
1010:
1011: }
1012:
1013:
1014:
1015: /* OK, we're going to free (reg->len - newsize) bytes at the end of
1016:
1017: this block. If the block after us is already free, simply add the
1018:
1019: space to that block.
1020:
1021: */
1022:
1023: n = reg->next;
1024:
1025: diff = reg->len - newsize;
1026:
1027:
1028:
1029: if (n && ISFREE(n) && reg->loc + reg->len == n->loc) {
1030:
1031: reg->len = newsize;
1032:
1033: n->loc -= diff;
1034:
1035: n->len += diff;
1036:
1037: return 0;
1038:
1039: }
1040:
1041: else {
1042:
1043: n = new_region();
1044:
1045: if (!n) {
1046:
1047: DEBUG("shrink_region: new_region failed");
1048:
1049: return EINTRN;
1050:
1051: }
1052:
1053: reg->len = newsize;
1054:
1055: n->loc = reg->loc + newsize;
1056:
1057: n->len = diff;
1058:
1059: n->mflags = reg->mflags & M_MAP;
1060:
1061: n->next = reg->next;
1062:
1063: reg->next = n;
1064:
1065: }
1066:
1067: return 0;
1068:
1069: }
1070:
1071:
1072:
1073: /*
1074:
1075: * max_rsize(map): return the length of the biggest free region
1076:
1077: * in the given memory map, or 0 if no regions remain.
1078:
1079: */
1080:
1081:
1082:
1083: long
1084:
1085: max_rsize(map)
1086:
1087: MMAP map;
1088:
1089: {
1090:
1091: MEMREGION *m, *max = 0;
1092:
1093: long size = 0;
1094:
1095:
1096:
1097: for (m = *map; m; m = m->next) {
1098:
1099: if (ISFREE(m)) {
1100:
1101: if (m->len > size) {
1102:
1103: max = m;
1104:
1105: size = m->len;
1106:
1107: }
1108:
1109: }
1110:
1111: }
1112:
1113: return size;
1114:
1115: }
1116:
1117:
1118:
1119: /*
1120:
1121: * tot_rsize(map, flag): if flag == 1, return the total number of bytes in
1122:
1123: * the given memory map; if flag == 0, return only the number of free
1124:
1125: * bytes
1126:
1127: */
1128:
1129:
1130:
1131: long
1132:
1133: tot_rsize(map, flag)
1134:
1135: MMAP map;
1136:
1137: int flag;
1138:
1139: {
1140:
1141: MEMREGION *m;
1142:
1143: long size = 0;
1144:
1145:
1146:
1147: for (m = *map; m; m = m->next) {
1148:
1149: if (flag || ISFREE(m)) {
1150:
1151: size += m->len;
1152:
1153: }
1154:
1155: }
1156:
1157: return size;
1158:
1159: }
1160:
1161:
1162:
1163: /*
1164:
1165: * alloc_region(MMAP map, ulong size): allocate a new region and attach
1166:
1167: * it to the current process; returns the address at which the region
1168:
1169: * was attached, or NULL. If not enough memory is found, wait a bit
1170:
1171: * and try again before giving up (maybe someone else will free some
1172:
1173: * memory)
1174:
1175: */
1176:
1177:
1178:
1179: virtaddr
1180:
1181: alloc_region(map, size)
1182:
1183: MMAP map;
1184:
1185: ulong size;
1186:
1187: {
1188:
1189: MEMREGION *m;
1190:
1191: PROC *proc = curproc;
1192:
1193: virtaddr v;
1194:
1195:
1196:
1197: m = get_region(map, size);
1198:
1199: if (!m) {
1200:
1201: return 0;
1202:
1203: }
1204:
1205:
1206:
1207: v = attach_region(proc, m);
1208:
1209: /* NOTE: get_region returns a region with link count 1; since attach_region
1210:
1211: * increments the link count, we restore it after calling attach_region
1212:
1213: */
1214:
1215: m->links = 1;
1216:
1217: if (!v) {
1218:
1219: m->links = 0;
1220:
1221: free_region(m);
1222:
1223: return 0;
1224:
1225: }
1226:
1227: return v;
1228:
1229: }
1230:
1231:
1232:
1233: /*
1234:
1235: * routines for creating a copy of an environment, and a new basepage.
1236:
1237: * note that the memory regions created should immediately be attached to
1238:
1239: * a process! Also note that create_env always operates in ST RAM, but
1240:
1241: * create_base might not.
1242:
1243: */
1244:
1245:
1246:
1247: MEMREGION *
1248:
1249: create_env(env)
1250:
1251: const char *env;
1252:
1253: {
1254:
1255: long size;
1256:
1257: MEMREGION *m;
1258:
1259: virtaddr v;
1260:
1261: const char *old;
1262:
1263: char *new;
1264:
1265:
1266:
1267: if (!env) {
1268:
1269: env = ((BASEPAGE *)curproc->base)->p_env;
1270:
1271: /* duplicate parent's environment */
1272:
1273: }
1274:
1275: size = 2;
1276:
1277: old = env;
1278:
1279: while (*env || *(env+1))
1280:
1281: env++,size++;
1282:
1283: v = alloc_region(core, size);
1284:
1285: if (!v) {
1286:
1287: DEBUG("create_env: alloc_region failed");
1288:
1289: return (MEMREGION *)0;
1290:
1291: }
1292:
1293: m = addr2mem(v);
1294:
1295:
1296:
1297: /* copy the old environment into the new */
1298:
1299: new = (char *) m->loc;
1300:
1301: while (size > 0) {
1302:
1303: *new++ = *old++;
1304:
1305: --size;
1306:
1307: }
1308:
1309: return m;
1310:
1311: }
1312:
1313:
1314:
1315: MEMREGION *
1316:
1317: create_base(cmd, env, flags, prgsize)
1318:
1319: const char *cmd;
1320:
1321: MEMREGION *env;
1322:
1323: ulong flags, prgsize;
1324:
1325: {
1326:
1327: long len, coresize, altsize;
1328:
1329: MMAP map;
1330:
1331: MEMREGION *m;
1332:
1333: BASEPAGE *b;
1334:
1335:
1336:
1337: /* if flags & F_ALTLOAD == 1, then we might decide to load in alternate
1338:
1339: RAM if enough is available. "enough" is: if more alt ram than ST ram,
1340:
1341: load there; otherwise, if more than (minalt+1)*128K alt ram available
1342:
1343: for heap space, load in alt ram ("minalt" is the high byte of flags)
1344:
1345: */
1346:
1347: if (flags & F_ALTLOAD) {
1348:
1349: coresize = max_rsize(core);
1350:
1351: altsize = max_rsize(alt);
1352:
1353: if (altsize >= coresize)
1354:
1355: map = alt;
1356:
1357: else {
1358:
1359: len = (flags & 0xf0000000) >> 28L;
1360:
1361: len = (len+1)*128*1024L + prgsize + 256;
1362:
1363: if (altsize >= len)
1364:
1365: map = alt;
1366:
1367: else
1368:
1369: map = core;
1370:
1371: }
1372:
1373: }
1374:
1375: else
1376:
1377: map = core;
1378:
1379:
1380:
1381: len = max_rsize(map);
1382:
1383:
1384:
1385: /* make sure that a little bit of memory is left over */
1386:
1387: if (len > 2*KEEP_MEM) {
1388:
1389: len -= KEEP_MEM;
1390:
1391: }
1392:
1393: m = addr2mem(alloc_region(map, len));
1394:
1395: if (!m) {
1396:
1397: DEBUG("create_base: alloc_region failed");
1398:
1399: return 0;
1400:
1401: }
1402:
1403: b = (BASEPAGE *)(m->loc);
1404:
1405:
1406:
1407: zero((char *)b, (long)sizeof(BASEPAGE));
1408:
1409: b->p_lowtpa = (long)b;
1410:
1411: b->p_hitpa = m->loc + m->len;
1412:
1413: b->p_env = (char *)env->loc;
1414:
1415: b->p_flags = flags;
1416:
1417:
1418:
1419: if (cmd)
1420:
1421: strncpy(b->p_cmdlin, cmd, 126);
1422:
1423: return m;
1424:
1425: }
1426:
1427:
1428:
1429: /*
1430:
1431: * load_region(filename): loads the program with the given file name
1432:
1433: * into a new region, and returns a pointer to that region. On an error,
1434:
1435: * returns 0 and leaves the error number in mint_errno.
1436:
1437: */
1438:
1439:
1440:
1441: static struct fileheader {
1442:
1443: short fmagic;
1444:
1445: long ftext;
1446:
1447: long fdata;
1448:
1449: long fbss;
1450:
1451: long fsym;
1452:
1453: long reserved;
1454:
1455: long flag;
1456:
1457: short reloc;
1458:
1459: } fh;
1460:
1461:
1462:
1463: MEMREGION *
1464:
1465: load_region(filename, env, cmdlin, xp)
1466:
1467: const char *filename;
1468:
1469: MEMREGION *env;
1470:
1471: const char *cmdlin;
1472:
1473: XATTR *xp; /* attributes for the file just loaded */
1474:
1475: {
1476:
1477: FILEPTR *f;
1478:
1479: DEVDRV *dev;
1480:
1481: MEMREGION *reg;
1482:
1483: BASEPAGE *b;
1484:
1485: long size, fixup, base, bytes_read;
1486:
1487: unsigned char c, *next;
1488:
1489: #define LRBUFSIZ 8196
1490:
1491: static unsigned char buffer[LRBUFSIZ];
1492:
1493: int trycount = 0;
1494:
1495:
1496:
1497: next = buffer;
1498:
1499:
1500:
1501: f = do_open(filename, O_DENYNONE | O_EXEC, 0, xp);
1502:
1503: if (!f) {
1504:
1505: return 0; /* mint_errno set by do_open */
1506:
1507: }
1508:
1509:
1510:
1511: dev = f->dev; /* could be different from fs */
1512:
1513: if ( (*dev->read)(f, (void *)&fh, (long)sizeof(fh)) != sizeof(fh) ||
1514:
1515: fh.fmagic != 0x601a ) {
1516:
1517: DEBUG("load_region: file not executable");
1518:
1519: mint_errno = ENOEXEC;
1520:
1521: failed:
1522:
1523: do_close(f);
1524:
1525: return 0;
1526:
1527: }
1528:
1529:
1530:
1531: size = fh.ftext + fh.fdata + fh.fbss;
1532:
1533: reg = 0;
1534:
1535: for (trycount = 0; (trycount < 1) && (reg == 0); trycount++) {
1536:
1537: reg = create_base(cmdlin, env, fh.flag, size);
1538:
1539: if (size+1024L > reg->len) {
1540:
1541: DEBUG("load_region: insufficient memory to load");
1542:
1543: detach_region(curproc, reg);
1544:
1545: reg = 0;
1546:
1547: }
1548:
1549: if (!reg) {
1550:
1551: /* maybe the memory shortage is short-term; sleep a bit to see */
1552:
1553: nap(10);
1554:
1555: }
1556:
1557: }
1558:
1559:
1560:
1561: if (reg == 0) {
1562:
1563: mint_errno = ENSMEM;
1564:
1565: goto failed;
1566:
1567: }
1568:
1569:
1570:
1571: b = (BASEPAGE *)reg->loc;
1572:
1573: b->p_flags = fh.flag;
1574:
1575: b->p_tbase = b->p_lowtpa + 256;
1576:
1577: b->p_tlen = fh.ftext;
1578:
1579: b->p_dbase = b->p_tbase + b->p_tlen;
1580:
1581: b->p_dlen = fh.fdata;
1582:
1583: b->p_bbase = b->p_dbase + b->p_dlen;
1584:
1585: size = (*dev->read)(f, (void *)b->p_tbase, fh.ftext+fh.fdata);
1586:
1587: if (size != fh.ftext + fh.fdata) {
1588:
1589: DEBUG("load_region: unexpected EOF");
1590:
1591: failed_reloc: /* come here when loading/relocation fails */
1592:
1593: mint_errno = ENOEXEC;
1594:
1595: detach_region(curproc, reg);
1596:
1597: goto failed;
1598:
1599: }
1600:
1601:
1602:
1603: b->p_blen = fh.fbss;
1604:
1605: if (fh.flag & F_FASTLOAD) /* fastload bit */
1606:
1607: size = b->p_blen;
1608:
1609: else
1610:
1611: size = b->p_hitpa - b->p_bbase;
1612:
1613: zero((char *)b->p_bbase, size);
1614:
1615: (*dev->lseek)(f, fh.fsym, SEEK_CUR); /* skip over symbol table */
1616:
1617: base = b->p_tbase;
1618:
1619:
1620:
1621: /* now read the relocation info; we use the temporary buffer provided
1622:
1623: * above to speed things up
1624:
1625: */
1626:
1627:
1628:
1629: if (fh.reloc == 0 && (*dev->read)(f, (char *)&fixup, 4L) && fixup) {
1630:
1631: fixup += base;
1632:
1633: size = LRBUFSIZ;
1634:
1635: bytes_read = 0;
1636:
1637: do {
1638:
1639: if (fixup >= b->p_hitpa) {
1640:
1641: DEBUG("load_region: bad relocation");
1642:
1643: goto failed_reloc;
1644:
1645: }
1646:
1647: else
1648:
1649: *((long *)fixup) += base;
1650:
1651: do {
1652:
1653: if (!bytes_read) {
1654:
1655: bytes_read =
1656:
1657: (*dev->read)(f,(char *)buffer,size);
1658:
1659: next = buffer;
1660:
1661: }
1662:
1663: if (bytes_read < 0) {
1664:
1665: DEBUG("load_region: EOF in relocation");
1666:
1667: goto failed_reloc;
1668:
1669: }
1670:
1671: else if (bytes_read == 0)
1672:
1673: c = 0;
1674:
1675: else {
1676:
1677: c = *next++; bytes_read--;
1678:
1679: }
1680:
1681: if (c == 1) fixup += 254;
1682:
1683: } while (c == 1);
1684:
1685: fixup += ( (unsigned) c) & 0xff;
1686:
1687: } while (c);
1688:
1689: }
1690:
1691:
1692:
1693: do_close(f);
1694:
1695: return reg;
1696:
1697: }
1698:
1699:
1700:
1701: /*
1702:
1703: * exec_region(p, mem, thread): create a child process out of a mem region
1704:
1705: * "p" is the process structure set up by the parent; it may be "curproc",
1706:
1707: * if we're overlaying. "mem" is the loaded memory region returned by
1708:
1709: * "load region". Any open files (other than the standard handles) owned
1710:
1711: * by "p" are closed, and if thread !=0 all memory is released; the caller
1712:
1713: * must explicitly attach the environment and base region. The caller must
1714:
1715: * also put "p" on the appropriate queue (most likely READY_Q).
1716:
1717: */
1718:
1719:
1720:
1721: extern long mint_dos(), mint_bios();
1722:
1723:
1724:
1725: void rts() {} /* dummy termination routine */
1726:
1727:
1728:
1729: PROC *
1730:
1731: exec_region(p, mem, thread)
1732:
1733: PROC *p;
1734:
1735: MEMREGION *mem;
1736:
1737: int thread;
1738:
1739: {
1740:
1741: BASEPAGE *b;
1742:
1743: FILEPTR *f;
1744:
1745: int i;
1746:
1747: MEMREGION *m;
1748:
1749:
1750:
1751: TRACE("exec_region");
1752:
1753:
1754:
1755: b = (BASEPAGE *) mem->loc;
1756:
1757:
1758:
1759: /* set some (undocumented) variables in the basepage */
1760:
1761: b->p_defdrv = p->curdrv;
1762:
1763: for (i = 0; i < 6; i++)
1764:
1765: b->p_devx[i] = i;
1766:
1767:
1768:
1769: p->dta = (DTABUF *)(b->p_dta = &b->p_cmdlin[0]);
1770:
1771: p->base = b;
1772:
1773:
1774:
1775: /* close extra open files */
1776:
1777: for (i = MIN_OPEN; i < MAX_OPEN; i++) {
1778:
1779: if ( (f = p->handle[i]) && (p->fdflags[i] & FD_CLOEXEC) ) {
1780:
1781: do_pclose(p, f);
1782:
1783: p->handle[i] = 0;
1784:
1785: }
1786:
1787: }
1788:
1789:
1790:
1791: /* initialize memory */
1792:
1793: recalc_maxmem(p);
1794:
1795: if (p->maxmem) {
1796:
1797: shrink_region(mem, p->maxmem);
1798:
1799: b->p_hitpa = b->p_lowtpa + mem->len;
1800:
1801: }
1802:
1803:
1804:
1805: p->memflags = b->p_flags;
1806:
1807:
1808:
1809: if (!thread) {
1810:
1811: for (i = 0; i < p->num_reg; i++) {
1812:
1813: m = p->mem[i];
1814:
1815: if (m) {
1816:
1817: m->links--;
1818:
1819: if (m->links <= 0)
1820:
1821: free_region(m);
1822:
1823: }
1824:
1825: }
1826:
1827: if (p->num_reg > NUM_REGIONS) {
1828:
1829: kfree(p->mem); kfree(p->addr);
1830:
1831: p->mem = kmalloc(NUM_REGIONS * SIZEOF(MEMREGION *));
1832:
1833: p->addr = kmalloc(NUM_REGIONS * SIZEOF(virtaddr));
1834:
1835: /* note: the mallocs have succeeded, since we just freed bigger areas */
1836:
1837: assert(p->mem && p->addr);
1838:
1839: p->num_reg = NUM_REGIONS;
1840:
1841: }
1842:
1843: zero((char *)p->mem, (p->num_reg)*SIZEOF(MEMREGION *));
1844:
1845: zero((char *)p->addr, (p->num_reg)*SIZEOF(virtaddr));
1846:
1847: }
1848:
1849:
1850:
1851: /* initialize signals */
1852:
1853: p->sigmask = 0;
1854:
1855: for (i = 0; i < NSIG; i++) {
1856:
1857: if (p->sighandle[i] != SIG_IGN) {
1858:
1859: p->sighandle[i] = SIG_DFL;
1860:
1861: p->sigflags[i] = 0;
1862:
1863: p->sigextra[i] = 0;
1864:
1865: }
1866:
1867: }
1868:
1869:
1870:
1871: /* zero the user registers, and set the FPU in a "clear" state */
1872:
1873: for (i = 0; i < 15; i++)
1874:
1875: p->ctxt[CURRENT].regs[i] = 0;
1876:
1877: p->ctxt[CURRENT].sr = 0;
1878:
1879: p->ctxt[CURRENT].fstate[0] = 0;
1880:
1881:
1882:
1883: /* set PC, stack registers, etc. appropriately */
1884:
1885: p->ctxt[CURRENT].pc = b->p_tbase;
1886:
1887:
1888:
1889: /* The "-0x20" is to make sure that syscall.s won't run past the end of
1890:
1891: * memory when the user makes a system call and doesn't push very many
1892:
1893: * parameters -- syscall always tries to copy the maximum possible number
1894:
1895: * of parms.
1896:
1897: *
1898:
1899: * NOTE: there's a sanity check here in case programs Mshrink a basepage
1900:
1901: * without fixing the p_hitpa field in the basepage; this is to ensure
1902:
1903: * compatibility with older versions of MiNT, which ignore p_hitpa.
1904:
1905: */
1906:
1907: if (valid_address(b->p_hitpa - 0x20))
1908:
1909: p->ctxt[CURRENT].usp = b->p_hitpa - 0x20;
1910:
1911: else
1912:
1913: p->ctxt[CURRENT].usp = mem->loc + mem->len - 0x20;
1914:
1915:
1916:
1917: p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
1918:
1919: p->ctxt[CURRENT].term_vec = (long)rts;
1920:
1921:
1922:
1923: /* set up stack for process */
1924:
1925: *((long *)(p->ctxt[CURRENT].usp + 4)) = (long) b;
1926:
1927:
1928:
1929: /* check for a valid text region. some compilers (e.g. Lattice 3) just throw
1930:
1931: everything into the text region, including data; fork() must be careful
1932:
1933: to save the whole region, then. We assume that if the compiler (or
1934:
1935: assembler, or whatever) goes to the trouble of making separate text, data,
1936:
1937: and bss regions, then the text region is code and isn't modified and
1938:
1939: fork doesn't have to save it.
1940:
1941: */
1942:
1943: if (b->p_tlen != 0 && b->p_blen != 0 && b->p_dlen != 0)
1944:
1945: p->txtsize = b->p_tlen;
1946:
1947: else
1948:
1949: p->txtsize = 0;
1950:
1951:
1952:
1953: /*
1954:
1955: * An ugly hack: dLibs tries to poke around in the parent's address space
1956:
1957: * to find stuff. For now, we'll allow this by faking a pointer into
1958:
1959: * the parent's address space in the place in the basepage where dLibs is
1960:
1961: * expecting it. This ugly hack only works correctly if the Pexec'ing
1962:
1963: * program (i.e. curproc) is in user mode.
1964:
1965: */
1966:
1967: curproc->base->p_usp = curproc->ctxt[SYSCALL].usp - 0x32;
1968:
1969:
1970:
1971: return p;
1972:
1973: }
1974:
1975:
1976:
1977: /*
1978:
1979: * misc. utility routines
1980:
1981: */
1982:
1983:
1984:
1985: /*
1986:
1987: * long memused(p): return total memory allocated to process p
1988:
1989: */
1990:
1991:
1992:
1993: long
1994:
1995: memused(p)
1996:
1997: PROC *p;
1998:
1999: {
2000:
2001: int i;
2002:
2003: long size;
2004:
2005:
2006:
2007: size = 0;
2008:
2009: for (i = 0; i < p->num_reg; i++) {
2010:
2011: if (p->mem[i])
2012:
2013: size += p->mem[i]->len;
2014:
2015: }
2016:
2017: return size;
2018:
2019: }
2020:
2021:
2022:
2023: /*
2024:
2025: * recalculate the maximum memory limit on a process; this limit depends
2026:
2027: * on the max. allocated memory and max. total memory limits set by
2028:
2029: * p_setlimit (see dos.c), and (perhaps) on the size of the program
2030:
2031: * that the process is executing. whenever any of these things
2032:
2033: * change (through p_exec or p_setlimit) this routine must be called
2034:
2035: */
2036:
2037:
2038:
2039: void
2040:
2041: recalc_maxmem(p)
2042:
2043: PROC *p;
2044:
2045: {
2046:
2047: BASEPAGE *b;
2048:
2049: long siz;
2050:
2051:
2052:
2053: b = (BASEPAGE *)p->base;
2054:
2055: if (b)
2056:
2057: siz = b->p_tlen + b->p_dlen + b->p_blen;
2058:
2059: else
2060:
2061: siz = 0;
2062:
2063: p->maxmem = 0;
2064:
2065: if (p->maxdata) {
2066:
2067: p->maxmem = p->maxdata + siz;
2068:
2069: }
2070:
2071:
2072:
2073: if (p->maxcore) {
2074:
2075: if (p->maxmem == 0 || p->maxmem > p->maxcore)
2076:
2077: p->maxmem = p->maxcore;
2078:
2079: }
2080:
2081: if (p->maxmem && p->maxmem < siz)
2082:
2083: p->maxmem = siz;
2084:
2085: }
2086:
2087:
2088:
2089: /*
2090:
2091: * valid_address: checks to see if the indicated address falls within
2092:
2093: * memory attached to the current process
2094:
2095: */
2096:
2097:
2098:
2099: int
2100:
2101: valid_address(addr)
2102:
2103: long addr;
2104:
2105: {
2106:
2107: int i;
2108:
2109: MEMREGION *m;
2110:
2111:
2112:
2113: for (i = 0; i < curproc->num_reg; i++) {
2114:
2115: if ((m = curproc->mem[i]) != 0) {
2116:
2117: if (addr >= m->loc && addr <= m->loc + m->len)
2118:
2119: return 1;
2120:
2121: }
2122:
2123: }
2124:
2125: return 0;
2126:
2127: }
2128:
2129:
2130:
2131: /*
2132:
2133: * some debugging stuff
2134:
2135: */
2136:
2137:
2138:
2139: void
2140:
2141: DUMPMEM(map)
2142:
2143: MMAP map;
2144:
2145: {
2146:
2147: MEMREGION *m;
2148:
2149:
2150:
2151: m = *map;
2152:
2153: ALERT("memory dump: starting at region %lx", m);
2154:
2155: while (m) {
2156:
2157: ALERT("%ld bytes at %lx (%d links); next region %lx", m->len, m->loc,
2158:
2159: m->links, m->next);
2160:
2161: m = m->next;
2162:
2163: }
2164:
2165: }
2166:
2167:
2168:
2169: void
2170:
2171: sanity_check(map)
2172:
2173: MMAP map;
2174:
2175: {
2176:
2177: #ifdef SANITY_CHECK
2178:
2179: MEMREGION *m, *nxt;
2180:
2181: long end;
2182:
2183:
2184:
2185: m = *map;
2186:
2187: while (m) {
2188:
2189: nxt = m->next;
2190:
2191: if (nxt) {
2192:
2193: end = m->loc + m->len;
2194:
2195: if (m->loc < nxt->loc && end > nxt->loc) {
2196:
2197: FATAL("MEMORY CHAIN CORRUPTED");
2198:
2199: }
2200:
2201: else if (end == nxt->loc && ISFREE(m) && ISFREE(nxt)) {
2202:
2203: ALERT("Continguous memory regions not merged!");
2204:
2205: }
2206:
2207: }
2208:
2209: m = nxt;
2210:
2211: }
2212:
2213: #endif
2214:
2215: }
2216:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.