1 /* The MINIX model of memory allocation reserves a fixed amount of memory for
2 * the combined text, data, and stack segments. The amount used for a child
3 * process created by FORK is the same as the parent had. If the child does
4 * an EXEC later, the new size is taken from the header of the file EXEC'ed.
6 * The layout in memory consists of the text segment, followed by the data
7 * segment, followed by a gap (unused memory), followed by the stack segment.
8 * The data segment grows upward and the stack grows downward, so each can
9 * take memory from the gap. If they meet, the process must be killed. The
10 * procedures in this file deal with the growth of the data and stack segments.
12 * The entry points into this file are:
13 * do_brk: BRK/SBRK system calls to grow or shrink the data segment
14 * adjust: see if a proposed segment adjustment is allowed
15 * size_ok: see if the segment sizes are feasible (i86 only)
23 #define DATA_CHANGED 1 /* flag value when data segment size changed */
24 #define STACK_CHANGED 2 /* flag value when stack size changed */
26 /*===========================================================================*
28 *===========================================================================*/
31 /* Entry point to brk(addr) system call. real_brk() does the real work,
32 * as that is called from elsewhere too.
35 r
= real_brk(mp
, (vir_bytes
) m_in
.addr
);
36 mp
->mp_reply
.reply_ptr
= (r
== OK
? m_in
.addr
: (char *) -1);
40 /*===========================================================================*
42 *===========================================================================*/
43 PUBLIC
int real_brk(struct mproc
*rmp
, vir_bytes v
)
45 /* Perform the brk(addr) system call.
47 * The call is complicated by the fact that on some machines (e.g., 8088),
48 * the stack pointer can grow beyond the base of the stack segment without
49 * anybody noticing it.
50 * The parameter, 'addr' is the new virtual address in D space.
52 * This call can also be performed on PM itself from brk() in misc.c.
56 vir_clicks new_clicks
;
58 new_clicks
= (vir_clicks
) ( ((long) v
+ CLICK_SIZE
- 1) >> CLICK_SHIFT
);
59 if (new_clicks
< rmp
->mp_seg
[D
].mem_vir
) {
60 rmp
->mp_reply
.reply_ptr
= (char *) -1;
63 new_clicks
-= rmp
->mp_seg
[D
].mem_vir
;
64 if ((r
=get_stack_ptr(rmp
->mp_endpoint
, &new_sp
)) != OK
) /* get sp value */
65 panic(__FILE__
,"couldn't get stack pointer", r
);
66 r
= adjust(rmp
, new_clicks
, new_sp
);
67 return(r
); /* return new address or -1 */
70 /*===========================================================================*
72 *===========================================================================*/
73 PUBLIC
int adjust(rmp
, data_clicks
, sp
)
74 register struct mproc
*rmp
; /* whose memory is being adjusted? */
75 vir_clicks data_clicks
; /* how big is data segment to become? */
76 vir_bytes sp
; /* new value of sp */
78 /* See if data and stack segments can coexist, adjusting them if need be.
79 * Memory is never allocated or freed. Instead it is added or removed from the
80 * gap between data segment and stack segment. If the gap size becomes
81 * negative, the adjustment of data or stack fails and ENOMEM is returned.
84 register struct mem_map
*mem_sp
, *mem_dp
;
85 vir_clicks sp_click
, gap_base
, lower
, old_clicks
;
87 long base_of_stack
, delta
; /* longs avoid certain problems */
89 mem_dp
= &rmp
->mp_seg
[D
]; /* pointer to data segment map */
90 mem_sp
= &rmp
->mp_seg
[S
]; /* pointer to stack segment map */
91 changed
= 0; /* set when either segment changed */
93 /* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */
94 base_of_stack
= (long) mem_sp
->mem_vir
+ (long) mem_sp
->mem_len
;
95 sp_click
= sp
>> CLICK_SHIFT
; /* click containing sp */
96 if (sp_click
>= base_of_stack
)
98 return(ENOMEM
); /* sp too high */
101 /* Compute size of gap between stack and data segments. */
102 delta
= (long) mem_sp
->mem_vir
- (long) sp_click
;
103 lower
= (delta
> 0 ? sp_click
: mem_sp
->mem_vir
);
105 /* Add a safety margin for future stack growth. Impossible to do right. */
106 #define SAFETY_BYTES (384 * sizeof(char *))
107 #define SAFETY_CLICKS ((SAFETY_BYTES + CLICK_SIZE - 1) / CLICK_SIZE)
108 gap_base
= mem_dp
->mem_vir
+ data_clicks
+ SAFETY_CLICKS
;
109 if (lower
< gap_base
)
111 return(ENOMEM
); /* data and stack collided */
114 /* Update data length (but not data orgin) on behalf of brk() system call. */
115 old_clicks
= mem_dp
->mem_len
;
116 if (data_clicks
!= mem_dp
->mem_len
) {
117 mem_dp
->mem_len
= data_clicks
;
118 changed
|= DATA_CHANGED
;
121 /* Update stack length and origin due to change in stack pointer. */
123 mem_sp
->mem_vir
-= delta
;
124 mem_sp
->mem_phys
-= delta
;
125 mem_sp
->mem_len
+= delta
;
126 changed
|= STACK_CHANGED
;
129 /* Do the new data and stack segment sizes fit in the address space? */
130 ft
= (rmp
->mp_flags
& SEPARATE
);
131 #if (CHIP == INTEL && _WORD_SIZE == 2)
132 r
= size_ok(ft
, rmp
->mp_seg
[T
].mem_len
, rmp
->mp_seg
[D
].mem_len
,
133 rmp
->mp_seg
[S
].mem_len
, rmp
->mp_seg
[D
].mem_vir
, rmp
->mp_seg
[S
].mem_vir
);
135 r
= (rmp
->mp_seg
[D
].mem_vir
+ rmp
->mp_seg
[D
].mem_len
>
136 rmp
->mp_seg
[S
].mem_vir
) ? ENOMEM
: OK
;
140 if (changed
&& (r2
=sys_newmap(rmp
->mp_endpoint
, rmp
->mp_seg
)) != OK
)
141 panic(__FILE__
,"couldn't sys_newmap in adjust", r2
);
145 /* New sizes don't fit or require too many page/segment registers. Restore.*/
146 if (changed
& DATA_CHANGED
) mem_dp
->mem_len
= old_clicks
;
147 if (changed
& STACK_CHANGED
) {
148 mem_sp
->mem_vir
+= delta
;
149 mem_sp
->mem_phys
+= delta
;
150 mem_sp
->mem_len
-= delta
;
155 #if (CHIP == INTEL && _WORD_SIZE == 2)
156 /*===========================================================================*
158 *===========================================================================*/
159 PUBLIC
int size_ok(file_type
, tc
, dc
, sc
, dvir
, s_vir
)
160 int file_type
; /* SEPARATE or 0 */
161 vir_clicks tc
; /* text size in clicks */
162 vir_clicks dc
; /* data size in clicks */
163 vir_clicks sc
; /* stack size in clicks */
164 vir_clicks dvir
; /* virtual address for start of data seg */
165 vir_clicks s_vir
; /* virtual address for start of stack seg */
167 /* Check to see if the sizes are feasible and enough segmentation registers
168 * exist. On a machine with eight 8K pages, text, data, stack sizes of
169 * (32K, 16K, 16K) will fit, but (33K, 17K, 13K) will not, even though the
170 * former is bigger (64K) than the latter (63K). Even on the 8088 this test
171 * is needed, since the data and stack may not exceed 4096 clicks.
172 * Note this is not used for 32-bit Intel Minix, the test is done in-line.
175 int pt
, pd
, ps
; /* segment sizes in pages */
177 pt
= ( (tc
<< CLICK_SHIFT
) + PAGE_SIZE
- 1)/PAGE_SIZE
;
178 pd
= ( (dc
<< CLICK_SHIFT
) + PAGE_SIZE
- 1)/PAGE_SIZE
;
179 ps
= ( (sc
<< CLICK_SHIFT
) + PAGE_SIZE
- 1)/PAGE_SIZE
;
181 if (file_type
== SEPARATE
) {
182 if (pt
> MAX_PAGES
|| pd
+ ps
> MAX_PAGES
) return(ENOMEM
);
184 if (pt
+ pd
+ ps
> MAX_PAGES
) return(ENOMEM
);
187 if (dvir
+ dc
> s_vir
) return(ENOMEM
);