break.c

Go to the documentation of this file.
00001 
00021 #include "pm.h"
00022 #include <signal.h>
00023 #include "mproc.h"
00024 #include "param.h"
00025 
00026 #define DATA_CHANGED       1    /* flag value when data segment size changed */
00027 #define STACK_CHANGED      2    /* flag value when stack size changed */
00028 
00029 /*===========================================================================*
00030  *                              do_brk                                       *
00031  *===========================================================================*/
00032 PUBLIC int do_brk()
00033 {
00034 /* Perform the brk(addr) system call.
00035  *
00036  * The call is complicated by the fact that on some machines (e.g., 8088),
00037  * the stack pointer can grow beyond the base of the stack segment without
00038  * anybody noticing it.
00039  * The parameter, 'addr' is the new virtual address in D space.
00040  */
00041 
00042   register struct mproc *rmp;
00043   int r;
00044   vir_bytes v, new_sp;
00045   vir_clicks new_clicks;
00046 
00047   rmp = mp;
00048   v = (vir_bytes) m_in.addr;
00049   new_clicks = (vir_clicks) ( ((long) v + CLICK_SIZE - 1) >> CLICK_SHIFT);
00050   if (new_clicks < rmp->mp_seg[D].mem_vir) {
00051         rmp->mp_reply.reply_ptr = (char *) -1;
00052         return(ENOMEM);
00053   }
00054   new_clicks -= rmp->mp_seg[D].mem_vir;
00055   if ((r=get_stack_ptr(who_e, &new_sp)) != OK) /* ask kernel for sp value */
00056         panic(__FILE__,"couldn't get stack pointer", r);
00057   r = adjust(rmp, new_clicks, new_sp);
00058   rmp->mp_reply.reply_ptr = (r == OK ? m_in.addr : (char *) -1);
00059   return(r);                    /* return new address or -1 */
00060 }
00061 
00062 /*===========================================================================*
00063  *                              adjust                                       *
00064  *===========================================================================*/
00065 PUBLIC int adjust(rmp, data_clicks, sp)
00066 register struct mproc *rmp;     /* whose memory is being adjusted? */
00067 vir_clicks data_clicks;         /* how big is data segment to become? */
00068 vir_bytes sp;                   /* new value of sp */
00069 {
00070 /* See if data and stack segments can coexist, adjusting them if need be.
00071  * Memory is never allocated or freed.  Instead it is added or removed from the
00072  * gap between data segment and stack segment.  If the gap size becomes
00073  * negative, the adjustment of data or stack fails and ENOMEM is returned.
00074  */
00075 
00076   register struct mem_map *mem_sp, *mem_dp;
00077   vir_clicks sp_click, gap_base, lower, old_clicks;
00078   int changed, r, ft;
00079   long base_of_stack, delta;    /* longs avoid certain problems */
00080 
00081   mem_dp = &rmp->mp_seg[D];     /* pointer to data segment map */
00082   mem_sp = &rmp->mp_seg[S];     /* pointer to stack segment map */
00083   changed = 0;                  /* set when either segment changed */
00084 
00085   if (mem_sp->mem_len == 0) return(OK); /* don't bother init */
00086 
00087   /* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */
00088   base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len;
00089   sp_click = sp >> CLICK_SHIFT; /* click containing sp */
00090   if (sp_click >= base_of_stack) return(ENOMEM);        /* sp too high */
00091 
00092   /* Compute size of gap between stack and data segments. */
00093   delta = (long) mem_sp->mem_vir - (long) sp_click;
00094   lower = (delta > 0 ? sp_click : mem_sp->mem_vir);
00095 
00096   /* Add a safety margin for future stack growth. Impossible to do right. */
00097 #define SAFETY_BYTES  (384 * sizeof(char *))
00098 #define SAFETY_CLICKS ((SAFETY_BYTES + CLICK_SIZE - 1) / CLICK_SIZE)
00099   gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS;
00100   if (lower < gap_base) return(ENOMEM); /* data and stack collided */
00101 
00102   /* Update data length (but not data orgin) on behalf of brk() system call. */
00103   old_clicks = mem_dp->mem_len;
00104   if (data_clicks != mem_dp->mem_len) {
00105         mem_dp->mem_len = data_clicks;
00106         changed |= DATA_CHANGED;
00107   }
00108 
00109   /* Update stack length and origin due to change in stack pointer. */
00110   if (delta > 0) {
00111         mem_sp->mem_vir -= delta;
00112         mem_sp->mem_phys -= delta;
00113         mem_sp->mem_len += delta;
00114         changed |= STACK_CHANGED;
00115   }
00116 
00117   /* Do the new data and stack segment sizes fit in the address space? */
00118   ft = (rmp->mp_flags & SEPARATE);
00119 #if (CHIP == INTEL && _WORD_SIZE == 2)
00120   r = size_ok(ft, rmp->mp_seg[T].mem_len, rmp->mp_seg[D].mem_len, 
00121        rmp->mp_seg[S].mem_len, rmp->mp_seg[D].mem_vir, rmp->mp_seg[S].mem_vir);
00122 #else
00123   r = (rmp->mp_seg[D].mem_vir + rmp->mp_seg[D].mem_len > 
00124           rmp->mp_seg[S].mem_vir) ? ENOMEM : OK;
00125 #endif
00126   if (r == OK) {
00127         int r2;
00128         if (changed && (r2=sys_newmap(rmp->mp_endpoint, rmp->mp_seg)) != OK)
00129                 panic(__FILE__,"couldn't sys_newmap in adjust", r2);
00130         return(OK);
00131   }
00132 
00133   /* New sizes don't fit or require too many page/segment registers. Restore.*/
00134   if (changed & DATA_CHANGED) mem_dp->mem_len = old_clicks;
00135   if (changed & STACK_CHANGED) {
00136         mem_sp->mem_vir += delta;
00137         mem_sp->mem_phys += delta;
00138         mem_sp->mem_len -= delta;
00139   }
00140   return(ENOMEM);
00141 }
00142 
00143 #if (CHIP == INTEL && _WORD_SIZE == 2)
00144 /*===========================================================================*
00145  *                              size_ok                                      *
00146  *===========================================================================*/
00147 PUBLIC int size_ok(file_type, tc, dc, sc, dvir, s_vir)
00148 int file_type;                  /* SEPARATE or 0 */
00149 vir_clicks tc;                  /* text size in clicks */
00150 vir_clicks dc;                  /* data size in clicks */
00151 vir_clicks sc;                  /* stack size in clicks */
00152 vir_clicks dvir;                /* virtual address for start of data seg */
00153 vir_clicks s_vir;               /* virtual address for start of stack seg */
00154 {
00155 /* Check to see if the sizes are feasible and enough segmentation registers
00156  * exist.  On a machine with eight 8K pages, text, data, stack sizes of
00157  * (32K, 16K, 16K) will fit, but (33K, 17K, 13K) will not, even though the
00158  * former is bigger (64K) than the latter (63K).  Even on the 8088 this test
00159  * is needed, since the data and stack may not exceed 4096 clicks.
00160  * Note this is not used for 32-bit Intel Minix, the test is done in-line.
00161  */
00162 
00163   int pt, pd, ps;               /* segment sizes in pages */
00164 
00165   pt = ( (tc << CLICK_SHIFT) + PAGE_SIZE - 1)/PAGE_SIZE;
00166   pd = ( (dc << CLICK_SHIFT) + PAGE_SIZE - 1)/PAGE_SIZE;
00167   ps = ( (sc << CLICK_SHIFT) + PAGE_SIZE - 1)/PAGE_SIZE;
00168 
00169   if (file_type == SEPARATE) {
00170         if (pt > MAX_PAGES || pd + ps > MAX_PAGES) return(ENOMEM);
00171   } else {
00172         if (pt + pd + ps > MAX_PAGES) return(ENOMEM);
00173   }
00174 
00175   if (dvir + dc > s_vir) return(ENOMEM);
00176 
00177   return(OK);
00178 }
00179 #endif
00180 

Generated on Fri Apr 14 22:57:31 2006 for minix by  doxygen 1.4.6