home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / mint / mint095s / mem.c < prev    next >
C/C++ Source or Header  |  1993-08-03  |  25KB  |  1,109 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. /*
  6.  * mem.c:: routines for managing memory regions
  7.  */
  8.  
  9. #include "mint.h"
  10.  
  11. static long core_malloc P_((long, int));
  12.  
  13. /* macro for testing whether a memory region is free */
  14. #define ISFREE(m) ((m)->links == 0)
  15.  
  16. /*
  17.  * initialize memory routines
  18.  */
  19.  
  20. /* initial number of memory regions */
  21. #define NREGIONS 512
  22.  
  23. /* number of new regions to allocate when the initial ones are used up */
  24. #define NEWREGIONS 256
  25.  
  26. static MEMREGION use_regions[NREGIONS+1];
  27. MEMREGION *rfreelist;
  28.  
  29. void
  30. init_mem()
  31. {
  32.     int i;
  33.  
  34.     use_regions[NREGIONS].next = 0;
  35.     for (i = 0; i < NREGIONS; i++) {
  36.         use_regions[i].next = &use_regions[i+1];
  37.     }
  38.     rfreelist = use_regions;
  39.  
  40.     init_core();
  41.     init_swap();
  42. }
  43.  
  44. /*
  45.  * init_core(): initialize the core memory map (normal ST ram) and also
  46.  * the alternate memory map (fast ram on the TT)
  47.  */
  48.  
  49. static MEMREGION *_core_regions = 0, *_alt_regions = 0,
  50.     *_ker_regions = 0;
  51.  
  52. MMAP core = &_core_regions;
  53. MMAP alt = &_alt_regions;
  54. MMAP ker = &_ker_regions;
  55.  
  56. /* note: add_region must adjust both the size and starting
  57.  * address of the region being added so that memory is
  58.  * always properly aligned
  59.  */
  60.  
  61. int
  62. add_region(map, place, size, mflags)
  63.     MMAP map;
  64.     ulong place, size;
  65.     unsigned mflags;    /* initial flags for region */
  66. {
  67.     MEMREGION *m;
  68.     ulong newplace;
  69.  
  70.     newplace = ROUND(place);
  71.     size = (place + size) - newplace;
  72.     size &= ~MASKBITS;
  73.     if (size <= 0)        /* region too small to use */
  74.         return 1;
  75.  
  76.     m = new_region();
  77.     if (m == 0)
  78.         return 0;    /* failure */
  79.     m->links = 0;
  80.     m->len = size;
  81.     m->loc = newplace;
  82.     m->next = *map;
  83.     m->mflags = mflags;
  84.     *map = m;
  85.     return 1;    /* success */
  86. }
  87.  
  88. static long
  89. core_malloc(amt, mode)
  90.     long amt;
  91.     int mode;
  92. {
  93.     static int mxalloc = -1;    /* does GEMDOS know about Mxalloc? */
  94.     long ret;
  95.  
  96.     if (mxalloc < 0) {
  97.         ret = (long)Mxalloc(-1L, 0);
  98.         if (ret == -32) mxalloc = 0;    /* unknown function */
  99.         else if (ret >= 0) mxalloc = 1;
  100.         else {
  101.             ALERT("GEMDOS returned %ld from Mxalloc", ret);
  102.             mxalloc = 0;
  103.         }
  104.     }
  105.     if (mxalloc)
  106.         return Mxalloc(amt, mode);
  107.     else if (mode == 1)
  108.         return 0L;
  109.     else
  110.         return Malloc(amt);
  111. }
  112.  
  113. void
  114. init_core()
  115. {
  116. #ifdef JUNK_MEM
  117.     extern void fillwjunk();
  118. #endif
  119.     ulong size;
  120.     ulong place;
  121.     void *tossave;
  122.  
  123.     tossave = (void *)core_malloc((long)TOS_MEM, 0);
  124.     if (!tossave) {
  125.         FATAL("Not enough memory to run MiNT");
  126.     }
  127.  
  128. /* initialize kernel memory */
  129.     place = (ulong)core_malloc(KERNEL_MEM, 3);
  130.     if (place != 0) {
  131.         (void)add_region(ker, place, KERNEL_MEM, M_KER);
  132. #ifdef JUNK_MEM
  133.     fillwjunk(place, (long)KERNEL_MEM);
  134. #endif
  135.     }
  136.  
  137. /* initialize ST RAM */
  138.     size = (ulong)core_malloc(-1L, 0);
  139.     while (size > 0) {
  140.         place = (ulong)core_malloc(size, 0);
  141.         if (!add_region(core, place, size, M_CORE))
  142.             FATAL("init_mem: unable to add a region");
  143. #ifdef JUNK_MEM
  144.         fillwjunk(place, size);
  145. #endif
  146.         size = (ulong)core_malloc(-1L, 0);
  147.     }
  148.  
  149. /* initialize alternate RAM */
  150.     size = (ulong)core_malloc(-1L, 1);
  151.     while (size > 0) {
  152.         place = (ulong)core_malloc(size, 1);
  153.         if (!add_region(alt, place, size, M_ALT))
  154.             FATAL("init_mem: unable to add a region");
  155.         size = (ulong)core_malloc(-1L, 1);
  156.     }
  157.  
  158.     (void)Mfree(tossave);        /* leave some memory for TOS to use */
  159. }
  160.  
  161. /*
  162.  * init_swap(): initialize the swap area; for now, this does nothing
  163.  */
  164.  
  165. MEMREGION *_swap_regions = 0;
  166. MMAP swap = &_swap_regions;
  167.  
  168. void
  169. init_swap()
  170. {
  171. }
  172.  
  173. /*
  174.  * routines for allocating/deallocating memory regions
  175.  */
  176.  
  177. /*
  178.  * new_region returns a new memory region descriptor, or NULL
  179.  */
  180.  
  181. MEMREGION *
  182. new_region()
  183. {
  184.     MEMREGION *m, *newfrees;
  185.     int i;
  186.  
  187.     m = rfreelist;
  188.     if (!m) {
  189.         ALERT("new_region: ran out of free regions");
  190.         return 0;
  191.     }
  192.     assert(ISFREE(m));
  193.     rfreelist = m->next;
  194.     m->next = 0;
  195.  
  196. /* if we're running low on free regions, allocate some more
  197.  * we have to do this with at least 1 free region left so that get_region
  198.  * has a chance of working
  199.  */
  200.     if (rfreelist && !rfreelist->next) {
  201.         MEMREGION *newstuff;
  202.  
  203.         TRACE("get_region: getting new region descriptors");
  204.         newstuff = get_region(ker, NEWREGIONS*SIZEOF(MEMREGION));
  205.         if (!newstuff)
  206.             newstuff = get_region(alt,NEWREGIONS*SIZEOF(MEMREGION));
  207.         if (!newstuff)
  208.             newstuff = get_region(core, NEWREGIONS*SIZEOF(MEMREGION));
  209.         newfrees = newstuff ? (MEMREGION *)newstuff->loc : 0;
  210.         if (newfrees) {
  211.             newfrees[NEWREGIONS-1].next = 0;
  212.             newfrees[NEWREGIONS-1].links = 0;
  213.             for (i = 0; i < NEWREGIONS-1; i++) {
  214.                 newfrees[i].next = &newfrees[i+1];
  215.                 newfrees[i].links = 0;
  216.             }
  217.             rfreelist = newfrees;
  218.         } else {
  219.             DEBUG("couldn't get new region descriptors!");
  220.         }
  221.     }
  222.  
  223.     return m;
  224. }
  225.  
  226. /*
  227.  * dispose_region destroys a memory region descriptor
  228.  */
  229.  
  230. void
  231. dispose_region(m)
  232.     MEMREGION *m;
  233. {
  234.     assert(ISFREE(m));
  235.     m->next = rfreelist;
  236.     rfreelist = m;
  237. }
  238.  
  239. /*
  240.  * virtaddr
  241.  * attach_region(proc, reg): attach the region to the given process:
  242.  * returns the address at which it was attached, or NULL if the process
  243.  * cannot attach more regions. The region link count is incremented if
  244.  * the attachment is successful.
  245.  */
  246.  
  247. virtaddr
  248. attach_region(proc, reg)
  249.     PROC *proc;
  250.     MEMREGION *reg;
  251. {
  252.     int i;
  253.     MEMREGION **newmem;
  254.     virtaddr *newaddr;
  255.  
  256.     if (!reg || !reg->loc) {
  257.         ALERT("attach_region: attaching a null region??");
  258.         return 0;
  259.     }
  260.     for (i = 0; i < proc->num_reg; i++) {
  261.         if (!proc->mem[i]) {
  262.             assert(proc->addr[i] == 0);
  263.             reg->links++;
  264.             proc->mem[i] = reg;
  265.             proc->addr[i] = (virtaddr) reg->loc;
  266.             return proc->addr[i];
  267.         }
  268.     }
  269.  
  270. /* Hmmm, OK, we have to expand the process' memory table */
  271.     TRACE("Expanding process memory table");
  272.     i = proc->num_reg + NUM_REGIONS;
  273.  
  274.     newmem = kmalloc(i * SIZEOF(MEMREGION *));
  275.     newaddr = kmalloc(i * SIZEOF(virtaddr));
  276.  
  277.     if (newmem && newaddr) {
  278.     /* copy over the old address mapping */
  279.         for (i = 0; i < proc->num_reg; i++) {
  280.             newmem[i] = proc->mem[i];
  281.             newaddr[i] = proc->addr[i];
  282.             if (newmem[i] == 0)
  283.                 assert(newaddr[i] == 0);
  284.         }
  285.     /* initialize the rest of the tables */
  286.         for(; i < proc->num_reg + NUM_REGIONS; i++) {
  287.             newmem[i] = 0;
  288.             newaddr[i] = 0;
  289.         }
  290.     /* free the old tables */
  291.         kfree(proc->mem); kfree(proc->addr);
  292.         proc->mem = newmem;
  293.         proc->addr = newaddr;
  294.         proc->num_reg += NUM_REGIONS;
  295.     /* this call will succeed */
  296.         TRACE("recursively calling attach_region");
  297.         return attach_region(proc, reg);
  298.     }
  299.  
  300.     DEBUG("attach_region: failed");
  301.     return 0;
  302. }
  303.  
  304. /*
  305.  * detach_region(proc, reg): remove region from the procedure's address
  306.  * space. If no more processes reference the region, return it to the
  307.  * system. Note that we search backwards, so that the most recent
  308.  * attachment of memory gets detached!
  309.  */
  310.  
  311. void
  312. detach_region(proc, reg)
  313.     PROC *proc;
  314.     MEMREGION *reg;
  315. {
  316.     int i;
  317.  
  318.     if (!reg) return;
  319.     for (i = proc->num_reg - 1; i >= 0; i--) {
  320.         if (proc->mem[i] == reg) {
  321.             reg->links--;
  322.             proc->mem[i] = 0; proc->addr[i] = 0;
  323.             if (reg->links == 0) {
  324.                 free_region(reg);
  325.             }
  326.             return;
  327.         }
  328.     }
  329.     DEBUG("detach_region: region not attached");
  330. }
  331.  
  332. /*
  333.  * get_region(MMAP map, ulong size) -- allocate a new region of the
  334.  * given size in the given memory map. if no region big enough is available,
  335.  * return NULL, otherwise return a pointer to the region.
  336.  * the "links" field in the region is set to 1
  337.  *
  338.  * BEWARE: new_region may call get_region (indirectly), so we have to be
  339.  * _very_ careful with re-entrancy in this function
  340.  */
  341.  
  342. MEMREGION *
  343. get_region(map, size)
  344.     MMAP map;
  345.     ulong size;
  346. {
  347.     MEMREGION *m, *n;
  348.  
  349. /* precautionary measures */
  350.     if (size == 0) {
  351.         DEBUG("request for 0 bytes??");
  352.         size = 1;
  353.     }
  354.  
  355.     size = ROUND(size);
  356.  
  357.     n = *map;
  358.  
  359.     sanity_check(map);
  360. /* exact matches are likely to be rare, so we pre-allocate a new
  361.  * region here; this helps us to avoid re-entrancy problems
  362.  * when new_region calls get_region
  363.  */
  364.     m = new_region();
  365.  
  366.     while (n) {
  367.         if (ISFREE(n)) {
  368.             if (n->len == size) {
  369.                 if (m) dispose_region(m);
  370.                 n->links++;
  371.                 return n;
  372.             }
  373.             else if (n->len > size) {
  374. /* split a new region, 'm', which will contain the free bytes after n */
  375.                 if (m) {
  376.                     m->next = n->next;
  377.                     n->next = m;
  378.                     m->mflags = n->mflags & M_MAP;
  379.                     m->loc = n->loc + size;
  380.                     m->len = n->len - size;
  381.                     n->len = size;
  382.                     n->links++;
  383.                     return n;
  384.                 } else {
  385.                     DEBUG("get_region: no regions left");
  386.                     return 0;
  387.                 }
  388.             }
  389.         }
  390.         n = n->next;
  391.     }
  392.  
  393.     if (m)
  394.         dispose_region(m);
  395.     return NULL;
  396. }
  397.  
  398. /*
  399.  * free_region(MEMREGION *reg): free the indicated region. The map
  400.  * in which the region is contained is given by reg->mflags.
  401.  * the caller is responsible for making sure that the region
  402.  * really should be freed, i.e. that reg->links == 0.
  403.  */
  404.  
  405. void
  406. free_region(reg)
  407.     MEMREGION *reg;
  408. {
  409.     MMAP map;
  410.     MEMREGION *m;
  411.  
  412.     if (!reg) return;
  413.  
  414.     assert(ISFREE(reg));
  415.  
  416.     if (reg->mflags & M_CORE)
  417.         map = core;
  418.     else if (reg->mflags & M_ALT)
  419.         map = alt;
  420.     else if (reg->mflags & M_KER)
  421.         map = ker;
  422.     else {
  423.         FATAL("free_region: region flags not valid (%x)", reg->mflags);
  424.     }
  425.     reg->mflags &= M_MAP;
  426.     m = *map;
  427.     assert(m);
  428.  
  429.     if (m == reg) goto merge_after;
  430.  
  431. /* merge previous region if it's free and contiguous with 'reg' */
  432.  
  433. /* first, we find the region */
  434.     while (m && m->next != reg)
  435.         m = m->next;
  436.  
  437.     assert(m != NULL);
  438.  
  439.     if (ISFREE(m) && (m->loc + m->len == reg->loc)) {
  440.         m->len += reg->len;
  441.         assert(m->next == reg);
  442.         m->next = reg->next;
  443.         reg->next = 0;
  444.         dispose_region(reg);
  445.         reg = m;
  446.     }
  447.  
  448. /* merge next region if it's free and contiguous with 'reg' */
  449. merge_after:
  450.     m = reg->next;
  451.     if (m && ISFREE(m) && reg->loc + reg->len == m->loc) {
  452.         reg->len += m->len;
  453.         reg->next = m->next;
  454.         m->next = 0;
  455.         dispose_region(m);
  456.     }
  457.  
  458.     sanity_check(map);
  459. }
  460.  
  461. /*
  462.  * shrink_region(MEMREGION *reg, ulong newsize):
  463.  *   shrink region 'reg', so that it is now 'newsize' bytes long.
  464.  *   if 'newsize' is bigger than the region's current size, return EGSBF;
  465.  *   otherwise return 0.
  466.  */
  467.  
  468. long
  469. shrink_region(reg, newsize)
  470.     MEMREGION *reg;
  471.     ulong newsize;
  472. {
  473.     MMAP map;
  474.     MEMREGION *n;
  475.     ulong diff;
  476.  
  477.  
  478.     newsize = ROUND(newsize);
  479.  
  480.     assert(reg->links > 0);
  481.  
  482.     if (reg->mflags & M_CORE)
  483.         map = core;
  484.     else if (reg->mflags & M_ALT)
  485.         map = alt;
  486.     else if (reg->mflags & M_KER)
  487.         map = ker;
  488.     else {
  489.         FATAL("shrink_region: bad region flags (%x)", reg->mflags);
  490.     }
  491.  
  492. /* shrinking to 0 is the same as freeing */
  493.     if (newsize == 0) {
  494.         detach_region(curproc, reg);
  495.         return 0;
  496.     }
  497.  
  498. /* if new size is the same as old size, don't do anything */
  499.     if (newsize == reg->len) {
  500.         return 0;    /* nothing to do */
  501.     }
  502.  
  503.     if (newsize > reg->len) {
  504.         DEBUG("shrink_region: request to make region bigger");
  505.         return EGSBF;    /* growth failure */
  506.     }
  507.  
  508. /* OK, we're going to free (reg->len - newsize) bytes at the end of
  509.    this block. If the block after us is already free, simply add the
  510.    space to that block.
  511.  */
  512.     n = reg->next;
  513.     diff = reg->len - newsize;
  514.  
  515.     if (n && ISFREE(n) && reg->loc + reg->len == n->loc) {
  516.         reg->len = newsize;
  517.         n->loc -= diff;
  518.         n->len += diff;
  519.         return 0;
  520.     }
  521.     else {
  522.         n = new_region();
  523.         if (!n) {
  524.             DEBUG("shrink_region: new_region failed");
  525.             return EINTRN;
  526.         }
  527.         reg->len = newsize;
  528.         n->loc = reg->loc + newsize;
  529.         n->len = diff;
  530.         n->mflags = reg->mflags & M_MAP;
  531.         n->next = reg->next;
  532.         reg->next = n;
  533.     }
  534.     return 0;
  535. }
  536.  
  537. /*
  538.  * max_rsize(map): return the length of the biggest free region
  539.  * in the given memory map, or 0 if no regions remain.
  540.  */
  541.  
  542. long
  543. max_rsize(map)
  544.     MMAP map;
  545. {
  546.     MEMREGION *m, *max = 0;
  547.     long size = 0;
  548.  
  549.     for (m = *map; m; m = m->next) {
  550.         if (ISFREE(m)) {
  551.             if (m->len > size) {
  552.                 max = m;
  553.                 size = m->len;
  554.             }
  555.         }
  556.     }
  557.     return size;
  558. }
  559.  
  560. /*
  561.  * tot_rsize(map, flag): if flag == 1, return the total number of bytes in
  562.  * the given memory map; if flag == 0, return only the number of free
  563.  * bytes
  564.  */
  565.  
  566. long
  567. tot_rsize(map, flag)
  568.     MMAP map;
  569.     int flag;
  570. {
  571.     MEMREGION *m;
  572.     long size = 0;
  573.  
  574.     for (m = *map; m; m = m->next) {
  575.         if (flag || ISFREE(m)) {
  576.             size += m->len;
  577.         }
  578.     }
  579.     return size;
  580. }
  581.  
  582. /*
  583.  * alloc_region(MMAP map, ulong size): allocate a new region and attach
  584.  * it to the current process; returns the address at which the region
  585.  * was attached, or NULL. If not enough memory is found, wait a bit
  586.  * and try again before giving up (maybe someone else will free some
  587.  * memory)
  588.  */
  589.  
  590. virtaddr
  591. alloc_region(map, size)
  592.     MMAP map;
  593.     ulong size;
  594. {
  595.     MEMREGION *m;
  596.     PROC *proc = curproc;
  597.     virtaddr v;
  598.  
  599.     m = get_region(map, size);
  600.     if (!m) {
  601.         return 0;
  602.     }
  603.  
  604.     v = attach_region(proc, m);
  605. /* NOTE: get_region returns a region with link count 1; since attach_region
  606.  * increments the link count, we restore it after calling attach_region
  607.  */
  608.     m->links = 1;
  609.     if (!v) {
  610.         m->links = 0;
  611.         free_region(m);
  612.         return 0;
  613.     }
  614.     return v;
  615. }
  616.  
  617. /*
  618.  * routines for creating a copy of an environment, and a new basepage.
  619.  * note that the memory regions created should immediately be attached to
  620.  * a process! Also note that create_env always operates in ST RAM, but
  621.  * create_base might not.
  622.  */
  623.  
  624. MEMREGION *
  625. create_env(env)
  626.     const char *env;
  627. {
  628.     long size;
  629.     MEMREGION *m;
  630.     virtaddr v;
  631.     const char *old;
  632.     char *new;
  633.     
  634.     if (!env) {
  635.         env = ((BASEPAGE *)curproc->base)->p_env;
  636.             /* duplicate parent's environment */
  637.     }
  638.     size = 2;
  639.     old = env;
  640.     while (*env || *(env+1))
  641.         env++,size++;
  642.     v = alloc_region(core, size);
  643.     if (!v) {
  644.         DEBUG("create_env: alloc_region failed");
  645.         return (MEMREGION *)0;
  646.     }
  647.     m = addr2mem(v);
  648.  
  649. /* copy the old environment into the new */
  650.     new = (char *) m->loc;
  651.     while (size > 0) {
  652.         *new++ = *old++;
  653.         --size;
  654.     }
  655.     return m;
  656. }
  657.  
  658. MEMREGION *
  659. create_base(cmd, env, flags, prgsize)
  660.     const char *cmd;
  661.     MEMREGION *env;
  662.     ulong flags, prgsize;
  663. {
  664.     long len, coresize, altsize;
  665.     MMAP map;
  666.     MEMREGION *m;
  667.     BASEPAGE *b;
  668.  
  669. /* if flags & F_ALTLOAD == 1, then we might decide to load in alternate
  670.    RAM if enough is available. "enough" is: if more alt ram than ST ram,
  671.    load there; otherwise, if more than (minalt+1)*128K alt ram available
  672.    for heap space, load in alt ram ("minalt" is the high byte of flags)
  673.  */
  674.     if (flags & F_ALTLOAD) {
  675.         coresize = max_rsize(core);
  676.         altsize = max_rsize(alt);
  677.         if (altsize >= coresize)
  678.             map = alt;
  679.         else {
  680.             len = (flags & 0xf0000000) >> 28L;
  681.             len = (len+1)*128*1024L + prgsize + 256;
  682.             if (altsize >= len)
  683.                 map = alt;
  684.             else
  685.                 map = core;
  686.         }
  687.     }
  688.     else
  689.         map = core;
  690.  
  691.     len = max_rsize(map);
  692.  
  693. /* make sure that a little bit of memory is left over */
  694.     if (len > 2*KEEP_MEM) {
  695.         len -= KEEP_MEM;
  696.     }
  697.     m = addr2mem(alloc_region(map, len));
  698.     if (!m) {
  699.         DEBUG("create_base: alloc_region failed");
  700.         return 0;
  701.     }
  702.     b = (BASEPAGE *)(m->loc);
  703.  
  704.     zero((char *)b, (long)sizeof(BASEPAGE));
  705.     b->p_lowtpa = (long)b;
  706.     b->p_hitpa = m->loc + m->len;
  707.     b->p_env = (char *)env->loc;
  708.     b->p_flags = flags;
  709.  
  710.     if (cmd)
  711.         strncpy(b->p_cmdlin, cmd, 126);
  712.     return m;
  713. }
  714.  
  715. /*
  716.  * load_region(filename): loads the program with the given file name
  717.  * into a new region, and returns a pointer to that region. On an error,
  718.  * returns 0 and leaves the error number in mint_errno.
  719.  */
  720.  
  721. static struct fileheader {
  722.     short    fmagic;
  723.     long    ftext;
  724.     long    fdata;
  725.     long    fbss;
  726.     long    fsym;
  727.     long    reserved;
  728.     long    flag;
  729.     short    reloc;
  730. } fh;
  731.  
  732. MEMREGION *
  733. load_region(filename, env, cmdlin, xp)
  734.     const char *filename;
  735.     MEMREGION *env;
  736.     const char *cmdlin;
  737.     XATTR *xp;        /* attributes for the file just loaded */
  738. {
  739.     FILEPTR *f;
  740.     DEVDRV *dev;
  741.     MEMREGION *reg;
  742.     BASEPAGE *b;
  743.     long size, fixup, base, bytes_read;
  744.     unsigned char c, *next;
  745. #define LRBUFSIZ 8196
  746.     static unsigned char buffer[LRBUFSIZ];
  747.     int trycount = 0;
  748.  
  749.     next = buffer;
  750.  
  751.     f = do_open(filename, O_DENYNONE | O_EXEC, 0, xp);
  752.     if (!f) {
  753.         return 0;        /* mint_errno set by do_open */
  754.     }
  755.  
  756.     dev = f->dev;            /* could be different from fs */
  757.     if ( (*dev->read)(f, (void *)&fh, (long)sizeof(fh)) != sizeof(fh) ||
  758.           fh.fmagic != 0x601a ) {
  759.         DEBUG("load_region: file not executable");
  760.         mint_errno = ENOEXEC;
  761. failed:
  762.         do_close(f);
  763.         return 0;
  764.     }
  765.  
  766.     size = fh.ftext + fh.fdata + fh.fbss;
  767.     reg = 0;
  768.     for (trycount = 0; (trycount < 1) && (reg == 0); trycount++) {
  769.         reg = create_base(cmdlin, env, fh.flag, size);
  770.         if (size+1024L > reg->len) {
  771.             DEBUG("load_region: insufficient memory to load");
  772.             detach_region(curproc, reg);
  773.             reg = 0;
  774.         }
  775.         if (!reg) {
  776.     /* maybe the memory shortage is short-term; sleep a bit to see */
  777.             nap(10);
  778.         }
  779.     }
  780.  
  781.     if (reg == 0) {
  782.         mint_errno = ENSMEM;
  783.         goto failed;
  784.     }
  785.  
  786.     b = (BASEPAGE *)reg->loc;
  787.     b->p_flags = fh.flag;
  788.     b->p_tbase = b->p_lowtpa + 256;
  789.     b->p_tlen = fh.ftext;
  790.     b->p_dbase = b->p_tbase + b->p_tlen;
  791.     b->p_dlen = fh.fdata;
  792.     b->p_bbase = b->p_dbase + b->p_dlen;
  793.     size = (*dev->read)(f, (void *)b->p_tbase, fh.ftext+fh.fdata);
  794.     if (size != fh.ftext + fh.fdata) {
  795.         DEBUG("load_region: unexpected EOF");
  796. failed_reloc:        /* come here when loading/relocation fails */
  797.         mint_errno = ENOEXEC;
  798.         detach_region(curproc, reg);
  799.         goto failed;
  800.     }
  801.  
  802.     b->p_blen = fh.fbss;
  803.     if (fh.flag & F_FASTLOAD)            /* fastload bit */
  804.         size = b->p_blen;
  805.     else
  806.         size = b->p_hitpa - b->p_bbase;
  807.     zero((char *)b->p_bbase, size);
  808.     (*dev->lseek)(f, fh.fsym, SEEK_CUR);    /* skip over symbol table */
  809.     base = b->p_tbase;
  810.  
  811. /* now read the relocation info; we use the temporary buffer provided
  812.  * above to speed things up
  813.  */
  814.  
  815.     if (fh.reloc == 0 && (*dev->read)(f, (char *)&fixup, 4L) && fixup) {
  816.         fixup += base;
  817.         size = LRBUFSIZ;
  818.         bytes_read = 0;
  819.         do {
  820.             if (fixup >= b->p_hitpa) {
  821.                 DEBUG("load_region: bad relocation");
  822.                 goto failed_reloc;
  823.             }
  824.             else
  825.                 *((long *)fixup) += base;
  826.             do {
  827.                 if (!bytes_read) {
  828.                     bytes_read =
  829.                         (*dev->read)(f,(char *)buffer,size);
  830.                     next = buffer;
  831.                 }
  832.                 if (bytes_read < 0) {
  833.                     DEBUG("load_region: EOF in relocation");
  834.                     goto failed_reloc;
  835.                 }
  836.                 else if (bytes_read == 0)
  837.                     c = 0;
  838.                 else {
  839.                     c = *next++; bytes_read--;
  840.                 }
  841.                 if (c == 1) fixup += 254;
  842.             } while (c == 1);
  843.             fixup += ( (unsigned) c) & 0xff;
  844.         } while (c);
  845.     }
  846.  
  847.     do_close(f);
  848.     return reg;
  849. }
  850.  
  851. /*
  852.  * exec_region(p, mem, thread): create a child process out of a mem region
  853.  * "p" is the process structure set up by the parent; it may be "curproc",
  854.  * if we're overlaying. "mem" is the loaded memory region returned by
  855.  * "load region". Any open files (other than the standard handles) owned
  856.  * by "p" are closed, and if thread !=0 all memory is released; the caller
  857.  * must explicitly attach the environment and base region. The caller must
  858.  * also put "p" on the appropriate queue (most likely READY_Q).
  859.  */
  860.  
  861. extern long mint_dos(), mint_bios();
  862.  
  863. void rts() {}        /* dummy termination routine */
  864.  
  865. PROC *
  866. exec_region(p, mem, thread)
  867.     PROC      *p;
  868.     MEMREGION *mem;
  869.     int thread;
  870. {
  871.     BASEPAGE *b;
  872.     FILEPTR *f;
  873.     int i;
  874.     MEMREGION *m;
  875.  
  876.     TRACE("exec_region");
  877.  
  878.     b = (BASEPAGE *) mem->loc;
  879.  
  880. /* set some (undocumented) variables in the basepage */
  881.     b->p_defdrv = p->curdrv;
  882.     for (i = 0; i < 6; i++)
  883.         b->p_devx[i] = i;
  884.  
  885.     p->dta = (DTABUF *)(b->p_dta = &b->p_cmdlin[0]);
  886.     p->base = b;
  887.  
  888. /* close extra open files */
  889.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  890.         if ( (f = p->handle[i]) && (p->fdflags[i] & FD_CLOEXEC) ) {
  891.             do_pclose(p, f);
  892.             p->handle[i] = 0;
  893.         }
  894.     }
  895.  
  896. /* initialize memory */
  897.     recalc_maxmem(p);
  898.     if (p->maxmem) {
  899.         shrink_region(mem, p->maxmem);
  900.         b->p_hitpa = b->p_lowtpa + mem->len;
  901.     }
  902.  
  903.     p->memflags = b->p_flags;
  904.  
  905.     if (!thread) {
  906.         for (i = 0; i < p->num_reg; i++) {
  907.             m = p->mem[i];
  908.             if (m) {
  909.                 m->links--;
  910.                 if (m->links <= 0)
  911.                     free_region(m);
  912.             }
  913.         }
  914.         if (p->num_reg > NUM_REGIONS) {
  915.             kfree(p->mem); kfree(p->addr);
  916.             p->mem = kmalloc(NUM_REGIONS * SIZEOF(MEMREGION *));
  917.             p->addr = kmalloc(NUM_REGIONS * SIZEOF(virtaddr));
  918.     /* note: the mallocs have succeeded, since we just freed bigger areas */
  919.             assert(p->mem && p->addr);
  920.             p->num_reg = NUM_REGIONS;
  921.         }
  922.         zero((char *)p->mem, (p->num_reg)*SIZEOF(MEMREGION *));
  923.         zero((char *)p->addr, (p->num_reg)*SIZEOF(virtaddr));
  924.     }
  925.  
  926. /* initialize signals */
  927.     p->sigmask = 0;
  928.     for (i = 0; i < NSIG; i++) {
  929.         if (p->sighandle[i] != SIG_IGN) {
  930.             p->sighandle[i] = SIG_DFL;
  931.             p->sigflags[i] = 0;
  932.             p->sigextra[i] = 0;
  933.         }
  934.     }
  935.  
  936. /* zero the user registers, and set the FPU in a "clear" state */
  937.     for (i = 0; i < 15; i++)
  938.         p->ctxt[CURRENT].regs[i] = 0;
  939.     p->ctxt[CURRENT].sr = 0;
  940.     p->ctxt[CURRENT].fstate[0] = 0;
  941.  
  942. /* set PC, stack registers, etc. appropriately */
  943.     p->ctxt[CURRENT].pc = b->p_tbase;
  944.  
  945. /* The "-0x20" is to make sure that syscall.s won't run past the end of
  946.  * memory when the user makes a system call and doesn't push very many
  947.  * parameters -- syscall always tries to copy the maximum possible number
  948.  * of parms.
  949.  *
  950.  * NOTE: there's a sanity check here in case programs Mshrink a basepage
  951.  * without fixing the p_hitpa field in the basepage; this is to ensure
  952.  * compatibility with older versions of MiNT, which ignore p_hitpa.
  953.  */
  954.     if (valid_address(b->p_hitpa - 0x20))
  955.         p->ctxt[CURRENT].usp = b->p_hitpa - 0x20;
  956.     else
  957.         p->ctxt[CURRENT].usp = mem->loc + mem->len - 0x20;
  958.  
  959.     p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
  960.     p->ctxt[CURRENT].term_vec = (long)rts;
  961.  
  962. /* set up stack for process */
  963.     *((long *)(p->ctxt[CURRENT].usp + 4)) = (long) b;
  964.  
  965. /* check for a valid text region. some compilers (e.g. Lattice 3) just throw
  966.    everything into the text region, including data; fork() must be careful
  967.    to save the whole region, then. We assume that if the compiler (or
  968.    assembler, or whatever) goes to the trouble of making separate text, data,
  969.    and bss regions, then the text region is code and isn't modified and
  970.    fork doesn't have to save it.
  971.  */
  972.     if (b->p_tlen != 0 && b->p_blen != 0 && b->p_dlen != 0)
  973.         p->txtsize = b->p_tlen;
  974.     else
  975.         p->txtsize = 0;
  976.  
  977. /*
  978.  * An ugly hack: dLibs tries to poke around in the parent's address space
  979.  * to find stuff. For now, we'll allow this by faking a pointer into
  980.  * the parent's address space in the place in the basepage where dLibs is
  981.  * expecting it. This ugly hack only works correctly if the Pexec'ing
  982.  * program (i.e. curproc) is in user mode.
  983.  */
  984.     curproc->base->p_usp = curproc->ctxt[SYSCALL].usp - 0x32;
  985.  
  986.     return p;
  987. }
  988.  
  989. /*
  990.  * misc. utility routines
  991.  */
  992.  
  993. /*
  994.  * long memused(p): return total memory allocated to process p
  995.  */
  996.  
  997. long
  998. memused(p)
  999.     PROC *p;
  1000. {
  1001.     int i;
  1002.     long size;
  1003.  
  1004.     size = 0;
  1005.     for (i = 0; i < p->num_reg; i++) {
  1006.         if (p->mem[i])
  1007.             size += p->mem[i]->len;
  1008.     }
  1009.     return size;
  1010. }
  1011.  
  1012. /* 
  1013.  * recalculate the maximum memory limit on a process; this limit depends
  1014.  * on the max. allocated memory and max. total memory limits set by
  1015.  * p_setlimit (see dos.c), and (perhaps) on the size of the program
  1016.  * that the process is executing. whenever any of these things
  1017.  * change (through p_exec or p_setlimit) this routine must be called
  1018.  */
  1019.  
  1020. void
  1021. recalc_maxmem(p)
  1022.     PROC *p;
  1023. {
  1024.     BASEPAGE *b;
  1025.     long siz;
  1026.  
  1027.     b = (BASEPAGE *)p->base;
  1028.     if (b)
  1029.         siz = b->p_tlen + b->p_dlen + b->p_blen;
  1030.     else
  1031.         siz = 0;
  1032.     p->maxmem = 0;
  1033.     if (p->maxdata) {
  1034.         p->maxmem = p->maxdata + siz;
  1035.     }
  1036.  
  1037.     if (p->maxcore) {
  1038.         if (p->maxmem == 0 || p->maxmem > p->maxcore)
  1039.             p->maxmem = p->maxcore;
  1040.     }
  1041.     if (p->maxmem && p->maxmem < siz)
  1042.         p->maxmem = siz;
  1043. }
  1044.  
  1045. /*
  1046.  * valid_address: checks to see if the indicated address falls within
  1047.  * memory attached to the current process
  1048.  */
  1049.  
  1050. int
  1051. valid_address(addr)
  1052.     long addr;
  1053. {
  1054.     int i;
  1055.     MEMREGION *m;
  1056.  
  1057.     for (i = 0; i < curproc->num_reg; i++) {
  1058.         if ((m = curproc->mem[i]) != 0) {
  1059.             if (addr >= m->loc && addr <= m->loc + m->len)
  1060.                 return 1;
  1061.         }
  1062.     }
  1063.     return 0;
  1064. }
  1065.  
  1066. /*
  1067.  * some debugging stuff
  1068.  */
  1069.  
  1070. void
  1071. DUMPMEM(map)
  1072.     MMAP map;
  1073. {
  1074.     MEMREGION *m;
  1075.  
  1076.     m = *map;
  1077.     ALERT("memory dump: starting at region %lx", m);
  1078.     while (m) {
  1079. ALERT("%ld bytes at %lx (%d links); next region %lx", m->len, m->loc,
  1080.       m->links, m->next);
  1081.     m = m->next;
  1082.     }
  1083. }
  1084.  
  1085. void
  1086. sanity_check(map)
  1087.     MMAP map;
  1088. {
  1089. #ifdef SANITY_CHECK
  1090.     MEMREGION *m, *nxt;
  1091.     long end;
  1092.  
  1093.     m = *map;
  1094.     while (m) {
  1095.         nxt = m->next;
  1096.         if (nxt) {
  1097.             end = m->loc + m->len;
  1098.             if (m->loc < nxt->loc && end > nxt->loc) {
  1099.                 FATAL("MEMORY CHAIN CORRUPTED");
  1100.             }
  1101.             else if (end == nxt->loc && ISFREE(m) && ISFREE(nxt)) {
  1102.                 ALERT("Continguous memory regions not merged!");
  1103.             }
  1104.         }
  1105.         m = nxt;
  1106.     }
  1107. #endif
  1108. }
  1109.