home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mint104s.zoo / mint.src / mem.c < prev    next >
C/C++ Source or Header  |  1993-03-08  |  39KB  |  1,658 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * mem.c:: routines for managing memory regions
  9.  */
  10.  
  11. #include "mint.h"
  12. #include "fasttext.h" /* for line A stuff */
  13.  
  14. #ifndef VgetSize
  15. extern long xbios();
  16. #define VgetSize(mode) xbios(91, (short)(mode))
  17. #define Vsetmode(mode) xbios(88, (short)(mode))
  18. #endif
  19.  
  20. static long core_malloc P_((long, int));
  21. static void core_free P_((long));
  22.  
  23. /* macro for testing whether a memory region is free */
  24. #define ISFREE(m) ((m)->links == 0)
  25.  
  26. /*
  27.  * list of shared text regions currently being executed
  28.  */
  29. SHTEXT *text_reg = 0;
  30.  
  31. /*
  32.  * initialize memory routines
  33.  */
  34.  
  35. /* initial number of memory regions */
  36. #define NREGIONS 512
  37.  
  38. /* number of new regions to allocate when the initial ones are used up */
  39. #define NEWREGIONS 256
  40.  
  41. static MEMREGION use_regions[NREGIONS+1];
  42. MEMREGION *rfreelist;
  43.  
  44. /* these variables are set in init_core(), and used in
  45.  * init_mem()
  46.  */
  47. static ulong scrnsize, scrnplace;
  48. static SCREEN *vscreen;
  49.  
  50. void
  51. init_mem()
  52. {
  53.     int i;
  54.     MEMREGION *r;
  55.     long newbase;
  56.  
  57.     use_regions[NREGIONS].next = 0;
  58.     for (i = 0; i < NREGIONS; i++) {
  59.         use_regions[i].next = &use_regions[i+1];
  60.     }
  61.     rfreelist = use_regions;
  62.  
  63.     init_core();
  64.     init_swap();
  65.  
  66.     init_tables();            /* initialize MMU constants */
  67.  
  68.     /* mark all the regions in the core & alt lists as "invalid" */
  69.     for (r = *core; r; r = r->next) {
  70.         mark_region(r,PROT_I);
  71.     }
  72.     for (r = *alt; r; r = r->next) {
  73.         mark_region(r,PROT_I);
  74.     }
  75.  
  76.     /* make sure the screen is set up properly */
  77.     newbase = s_realloc(scrnsize);
  78.  
  79.     /* if we did get a new screen, point the new screen
  80.      * at the right place after copying the data
  81.      * if possible, save the screen to another buffer,
  82.      * since if the new screen and old screen overlap
  83.      * the blit will look very ugly.
  84.      * Note that if the screen isn't moveable, then we set
  85.      * scrnsize to a ridiculously large value, and so the
  86.      * s_realloc above failed.
  87.      */
  88.     if (newbase) {
  89.     /* find a free region for temp storage */
  90.         for (r = *core; r; r = r->next) {
  91.             if (ISFREE(r) && r->len >= scrnsize)
  92.                 break;
  93.         }
  94.  
  95.         if (r) {
  96.             quickmove((char *)r->loc, (char *)scrnplace, scrnsize);
  97.             Setscreen((void *)r->loc, (void *)r->loc, -1);
  98.             Vsync();
  99.             quickmove((char *)newbase, (char *)r->loc, scrnsize);
  100.         } else {
  101.             quickmove((char *)newbase, (char *)scrnplace, scrnsize);
  102.         }
  103.         Setscreen((void *)newbase, (void *)newbase, -1);
  104.     /* fix the cursor */
  105.         Cconws("\r\n"); 
  106.     }
  107. }
  108.  
  109. /*
  110.  * init_core(): initialize the core memory map (normal ST ram) and also
  111.  * the alternate memory map (fast ram on the TT)
  112.  */
  113.  
  114. static MEMREGION *_core_regions = 0, *_alt_regions = 0,
  115.     *_ker_regions = 0;
  116.  
  117. MMAP core = &_core_regions;
  118. MMAP alt = &_alt_regions;
  119. MMAP ker = &_ker_regions;
  120.  
  121. /* note: add_region must adjust both the size and starting
  122.  * address of the region being added so that memory is
  123.  * always properly aligned
  124.  */
  125.  
  126. int
  127. add_region(map, place, size, mflags)
  128.     MMAP map;
  129.     ulong place, size;
  130.     unsigned mflags;    /* initial flags for region */
  131. {
  132.       MEMREGION *m;
  133.     ulong trimsize;
  134.  
  135.     TRACELOW(("add_region(map=%lx,place=%lx,size=%lx,flags=%x)",
  136.         map,place,size,mflags));
  137.  
  138.     m = new_region();
  139.     if (m == 0)
  140.         return 0;    /* failure */
  141.     m->links = 0;
  142.  
  143.     if (place & MASKBITS) {
  144.         /* increase place & shorten size by the amount we're trimming */
  145.         trimsize = (MASKBITS+1) - (place & MASKBITS);
  146.         if (size <= trimsize) goto lose;
  147.         size -= trimsize;
  148.         place += trimsize;
  149.     }
  150.  
  151.     /* now trim size DOWN to a multiple of pages */
  152.     if (size & MASKBITS) size &= ~MASKBITS;
  153.  
  154.     /* only add if there's anything left */
  155.     if (size) {
  156.         m->len = size;
  157.         m->loc = place;
  158.         m->next = *map;
  159.         m->mflags = mflags;
  160.         *map = m;
  161.     }
  162.     else {
  163.         /* succeed but don't do anything; dispose of region */
  164. lose:        dispose_region(m);
  165.     }
  166.     return 1;    /* success */
  167. }
  168.  
  169. static long
  170. core_malloc(amt, mode)
  171.     long amt;
  172.     int mode;
  173. {
  174.     static int mxalloc = -1;    /* does GEMDOS know about Mxalloc? */
  175.     long ret;
  176.  
  177.     if (mxalloc < 0) {
  178.         ret = (long)Mxalloc(-1L, 0);
  179.         if (ret == -32) mxalloc = 0;    /* unknown function */
  180.         else if (ret >= 0) mxalloc = 1;
  181.         else {
  182.             ALERT("GEMDOS returned %ld from Mxalloc", ret);
  183.             mxalloc = 0;
  184.         }
  185.     }
  186.     if (mxalloc)
  187.         return Mxalloc(amt, mode);
  188.     else if (mode == 1)
  189.         return 0L;
  190.     else
  191.         return Malloc(amt);
  192. }
  193.  
  194. static void
  195. core_free(where)
  196.     long where;
  197. {
  198.     Mfree((void *)where);
  199. }
  200.  
  201. void
  202. init_core()
  203. {
  204.     extern int FalconVideo;    /* set in main.c */
  205.     int scrndone = 0;
  206.     ulong size;
  207.     ulong place;
  208.     ulong temp;
  209.     void *tossave;
  210.  
  211.     tossave = (void *)core_malloc((long)TOS_MEM, 0);
  212.     if (!tossave) {
  213.         FATAL("Not enough memory to run MiNT");
  214.     }
  215.  
  216. /* initialize kernel memory */
  217.     place = (ulong)core_malloc(KERNEL_MEM, 3);
  218.     if (place != 0) {
  219.         nalloc_arena_add((void *)place,KERNEL_MEM);
  220.     }
  221.  
  222. /*
  223.  * find out where the screen is. We want to manage the screen
  224.  * memory along with all the other memory, so that Srealloc()
  225.  * can be used by the XBIOS to allocate screens from the
  226.  * end of memory -- this avoids fragmentation problems when
  227.  * changing resolutions.
  228.  */
  229. /* Note, however, that some graphics boards (e.g. Matrix)
  230.  * are unable to change the screen address. We fake out the
  231.  * rest of our code by pretending to have a really huge
  232.  * screen that can't be changed.
  233.  */
  234.     scrnplace = (long)Physbase();
  235.  
  236.     vscreen = (SCREEN *)((char *)lineA0() - 346);
  237.     if (FalconVideo) {
  238.     /* the Falcon can tell us the screen size */
  239.         scrnsize = VgetSize(Vsetmode(-1));
  240.     } else {
  241.     /* otherwise, use the line A variables */
  242.         scrnsize = (vscreen->maxy+1)*(long)vscreen->linelen;
  243.     }
  244.  
  245. /* check for a graphics card with fixed screen location */
  246. #define phys_top_st (*(ulong *)0x42eL)
  247.  
  248.     if (scrnplace >= phys_top_st) {
  249. /* screen isn't in ST RAM */
  250.         scrnsize = 0x7fffffffUL;
  251.         scrndone = 1;
  252.     } else {
  253.         temp = (ulong)core_malloc(scrnsize+256L, 0);
  254.         if (temp) {
  255.             (void)Setscreen((void *)-1L,
  256.                     (void *)((temp+511)&(0xffffff00L)), -1);
  257.             if ((long)Physbase() != (temp+511)&(0xffffff00L)) {
  258.                 scrnsize = 0x7fffffffUL;
  259.                 scrndone = 1;
  260.             }
  261.             (void)Setscreen((void *)-1L, (void *)scrnplace, -1);
  262.             core_free(temp);
  263.         }
  264.     }
  265.  
  266. /* initialize ST RAM */
  267.     size = (ulong)core_malloc(-1L, 0);
  268.     while (size > 0) {
  269.         place = (ulong)core_malloc(size, 0);
  270.         if (place + size == scrnplace) {
  271.             size += scrnsize;
  272.             scrndone = 1;
  273.         }
  274.         if (!add_region(core, place, size, M_CORE))
  275.             FATAL("init_mem: unable to add a region");
  276.         size = (ulong)core_malloc(-1L, 0);
  277.     }
  278.  
  279.     if (!scrndone) {
  280.         (void)add_region(core, scrnplace, scrnsize, M_CORE);
  281.     }
  282.  
  283. /* initialize alternate RAM */
  284.     size = (ulong)core_malloc(-1L, 1);
  285.     while (size > 0) {
  286.         place = (ulong)core_malloc(size, 1);
  287.         if (!add_region(alt, place, size, M_ALT))
  288.             FATAL("init_mem: unable to add a region");
  289.         size = (ulong)core_malloc(-1L, 1);
  290.     }
  291.  
  292.     (void)Mfree(tossave);        /* leave some memory for TOS to use */
  293. }
  294.  
  295. /*
  296.  * init_swap(): initialize the swap area; for now, this does nothing
  297.  */
  298.  
  299. MEMREGION *_swap_regions = 0;
  300. MMAP swap = &_swap_regions;
  301.  
  302. void
  303. init_swap()
  304. {
  305. }
  306.  
  307. /*
  308.  * routines for allocating/deallocating memory regions
  309.  */
  310.  
  311. /*
  312.  * new_region returns a new memory region descriptor, or NULL
  313.  */
  314.  
  315. MEMREGION *
  316. new_region()
  317. {
  318.     MEMREGION *m, *newfrees;
  319.     int i;
  320.  
  321.     m = rfreelist;
  322.     if (!m) {
  323.         ALERT("new_region: ran out of free regions");
  324.         return 0;
  325.     }
  326.     assert(ISFREE(m));
  327.     rfreelist = m->next;
  328.     m->next = 0;
  329.  
  330. /* if we're running low on free regions, allocate some more
  331.  * we have to do this with at least 1 free region left so that get_region
  332.  * has a chance of working
  333.  */
  334.     if (rfreelist && !rfreelist->next) {
  335.         MEMREGION *newstuff;
  336.  
  337.         TRACELOW(("get_region: getting new region descriptors"));
  338.         newstuff = get_region(ker, NEWREGIONS*SIZEOF(MEMREGION), PROT_S);
  339.         if (!newstuff)
  340.             newstuff = get_region(alt,NEWREGIONS*SIZEOF(MEMREGION), PROT_S);
  341.         if (!newstuff)
  342.             newstuff = get_region(core, NEWREGIONS*SIZEOF(MEMREGION), PROT_S);
  343.         newfrees = newstuff ? (MEMREGION *)newstuff->loc : 0;
  344.         if (newfrees) {
  345.             newfrees[NEWREGIONS-1].next = 0;
  346.             newfrees[NEWREGIONS-1].links = 0;
  347.             for (i = 0; i < NEWREGIONS-1; i++) {
  348.                 newfrees[i].next = &newfrees[i+1];
  349.                 newfrees[i].links = 0;
  350.             }
  351.             rfreelist = newfrees;
  352.         } else {
  353.             DEBUG(("couldn't get new region descriptors!"));
  354.         }
  355.     }
  356.  
  357.     return m;
  358. }
  359.  
  360. /*
  361.  * dispose_region destroys a memory region descriptor
  362.  */
  363.  
  364. void
  365. dispose_region(m)
  366.     MEMREGION *m;
  367. {
  368.     m->next = rfreelist;
  369.     rfreelist = m;
  370. }
  371.  
  372. /*
  373.  * change_prot_status: change the status of a region to 'newmode'.  We're
  374.  * given its starting address, not its region structure pointer, so we have
  375.  * to find the region pointer; since this is illegal if proc doesn't own
  376.  * the region, we know we'll find the region struct pointer in proc->mem.
  377.  *
  378.  * If the proc doesn't own it, you get EACCDN.  There are no other errors.
  379.  * God help you if newmode isn't legal!
  380.  */
  381.  
  382. long
  383. change_prot_status(proc,start,newmode)
  384. PROC *proc;
  385. long start;
  386. int newmode;
  387. {
  388.     MEMREGION **mr;
  389.     int i;
  390.  
  391.     /* return EACCDN if you don't own the region in question */
  392.     if (!proc->mem) return EACCDN;
  393.  
  394.     for (mr = proc->mem, i = 0; i < proc->num_reg; i++, mr++) {
  395.     if ((*mr)->loc == start) goto found;
  396.     }
  397.     return EACCDN;
  398.  
  399. found:
  400.     mark_region(*mr,newmode);
  401.     return E_OK;
  402. }
  403.  
  404. /*
  405.  * virtaddr
  406.  * attach_region(proc, reg): attach the region to the given process:
  407.  * returns the address at which it was attached, or NULL if the process
  408.  * cannot attach more regions. The region link count is incremented if
  409.  * the attachment is successful.
  410.  *
  411.  * Calls mark_region on the region to mark this process as an owner.
  412.  * This is redundant since it executes a complicated no-op for every
  413.  * other process in the system.  Sigh.
  414.  */
  415.  
  416. virtaddr
  417. attach_region(proc, reg)
  418.     PROC *proc;
  419.     MEMREGION *reg;
  420. {
  421.     int i;
  422.     MEMREGION **newmem;
  423.     virtaddr *newaddr;
  424.  
  425.     TRACELOW(("attach_region %lx len %lx to pid %d",
  426.         reg->loc, reg->len, proc->pid));
  427.  
  428.     if (!reg || !reg->loc) {
  429.         ALERT("attach_region: attaching a null region??");
  430.         return 0;
  431.     }
  432.  
  433. again:
  434.     for (i = 0; i < proc->num_reg; i++) {
  435.         if (!proc->mem[i]) {
  436.             assert(proc->addr[i] == 0);
  437.             reg->links++;
  438.             proc->mem[i] = reg;
  439.             proc->addr[i] = (virtaddr) reg->loc;
  440.             mark_region(reg,PROT_NOCHANGE);
  441.             return proc->addr[i];
  442.         }
  443.     }
  444.  
  445. /* Hmmm, OK, we have to expand the process' memory table */
  446.     TRACELOW(("Expanding process memory table"));
  447.     i = proc->num_reg + NUM_REGIONS;
  448.  
  449.     newmem = kmalloc(i * SIZEOF(MEMREGION *));
  450.     newaddr = kmalloc(i * SIZEOF(virtaddr));
  451.  
  452.     if (newmem && newaddr) {
  453.     /*
  454.      * We have to use temps while allocating and freeing mem
  455.      * and addr so the memory protection code won't walk this
  456.      * process' memory list in the middle.
  457.      */
  458.         void *pmem, *paddr;
  459.  
  460.     /* copy over the old address mapping */
  461.         for (i = 0; i < proc->num_reg; i++) {
  462.             newmem[i] = proc->mem[i];
  463.             newaddr[i] = proc->addr[i];
  464.             if (newmem[i] == 0)
  465.                 assert(newaddr[i] == 0);
  466.         }
  467.     /* initialize the rest of the tables */
  468.         for(; i < proc->num_reg + NUM_REGIONS; i++) {
  469.             newmem[i] = 0;
  470.             newaddr[i] = 0;
  471.         }
  472.     /* free the old tables (carefully! for memory protection) */
  473.         pmem = proc->mem;
  474.         paddr = proc->addr;
  475.         proc->mem = NULL;
  476.         proc->addr = NULL;
  477.         kfree(pmem); kfree(paddr);
  478.         proc->mem = newmem;
  479.         proc->addr = newaddr;
  480.         proc->num_reg += NUM_REGIONS;
  481.     /* this time we will succeed */
  482.         goto again;
  483.     } else {
  484.         if (newmem) kfree(newmem);
  485.         if (newaddr) kfree(newaddr);
  486.         DEBUG(("attach_region: failed"));
  487.         return 0;
  488.     }
  489. }
  490.  
  491. /*
  492.  * detach_region(proc, reg): remove region from the procedure's address
  493.  * space. If no more processes reference the region, return it to the
  494.  * system. Note that we search backwards, so that the most recent
  495.  * attachment of memory gets detached!
  496.  *
  497.  * Calls mark_region on the region to mark this process as a non-owner.
  498.  * This is redundant since it executes a complicated no-op for every
  499.  * other process in the system.  Sigh.
  500.  */
  501.  
  502. void
  503. detach_region(proc, reg)
  504.     PROC *proc;
  505.     MEMREGION *reg;
  506. {
  507.     int i;
  508.  
  509.     if (!reg) return;
  510.  
  511.     TRACELOW(("detach_region %lx len %lx from pid %d",
  512.         reg->loc, reg->len, proc->pid));
  513.  
  514.     for (i = proc->num_reg - 1; i >= 0; i--) {
  515.         if (proc->mem[i] == reg) {
  516.             reg->links--;
  517.             proc->mem[i] = 0; proc->addr[i] = 0;
  518.             if (reg->links == 0) {
  519.                 free_region(reg);
  520.             }
  521.             else {
  522.                 /* cause curproc's table to be updated */
  523.                 mark_region(reg,PROT_NOCHANGE);
  524.             }
  525.             return;
  526.         }
  527.     }
  528.     DEBUG(("detach_region: region not attached"));
  529. }
  530.  
  531. /*
  532.  * get_region(MMAP map, ulong size, int mode) -- allocate a new region of the
  533.  * given size in the given memory map. if no region big enough is available,
  534.  * return NULL, otherwise return a pointer to the region.
  535.  * "mode" tells us about memory protection modes
  536.  *
  537.  * the "links" field in the region is set to 1
  538.  *
  539.  * BEWARE: new_region may call get_region (indirectly), so we have to be
  540.  * _very_ careful with re-entrancy in this function
  541.  */
  542.  
  543. MEMREGION *
  544. get_region(map, size, mode)
  545.     MMAP map;
  546.     ulong size;
  547.     int mode;
  548. {
  549.     MEMREGION *m, *n;
  550.  
  551.     TRACELOW(("get_region(%s,%lx,%x)",
  552.         (map == ker ? "ker" : (map == core ? "core" : "alt")),
  553.         size, mode));
  554.  
  555. /* precautionary measures */
  556.     if (size == 0) {
  557.         DEBUG(("request for 0 bytes??"));
  558.         size = 1;
  559.     }
  560.  
  561.     size = ROUND(size);
  562.  
  563.     n = *map;
  564.  
  565.     sanity_check(map);
  566. /* exact matches are likely to be rare, so we pre-allocate a new
  567.  * region here; this helps us to avoid re-entrancy problems
  568.  * when new_region calls get_region
  569.  */
  570.     m = new_region();
  571.  
  572.     while (n) {
  573.         if (ISFREE(n)) {
  574.             if (n->len == size) {
  575.                 if (m) dispose_region(m);
  576.                 n->links++;
  577.                 goto win;
  578.             }
  579.             else if (n->len > size) {
  580. /* split a new region, 'm', which will contain the free bytes after n */
  581.                 if (m) {
  582.                     m->next = n->next;
  583.                     n->next = m;
  584.                     m->mflags = n->mflags & M_MAP;
  585.                     m->loc = n->loc + size;
  586.                     m->len = n->len - size;
  587.                     n->len = size;
  588.                     n->links++;
  589.                     goto win;
  590.                 } else {
  591.                     DEBUG(("get_region: no regions left"));
  592.                     return 0;
  593.                 }
  594.             }
  595.         }
  596.         n = n->next;
  597.     }
  598.  
  599.     if (m)
  600.         dispose_region(m);
  601.  
  602.     TRACELOW(("get_region: no memory left in this map"));
  603.     return NULL;
  604.  
  605. win:
  606.     mark_region(n, mode & PROT_PROTMODE);
  607.     if (mode & M_KEEP) n->mflags |= M_KEEP;
  608.  
  609.     return n;
  610. }
  611.  
  612. /*
  613.  * free_region(MEMREGION *reg): free the indicated region. The map
  614.  * in which the region is contained is given by reg->mflags.
  615.  * the caller is responsible for making sure that the region
  616.  * really should be freed, i.e. that reg->links == 0.
  617.  *
  618.  * special things to do:
  619.  * if the region is a shared text region, we must close the
  620.  * associated file descriptor
  621.  */
  622.  
  623. void
  624. free_region(reg)
  625.     MEMREGION *reg;
  626. {
  627.     MMAP map;
  628.     MEMREGION *m;
  629.     SHTEXT *s, **old;
  630.  
  631.     if (!reg) return;
  632.  
  633.     assert(ISFREE(reg));
  634.  
  635.     if (reg->mflags & M_SHTEXT) {
  636.         TRACE(("freeing shared text region"));
  637.         old = &text_reg;
  638.         for(;;) {
  639.             s = *old;
  640.             if (!s) break;
  641.             if (s->text == reg) {
  642.                 if (s->f)
  643.                     do_close(s->f);
  644.                 *old = s->next;
  645.                 kfree(s);
  646.                 break;
  647.             }
  648.             old = &s->next;
  649.         }
  650.         if (!s) {
  651.             DEBUG(("No shared text entry for M_SHTEXT region??"));
  652.         }
  653.     }
  654.  
  655.     if (reg->mflags & M_CORE)
  656.         map = core;
  657.     else if (reg->mflags & M_ALT)
  658.         map = alt;
  659.     else if (reg->mflags & M_KER)
  660.         map = ker;
  661.     else {
  662.         FATAL("free_region: region flags not valid (%x)", reg->mflags);
  663.     }
  664.     reg->mflags &= M_MAP;
  665.  
  666. /* unhook any vectors pointing into this region */
  667.     unlink_vectors(reg->loc, reg->loc + reg->len);
  668.  
  669. /* BUG(?): should invalidate caches entries - a copyback cache could stuff
  670.  * things into freed memory.
  671.  *    cinv(reg->loc, reg->len);
  672.  */
  673.     m = *map;
  674.     assert(m);
  675.  
  676.     /* MEMPROT: invalidate */
  677.     if (map == core || map == alt)
  678.         mark_region(reg,PROT_I);
  679.  
  680.     if (m == reg) goto merge_after;
  681.  
  682. /* merge previous region if it's free and contiguous with 'reg' */
  683.  
  684. /* first, we find the region */
  685.     while (m && m->next != reg)
  686.         m = m->next;
  687.  
  688.     if (m == NULL) {
  689.         FATAL("couldn't find region %lx: loc: %lx len: %ld",
  690.             reg, reg->loc, reg->len);
  691.     }
  692.  
  693.     if (ISFREE(m) && (m->loc + m->len == reg->loc)) {
  694.         m->len += reg->len;
  695.         assert(m->next == reg);
  696.         m->next = reg->next;
  697.         reg->next = 0;
  698.         dispose_region(reg);
  699.         reg = m;
  700.     }
  701.  
  702. /* merge next region if it's free and contiguous with 'reg' */
  703. merge_after:
  704.     m = reg->next;
  705.     if (m && ISFREE(m) && reg->loc + reg->len == m->loc) {
  706.         reg->len += m->len;
  707.         reg->next = m->next;
  708.         m->next = 0;
  709.         dispose_region(m);
  710.     }
  711.  
  712.     sanity_check(map);
  713. }
  714.  
  715. /*
  716.  * shrink_region(MEMREGION *reg, ulong newsize):
  717.  *   shrink region 'reg', so that it is now 'newsize' bytes long.
  718.  *   if 'newsize' is bigger than the region's current size, return EGSBF;
  719.  *   otherwise return 0.
  720.  */
  721.  
  722. long
  723. shrink_region(reg, newsize)
  724.     MEMREGION *reg;
  725.     ulong newsize;
  726. {
  727.     MEMREGION *n;
  728.     ulong diff;
  729.  
  730.  
  731.     newsize = ROUND(newsize);
  732.  
  733.     assert(reg->links > 0);
  734.  
  735.     if (!(reg->mflags & (M_CORE | M_ALT | M_KER))) {
  736.         FATAL("shrink_region: bad region flags (%x)", reg->mflags);
  737.     }
  738.  
  739. /* shrinking to 0 is the same as freeing */
  740.     if (newsize == 0) {
  741.         detach_region(curproc, reg);
  742.         return 0;
  743.     }
  744.  
  745. /* if new size is the same as old size, don't do anything */
  746.     if (newsize == reg->len) {
  747.         return 0;    /* nothing to do */
  748.     }
  749.  
  750.     if (newsize > reg->len) {
  751.         DEBUG(("shrink_region: request to make region bigger"));
  752.         return EGSBF;    /* growth failure */
  753.     }
  754.  
  755. /* OK, we're going to free (reg->len - newsize) bytes at the end of
  756.    this block. If the block after us is already free, simply add the
  757.    space to that block.
  758.  */
  759.     n = reg->next;
  760.     diff = reg->len - newsize;
  761.  
  762.     if (n && ISFREE(n) && reg->loc + reg->len == n->loc) {
  763.         reg->len = newsize;
  764.         n->loc -= diff;
  765.         n->len += diff;
  766.         /* MEMPROT: invalidate the second half */
  767.         /* (part of it is already invalid; that's OK) */
  768.         mark_region(n,PROT_I);
  769.  
  770.         return 0;
  771.     }
  772.     else {
  773.         n = new_region();
  774.         if (!n) {
  775.             DEBUG(("shrink_region: new_region failed"));
  776.             return EINTRN;
  777.         }
  778.         reg->len = newsize;
  779.         n->loc = reg->loc + newsize;
  780.         n->len = diff;
  781.         n->mflags = reg->mflags & M_MAP;
  782.         n->next = reg->next;
  783.         reg->next = n;
  784.         /* MEMPROT: invalidate the new, free region */
  785.         mark_region(n,PROT_I);
  786.     }
  787.     return 0;
  788. }
  789.  
  790. /*
  791.  * max_rsize(map): return the length of the biggest free region
  792.  * in the given memory map, or 0 if no regions remain.
  793.  */
  794.  
  795. long
  796. max_rsize(map)
  797.     MMAP map;
  798. {
  799.     MEMREGION *m;
  800.     long size = 0;
  801.  
  802.     for (m = *map; m; m = m->next) {
  803.         if (ISFREE(m)) {
  804.             if (m->len > size) {
  805.                 size = m->len;
  806.             }
  807.         }
  808.     }
  809.     return size;
  810. }
  811.  
  812. /*
  813.  * tot_rsize(map, flag): if flag == 1, return the total number of bytes in
  814.  * the given memory map; if flag == 0, return only the number of free
  815.  * bytes
  816.  */
  817.  
  818. long
  819. tot_rsize(map, flag)
  820.     MMAP map;
  821.     int flag;
  822. {
  823.     MEMREGION *m;
  824.     long size = 0;
  825.  
  826.     for (m = *map; m; m = m->next) {
  827.         if (flag || ISFREE(m)) {
  828.             size += m->len;
  829.         }
  830.     }
  831.     return size;
  832. }
  833.  
  834. /*
  835.  * alloc_region(MMAP map, ulong size, int mode): allocate a new region and
  836.  * attach it to the current process; returns the address at which the region
  837.  * was attached, or NULL. The mode argument is the memory protection mode to
  838.  * give to get_region, and in turn to mark_region.
  839.  */
  840.  
  841. virtaddr
  842. alloc_region(map, size, mode)
  843.     MMAP map;
  844.     ulong size;
  845.     int mode;
  846. {
  847.     MEMREGION *m;
  848.     PROC *proc = curproc;
  849.     virtaddr v;
  850.  
  851.     TRACELOW(("alloc_region(map,size: %lx,mode: %x)",size,mode));
  852.     if (!size) {
  853.         DEBUG(("alloc_region of zero bytes?!"));
  854.         return 0;
  855.     }
  856.  
  857.     m = get_region(map, size, mode);
  858.     if (!m) {
  859.         TRACELOW(("alloc_region: get_region failed"));
  860.         return 0;
  861.     }
  862.  
  863. /* sanity check: even addresses only, please */
  864.     assert((m->loc & MASKBITS) == 0);
  865.  
  866.     v = attach_region(proc, m);
  867. /* NOTE: get_region returns a region with link count 1; since attach_region
  868.  * increments the link count, we restore it after calling attach_region
  869.  */
  870.     m->links = 1;
  871.     if (!v) {
  872.         m->links = 0;
  873.         free_region(m);
  874.         TRACE(("alloc_region: attach_region failed"));
  875.         return 0;
  876.     }
  877.     return v;
  878. }
  879.  
  880. /*
  881.  * routines for creating a copy of an environment, and a new basepage.
  882.  * note that the memory regions created should immediately be attached to
  883.  * a process! Also note that create_env always operates in ST RAM, but
  884.  * create_base might not.
  885.  */
  886.  
  887. MEMREGION *
  888. create_env(env)
  889.     const char *env;
  890. {
  891.     long size;
  892.     MEMREGION *m;
  893.     virtaddr v;
  894.     const char *old;
  895.     char *new;
  896.  
  897.     if (!env) {
  898.         env = ((BASEPAGE *)curproc->base)->p_env;
  899.             /* duplicate parent's environment */
  900.     }
  901.     size = 2;
  902.     old = env;
  903.     while (*env || *(env+1))
  904.         env++,size++;
  905.  
  906.     v = alloc_region(core, size, PROT_P);
  907.     /* if core fails, try alt */
  908.     if (!v)
  909.         v = alloc_region(alt, size, PROT_P);
  910.  
  911.     if (!v) {
  912.         DEBUG(("create_env: alloc_region failed"));
  913.         return (MEMREGION *)0;
  914.     }
  915.     m = addr2mem(v);
  916.  
  917. /* copy the old environment into the new */
  918.     new = (char *) m->loc;
  919.     TRACE(("copying environment: from %lx to %lx", old, new));
  920.     while (size > 0) {
  921.         *new++ = *old++;
  922.         --size;
  923.     }
  924.     TRACE(("finished copying environment"));
  925.  
  926.     return m;
  927. }
  928.  
  929. MEMREGION *
  930. create_base(cmd, env, flags, prgsize)
  931.     const char *cmd;
  932.     MEMREGION *env;
  933.     ulong flags, prgsize;
  934. {
  935.     long len, coresize, altsize;
  936.     MMAP map;
  937.     MEMREGION *m;
  938.     BASEPAGE *b;
  939.     short protmode;
  940.  
  941. /* if flags & F_ALTLOAD == 1, then we might decide to load in alternate
  942.    RAM if enough is available. "enough" is: if more alt ram than ST ram,
  943.    load there; otherwise, if more than (minalt+1)*128K alt ram available
  944.    for heap space, load in alt ram ("minalt" is the high byte of flags)
  945.  */
  946.     if (flags & F_ALTLOAD) {
  947.         coresize = max_rsize(core);
  948.         altsize = max_rsize(alt);
  949.         if (altsize >= coresize)
  950.             map = alt;
  951.         else {
  952.             len = (flags & F_MINALT) >> 28L;
  953.             len = (len+1)*128*1024L + prgsize + 256;
  954.             if (altsize >= len)
  955.                 map = alt;
  956.             else
  957.                 map = core;
  958.         }
  959.     }
  960.     else
  961.         map = core;
  962.  
  963.     len = max_rsize(map);
  964.     if (len < prgsize) {
  965.         /* can't possibly load this file in its eligible regions */
  966.         DEBUG(("create_base: max_rsize smaller than prgsize"));
  967.         return 0;
  968.     }
  969.  
  970. /* make sure that a little bit of memory is left over */
  971.     if (len > 2*KEEP_MEM) {
  972.         len -= KEEP_MEM;
  973.     }
  974.  
  975.     protmode = (flags & F_PROTMODE) >> F_PROTSHIFT;
  976.  
  977.     m = addr2mem(alloc_region(map, len, protmode));
  978.     if (!m) {
  979.         DEBUG(("create_base: alloc_region failed"));
  980.         return 0;
  981.     }
  982.     b = (BASEPAGE *)(m->loc);
  983.  
  984.     zero((char *)b, (long)sizeof(BASEPAGE));
  985.     b->p_lowtpa = (long)b;
  986.     b->p_hitpa = m->loc + m->len;
  987.     b->p_env = (char *)env->loc;
  988.     b->p_flags = flags;
  989.  
  990.     if (cmd)
  991.         strncpy(b->p_cmdlin, cmd, 126);
  992.     return m;
  993. }
  994.  
  995. /*
  996.  * load_region(): loads the program with the given file name
  997.  * into a new region, and returns a pointer to that region. On
  998.  * an error, returns 0 and leaves the error number in mint_errno.
  999.  * "env" points to an already set up environment region, as returned
  1000.  * by create_env. On success, "xp" points to the file attributes, which
  1001.  * Pexec has already determined, and "fp" points to the programs
  1002.  * prgflags. "text" is a pointer to a MEMREGION
  1003.  * pointer, which will be set to the region occupied by the shared
  1004.  * text segment of this program (if applicable).
  1005.  */
  1006.  
  1007. MEMREGION *
  1008. load_region(filename, env, cmdlin, xp, text, fp)
  1009.     const char *filename;
  1010.     MEMREGION *env;
  1011.     const char *cmdlin;
  1012.     XATTR *xp;        /* attributes for the file just loaded */
  1013.     MEMREGION **text;    /* set to point to shared text region,
  1014.                    if any */
  1015.     long *fp;        /* prgflags for this file */
  1016. {
  1017.     FILEPTR *f;
  1018.     DEVDRV *dev;
  1019.     MEMREGION *reg, *shtext;
  1020.     BASEPAGE *b;
  1021.     long size, start;
  1022.     FILEHEAD fh;
  1023.  
  1024. /* bug: this should be O_DENYW mode, not O_DENYNONE */
  1025. /* we must use O_DENYNONE because of the desktop and because of the
  1026.  * TOS file system brain-damage
  1027.  */
  1028.     f = do_open(filename, O_DENYNONE | O_EXEC, 0, xp);
  1029.     if (!f) {
  1030.         return 0;        /* mint_errno set by do_open */
  1031.     }
  1032.  
  1033.     dev = f->dev;
  1034.     size = (*dev->read)(f, (void *)&fh, (long)sizeof(fh));
  1035.     if (fh.fmagic != GEMDOS_MAGIC || size != (long)sizeof(fh)) {
  1036.         DEBUG(("load_region: file not executable"));
  1037.         mint_errno = ENOEXEC;
  1038. failed:
  1039.         do_close(f);
  1040.         return 0;
  1041.     }
  1042.  
  1043.     *fp = fh.flag;
  1044.  
  1045.     if (fh.flag & F_SHTEXT) {
  1046.         TRACE(("loading shared text segment"));
  1047.         shtext = get_text_seg(f, &fh, xp);
  1048.         if (!shtext) {
  1049.             DEBUG(("load_region: unable to get shared text segment"));
  1050. /* mint_errno set in get_text_seg */
  1051.             goto failed;
  1052.         }
  1053.         size = fh.fdata + fh.fbss;
  1054.     } else {
  1055.         size = fh.ftext + fh.fdata + fh.fbss;
  1056.         shtext = 0;
  1057.     }
  1058.  
  1059.     reg = create_base(cmdlin, env, fh.flag, size);
  1060.     if (reg && size+1024L > reg->len) {
  1061.         DEBUG(("load_region: insufficient memory to load"));
  1062.         detach_region(curproc, reg);
  1063.         reg = 0;
  1064.     }
  1065.  
  1066.     if (reg == 0) {
  1067.         if (shtext) {
  1068.             detach_region(curproc, shtext);
  1069.         }
  1070.         mint_errno = ENSMEM;
  1071.         goto failed;
  1072.     }
  1073.  
  1074.     b = (BASEPAGE *)reg->loc;
  1075.     b->p_flags = fh.flag;
  1076.     if (shtext) {
  1077.         b->p_tbase = shtext->loc;
  1078.         b->p_tlen = 0;
  1079.         b->p_dbase = b->p_lowtpa + 256;
  1080.     } else {
  1081.         b->p_tbase = b->p_lowtpa + 256;
  1082.         b->p_tlen = fh.ftext;
  1083.         b->p_dbase = b->p_tbase + b->p_tlen;
  1084.     }
  1085.     b->p_dlen = fh.fdata;
  1086.     b->p_bbase = b->p_dbase + b->p_dlen;
  1087.     b->p_blen = fh.fbss;
  1088.  
  1089. /* if shared text, then we start loading at the end of the
  1090.  * text region, since that is already set up
  1091.  */
  1092.     if (shtext) {
  1093.     /* skip over text info */
  1094.         size = fh.fdata;
  1095.         start = fh.ftext;
  1096.     } else {
  1097.         size = fh.ftext + fh.fdata;
  1098.         start = 0;
  1099.     }
  1100.  
  1101.     mint_errno = (int)load_and_reloc(f, &fh, (char *)b+256, start,
  1102.             size, b);
  1103.  
  1104.     if (mint_errno) {
  1105.         detach_region(curproc, reg);
  1106.         if (shtext) detach_region(curproc, shtext);
  1107.         goto failed;
  1108.     }
  1109.  
  1110.     if (fh.flag & F_FASTLOAD)            /* fastload bit */
  1111.         size = b->p_blen;
  1112.     else
  1113.         size = b->p_hitpa - b->p_bbase;
  1114.     zero((char *)b->p_bbase, size);
  1115.  
  1116.     do_close(f);
  1117.     *text = shtext;
  1118.     return reg;
  1119. }
  1120.  
  1121. /*
  1122.  * load_and_reloc(f, fh, where, start, nbytes): load and relocate from
  1123.  * the open GEMDOS executable file f "nbytes" bytes starting at offset
  1124.  * "start" (relative to the end of the file header, i.e. from the first
  1125.  * byte of the actual program image in the file). "where" is the address
  1126.  * in (physical) memory into which the loaded image must be placed; it is
  1127.  * assumed that "where" is big enough to hold "nbytes" bytes!
  1128.  */
  1129.  
  1130. long
  1131. load_and_reloc(f, fh, where, start, nbytes, base)
  1132.     FILEPTR *f;
  1133.     FILEHEAD *fh;
  1134.     char *where;
  1135.     long start;
  1136.     long nbytes;
  1137.     BASEPAGE *base;
  1138. {
  1139.     unsigned char c, *next;
  1140.     long r;
  1141.     DEVDRV *dev;
  1142. #define LRBUFSIZ 8196
  1143.     static unsigned char buffer[LRBUFSIZ];
  1144.     long fixup, size, bytes_read;
  1145.     long reloc;
  1146.  
  1147.  
  1148. TRACE(("load_and_reloc: %ld to %ld at %lx", start, nbytes+start, where));
  1149.     dev = f->dev;
  1150.  
  1151.     r = (*dev->lseek)(f, start+sizeof(FILEHEAD), SEEK_SET);
  1152.     if (r < 0) return r;
  1153.     r = (*dev->read)(f, where, nbytes);
  1154.     if (r != nbytes) {
  1155.         DEBUG(("load_region: unexpected EOF"));
  1156.         return ENOEXEC;
  1157.     }
  1158.  
  1159. /* now do the relocation */
  1160. /* skip over symbol table, etc. */
  1161.     r = (*dev->lseek)(f, sizeof(FILEHEAD) + fh->ftext + fh->fdata +
  1162.             fh->fsym, SEEK_SET);
  1163.     if (r < 0) return ENOEXEC;
  1164.  
  1165.     if (fh->reloc != 0 || (*dev->read)(f, (char *)&fixup, 4L) != 4L
  1166.         || fixup == 0) {
  1167.         return 0;    /* no relocation to be performed */
  1168.     }
  1169.  
  1170.     size = LRBUFSIZ;
  1171.     bytes_read = 0;
  1172.     next = buffer;
  1173.  
  1174.     do {
  1175.         if (fixup >= nbytes + start) {
  1176.             TRACE(("load_region: end of relocation at %ld", fixup));
  1177.             break;
  1178.         }
  1179.         else if (fixup >= start) {
  1180.             reloc = *((long *)(where + fixup - start));
  1181.             if (reloc < fh->ftext) {
  1182.                 reloc += base->p_tbase;
  1183.             } else if (reloc < fh->ftext + fh->fdata && base->p_dbase) {
  1184.                 reloc += base->p_dbase - fh->ftext;
  1185.             } else if (reloc < fh->ftext + fh->fdata + fh->fbss && base->p_bbase) {
  1186.                 reloc += base->p_bbase - (fh->ftext + fh->fdata);
  1187.             } else {
  1188.                 DEBUG(("load_region: bad relocation: %ld", reloc));
  1189.                 if (base->p_dbase)
  1190.                     reloc += base->p_dbase - fh->ftext;    /* assume data reloc */
  1191.                 else if (base->p_bbase)
  1192.                     reloc += base->p_bbase - (fh->ftext + fh->fdata);
  1193.                 else
  1194.                     return ENOEXEC;
  1195.             }
  1196.             *((long *)(where + fixup - start)) = reloc;
  1197.         }
  1198.         do {
  1199.             if (!bytes_read) {
  1200.                 bytes_read =
  1201.                     (*dev->read)(f,(char *)buffer,size);
  1202.                 next = buffer;
  1203.             }
  1204.             if (bytes_read < 0) {
  1205.                 DEBUG(("load_region: EOF in relocation"));
  1206.                 return ENOEXEC;
  1207.             }
  1208.             else if (bytes_read == 0)
  1209.                 c = 0;
  1210.             else {
  1211.                 c = *next++; bytes_read--;
  1212.             }
  1213.             if (c == 1) fixup += 254;
  1214.         } while (c == 1);
  1215.         fixup += ( (unsigned) c) & 0xff;
  1216.     } while (c);
  1217.  
  1218.     return 0;
  1219. }
  1220.  
  1221. /*
  1222.  * function to check for existence of a shared text region
  1223.  * corresponding to file "f", and if none is found, to create one
  1224.  * the memory region being returned is attached to the current
  1225.  * process
  1226.  */
  1227.  
  1228. MEMREGION *
  1229. get_text_seg(f, fh, xp)
  1230.     FILEPTR *f;
  1231.     FILEHEAD *fh;
  1232.     XATTR *xp;
  1233. {
  1234.     SHTEXT *s;
  1235.     MEMREGION *m;
  1236.     long r;
  1237.     BASEPAGE b;
  1238.  
  1239.     s = text_reg;
  1240.  
  1241.     while(s) {
  1242.         if (s->f && samefile(&f->fc, &s->f->fc) &&
  1243.             xp->mtime == s->mtime &&
  1244.             xp->mdate == s->mdate)
  1245.         {
  1246.             m = s->text;
  1247.             if (attach_region(curproc, m)) {
  1248. TRACE(("re-using shared text region %lx", m));
  1249.                 return m;
  1250.             }
  1251.             else {
  1252.                 mint_errno = ENSMEM;
  1253.                 return 0;
  1254.             }
  1255.         }
  1256.         s = s->next;
  1257.     }
  1258.  
  1259. /* hmmm, not found; OK, we'll have to create a new text region */
  1260.  
  1261.     s = kmalloc(SIZEOF(SHTEXT));
  1262.     if (!s) {
  1263.         mint_errno = ENSMEM;
  1264.         return 0;
  1265.     }
  1266.     m = 0;
  1267. /* actually, I can't see why loading in TT RAM is ever undesireable,
  1268.  * since shared text programs should be very clean (and since only
  1269.  * the text segment is going in there). But better safe than sorry.
  1270.  */
  1271.     if (fh->flag & F_ALTLOAD) {
  1272.         m = addr2mem(alloc_region(alt, fh->ftext, PROT_P));
  1273.     }
  1274.     if (!m)
  1275.         m = addr2mem(alloc_region(core, fh->ftext, PROT_P));
  1276.  
  1277.     if (!m) {
  1278.         kfree(s);
  1279.         mint_errno = ENSMEM;
  1280.         return 0;
  1281.     }
  1282.  
  1283. /* set up a fake "basepage" for load_and_reloc
  1284.  * note: the 0 values should make load_and_reloc
  1285.  * barf on any attempts at data relocation, since we have
  1286.  * no data segment
  1287.  */
  1288. TRACE(("attempting to create shared text region"));
  1289.  
  1290.     b.p_tbase = m->loc;
  1291.     b.p_tlen = fh->ftext;
  1292.     b.p_dbase = 0;
  1293.     b.p_dlen = 0;
  1294.     b.p_bbase = b.p_blen = 0;
  1295.  
  1296.     r = load_and_reloc(f, fh, (char *)m->loc, 0, fh->ftext, &b);
  1297.     if (r) {
  1298.         m->links = 0;
  1299.         detach_region(curproc, m);
  1300.         kfree(s);
  1301.         return 0;
  1302.     }
  1303.  
  1304. /* region has valid shared text data */
  1305.     m->mflags |= M_SHTEXT;
  1306.  
  1307. /*
  1308.  * KLUDGE: to make sure we always have up to date shared text
  1309.  * info, even across a network, we leave the file passed
  1310.  * to us open with DENYWRITE mode, so that nobody will
  1311.  * modify it.
  1312.  */
  1313.     f->links++;    /* keep the file open longer */
  1314.  
  1315. /* BUG: what if someone already has the file open for
  1316.  * writing? Then we could get screwed...
  1317.  */
  1318.     f->flags = (f->flags & ~O_SHMODE) | O_DENYW;
  1319.     s->f = f;
  1320.     s->text = m;
  1321.     s->next = text_reg;
  1322.     s->mtime = xp->mtime;
  1323.     s->mdate = xp->mdate;
  1324.     text_reg = s;
  1325. TRACE(("shared text region %lx created", m));
  1326.     return m;
  1327. }
  1328.  
  1329. /*
  1330.  * exec_region(p, mem, thread): create a child process out of a mem region
  1331.  * "p" is the process structure set up by the parent; it may be "curproc",
  1332.  * if we're overlaying. "mem" is the loaded memory region returned by
  1333.  * "load region". Any open files (other than the standard handles) owned
  1334.  * by "p" are closed, and if thread !=0 all memory is released; the caller
  1335.  * must explicitly attach the environment and base region. The caller must
  1336.  * also put "p" on the appropriate queue (most likely READY_Q).
  1337.  */
  1338.  
  1339. extern long mint_dos(), mint_bios();
  1340.  
  1341. void rts() {}        /* dummy termination routine */
  1342.  
  1343. PROC *
  1344. exec_region(p, mem, thread)
  1345.     PROC      *p;
  1346.     MEMREGION *mem;
  1347.     int thread;
  1348. {
  1349.     BASEPAGE *b;
  1350.     FILEPTR *f;
  1351.     int i;
  1352.     MEMREGION *m;
  1353.  
  1354.     TRACE(("exec_region"));
  1355.  
  1356.     b = (BASEPAGE *) mem->loc;
  1357.  
  1358.     cpush((void *)b->p_tbase, b->p_tlen);    /* flush cached versions of the text */
  1359.     
  1360. /* set some (undocumented) variables in the basepage */
  1361.     b->p_defdrv = p->curdrv;
  1362.     for (i = 0; i < 6; i++)
  1363.         b->p_devx[i] = i;
  1364.  
  1365.     p->dta = (DTABUF *)(b->p_dta = &b->p_cmdlin[0]);
  1366.     p->base = b;
  1367.  
  1368. /* close extra open files */
  1369.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  1370.         if ( (f = p->handle[i]) != 0 && (p->fdflags[i] & FD_CLOEXEC) ) {
  1371.             do_pclose(p, f);
  1372.             p->handle[i] = 0;
  1373.         }
  1374.     }
  1375.  
  1376. /* initialize memory */
  1377.     recalc_maxmem(p);
  1378.     if (p->maxmem) {
  1379.         shrink_region(mem, p->maxmem);
  1380.         b->p_hitpa = b->p_lowtpa + mem->len;
  1381.     }
  1382.  
  1383.     p->memflags = b->p_flags;
  1384.  
  1385.     if (!thread) {
  1386.         for (i = 0; i < p->num_reg; i++) {
  1387.             m = p->mem[i];
  1388.             if (m) {
  1389.                 m->links--;
  1390.                 if (m->links <= 0)
  1391.                     free_region(m);
  1392.             }
  1393.         }
  1394.         if (p->num_reg > NUM_REGIONS) {
  1395.             /*
  1396.              * If the proc struct has a larger mem array than
  1397.              * the default, then free it and allocate a
  1398.              * default-sized one.
  1399.              */
  1400.  
  1401.             /*
  1402.              * hoo ha! Memory protection problem here. Use
  1403.              * temps and pre-clear p->mem so memprot doesn't try
  1404.              * to walk these structures as we're freeing and
  1405.              * reallocating them!  (Calling kmalloc can cause
  1406.              * a table walk if the alloc results in calling
  1407.              * get_region.)
  1408.              */
  1409.             void *pmem, *paddr;
  1410.  
  1411.             pmem = p->mem;
  1412.             paddr = p->addr;
  1413.             p->mem = NULL; p->addr = NULL;
  1414.             kfree(pmem); kfree(paddr);
  1415.  
  1416.             pmem = kmalloc(NUM_REGIONS * SIZEOF(MEMREGION *));
  1417.             paddr = kmalloc(NUM_REGIONS * SIZEOF(virtaddr));
  1418.             assert(pmem && paddr);
  1419.             p->mem = pmem;
  1420.             p->addr = paddr;
  1421.             p->num_reg = NUM_REGIONS;
  1422.         }
  1423.         zero((char *)p->mem, (p->num_reg)*SIZEOF(MEMREGION *));
  1424.         zero((char *)p->addr, (p->num_reg)*SIZEOF(virtaddr));
  1425.     }
  1426.  
  1427. /* initialize signals */
  1428.     p->sigmask = 0;
  1429.     for (i = 0; i < NSIG; i++) {
  1430.         if (p->sighandle[i] != SIG_IGN) {
  1431.             p->sighandle[i] = SIG_DFL;
  1432.             p->sigflags[i] = 0;
  1433.             p->sigextra[i] = 0;
  1434.         }
  1435.     }
  1436.  
  1437. /* zero the user registers, and set the FPU in a "clear" state */
  1438.     for (i = 0; i < 15; i++)
  1439.         p->ctxt[CURRENT].regs[i] = 0;
  1440.     p->ctxt[CURRENT].sr = 0;
  1441.     p->ctxt[CURRENT].fstate[0] = 0;
  1442.  
  1443. /* set PC, stack registers, etc. appropriately */
  1444.     p->ctxt[CURRENT].pc = b->p_tbase;
  1445.  
  1446. /* The "-0x20" is to make sure that syscall.s won't run past the end of
  1447.  * memory when the user makes a system call and doesn't push very many
  1448.  * parameters -- syscall always tries to copy the maximum possible number
  1449.  * of parms.
  1450.  *
  1451.  * NOTE: there's a sanity check here in case programs Mshrink a basepage
  1452.  * without fixing the p_hitpa field in the basepage; this is to ensure
  1453.  * compatibility with older versions of MiNT, which ignore p_hitpa.
  1454.  */
  1455.     if (valid_address(b->p_hitpa - 0x20))
  1456.         p->ctxt[CURRENT].usp = b->p_hitpa - 0x20;
  1457.     else
  1458.         p->ctxt[CURRENT].usp = mem->loc + mem->len - 0x20;
  1459.  
  1460.     p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
  1461.     p->ctxt[CURRENT].term_vec = (long)rts;
  1462.  
  1463. /* set up stack for process */
  1464.     *((long *)(p->ctxt[CURRENT].usp + 4)) = (long) b;
  1465.  
  1466. /* check for a valid text region. some compilers (e.g. Lattice 3) just throw
  1467.    everything into the text region, including data; fork() must be careful
  1468.    to save the whole region, then. We assume that if the compiler (or
  1469.    assembler, or whatever) goes to the trouble of making separate text, data,
  1470.    and bss regions, then the text region is code and isn't modified and
  1471.    fork doesn't have to save it.
  1472.  */
  1473.     if (b->p_blen != 0 || b->p_dlen != 0)
  1474.         p->txtsize = b->p_tlen;
  1475.     else
  1476.         p->txtsize = 0;
  1477.  
  1478. /*
  1479.  * An ugly hack: dLibs tries to poke around in the parent's address space
  1480.  * to find stuff. For now, we'll allow this by faking a pointer into
  1481.  * the parent's address space in the place in the basepage where dLibs is
  1482.  * expecting it. This ugly hack only works correctly if the Pexec'ing
  1483.  * program (i.e. curproc) is in user mode.
  1484.  */
  1485.     if (curproc != rootproc)
  1486.         curproc->base->p_usp = curproc->ctxt[SYSCALL].usp - 0x32;
  1487.  
  1488.     return p;
  1489. }
  1490.  
  1491. /*
  1492.  * misc. utility routines
  1493.  */
  1494.  
  1495. /*
  1496.  * long memused(p): return total memory allocated to process p
  1497.  */
  1498.  
  1499. long
  1500. memused(p)
  1501.     PROC *p;
  1502. {
  1503.     int i;
  1504.     long size;
  1505.  
  1506.     /* a ZOMBIE owns no memory and its mem array ptr is zero */
  1507.     if (p->mem == NULL) return 0;
  1508.  
  1509.     size = 0;
  1510.     for (i = 0; i < p->num_reg; i++) {
  1511.         if (p->mem[i])
  1512.             size += p->mem[i]->len;
  1513.     }
  1514.     return size;
  1515. }
  1516.  
  1517. /* 
  1518.  * recalculate the maximum memory limit on a process; this limit depends
  1519.  * on the max. allocated memory and max. total memory limits set by
  1520.  * p_setlimit (see dos.c), and (perhaps) on the size of the program
  1521.  * that the process is executing. whenever any of these things
  1522.  * change (through p_exec or p_setlimit) this routine must be called
  1523.  */
  1524.  
  1525. void
  1526. recalc_maxmem(p)
  1527.     PROC *p;
  1528. {
  1529.     BASEPAGE *b;
  1530.     long siz;
  1531.  
  1532.     b = (BASEPAGE *)p->base;
  1533.     if (b)
  1534.         siz = b->p_tlen + b->p_dlen + b->p_blen;
  1535.     else
  1536.         siz = 0;
  1537.     p->maxmem = 0;
  1538.     if (p->maxdata) {
  1539.         p->maxmem = p->maxdata + siz;
  1540.     }
  1541.  
  1542.     if (p->maxcore) {
  1543.         if (p->maxmem == 0 || p->maxmem > p->maxcore)
  1544.             p->maxmem = p->maxcore;
  1545.     }
  1546.     if (p->maxmem && p->maxmem < siz)
  1547.         p->maxmem = siz;
  1548. }
  1549.  
  1550. /*
  1551.  * valid_address: checks to see if the indicated address falls within
  1552.  * memory attached to the current process
  1553.  */
  1554.  
  1555. int
  1556. valid_address(addr)
  1557.     long addr;
  1558. {
  1559.     int i;
  1560.     MEMREGION *m;
  1561.  
  1562.     for (i = 0; i < curproc->num_reg; i++) {
  1563.         if ((m = curproc->mem[i]) != 0) {
  1564.             if (addr >= m->loc && addr <= m->loc + m->len)
  1565.                 return 1;
  1566.         }
  1567.     }
  1568.     return 0;
  1569. }
  1570.  
  1571. /*
  1572.  * convert an address to a memory region; this works only in
  1573.  * the ST RAM and TT RAM maps, and will fail for memory that
  1574.  * MiNT doesn't own or which is virtualized
  1575.  */
  1576.  
  1577. MEMREGION *
  1578. addr2region(addr)
  1579.     long addr;
  1580. {
  1581.     unsigned long ua = (unsigned long) addr;
  1582.  
  1583.     extern ulong mint_top_st, mint_top_tt;
  1584.     MEMREGION *r;
  1585.     MMAP map;
  1586.  
  1587.     if (ua < mint_top_st) {
  1588.         map = core;
  1589.     } else if (ua < mint_top_tt) {
  1590.         map = alt;
  1591.     } else {
  1592.         return 0;
  1593.     }
  1594.  
  1595.     for (r = *map; r; r = r->next) {
  1596.         if (addr >= r->loc && addr < r->loc + r->len)
  1597.             return r;
  1598.     }
  1599.     return 0;
  1600. }
  1601.  
  1602. /*
  1603.  * some debugging stuff
  1604.  */
  1605.  
  1606. void
  1607. DUMP_ALL_MEM()
  1608. {
  1609.     DUMPMEM(ker);
  1610.     DUMPMEM(core);
  1611.     DUMPMEM(alt);
  1612. }
  1613.  
  1614. void
  1615. DUMPMEM(map)
  1616.     MMAP map;
  1617. {
  1618. #ifndef NO_DEBUG_INFO
  1619.     MEMREGION *m;
  1620.  
  1621.     m = *map;
  1622.     FORCE("%s memory dump: starting at region %lx",
  1623.         (map == ker ? "ker" : (map == core ? "core" : "alt")), m);
  1624.     while (m) {
  1625.         FORCE("%ld bytes at %lx (%d links); next region %lx", m->len, m->loc,
  1626.             m->links, m->next);
  1627.         m = m->next;
  1628.     }
  1629. #endif
  1630. }
  1631.  
  1632. void
  1633. sanity_check(map)
  1634.     MMAP map;
  1635. {
  1636. #ifdef SANITY_CHECK
  1637.     MEMREGION *m, *nxt;
  1638.     long end;
  1639.  
  1640.     m = *map;
  1641.     while (m) {
  1642.         nxt = m->next;
  1643.         if (nxt) {
  1644.             end = m->loc + m->len;
  1645.             if (m->loc < nxt->loc && end > nxt->loc) {
  1646.                 FATAL("MEMORY CHAIN CORRUPTED");
  1647.             }
  1648.             else if (end == nxt->loc && ISFREE(m) && ISFREE(nxt)) {
  1649.                 ALERT("Continguous memory regions not merged!");
  1650.             }
  1651.         }
  1652.         m = nxt;
  1653.     }
  1654. #else
  1655.     UNUSED(map);
  1656. #endif
  1657. }
  1658.