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
19 #include <minix/callnr.h>
20 #include <minix/com.h>
21 #include <minix/config.h>
22 #include <minix/const.h>
24 #include <minix/endpoint.h>
25 #include <minix/keymap.h>
26 #include <minix/minlib.h>
27 #include <minix/type.h>
28 #include <minix/ipc.h>
29 #include <minix/sysutil.h>
30 #include <minix/syslib.h>
31 #include <minix/bitmap.h>
41 #define DATA_CHANGED 1 /* flag value when data segment size changed */
42 #define STACK_CHANGED 2 /* flag value when stack size changed */
44 /*===========================================================================*
46 *===========================================================================*/
47 PUBLIC
int do_brk(message
*msg
)
49 /* Perform the brk(addr) system call.
50 * The parameter, 'addr' is the new virtual address in D space.
54 if(vm_isokendpt(msg
->VMB_ENDPOINT
, &proc
) != OK
) {
55 printf("VM: bogus endpoint VM_BRK %d\n", msg
->VMB_ENDPOINT
);
59 return real_brk(&vmproc
[proc
], (vir_bytes
) msg
->VMB_ADDR
);
62 /*===========================================================================*
64 *===========================================================================*/
65 PUBLIC
int adjust(rmp
, data_clicks
, sp
)
66 struct vmproc
*rmp
; /* whose memory is being adjusted? */
67 vir_clicks data_clicks
; /* how big is data segment to become? */
68 vir_bytes sp
; /* new value of sp */
70 /* See if data and stack segments can coexist, adjusting them if need be.
71 * Memory is never allocated or freed. Instead it is added or removed from the
72 * gap between data segment and stack segment. If the gap size becomes
73 * negative, the adjustment of data or stack fails and ENOMEM is returned.
76 register struct mem_map
*mem_sp
, *mem_dp
;
77 vir_clicks sp_click
, gap_base
, sp_lower
, old_clicks
;
79 long base_of_stack
, sp_delta
; /* longs avoid certain problems */
81 mem_dp
= &rmp
->vm_arch
.vm_seg
[D
]; /* pointer to data segment map */
82 mem_sp
= &rmp
->vm_arch
.vm_seg
[S
]; /* pointer to stack segment map */
83 changed
= 0; /* set when either segment changed */
85 /* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */
86 base_of_stack
= (long) mem_sp
->mem_vir
+ (long) mem_sp
->mem_len
;
87 sp_click
= sp
>> CLICK_SHIFT
; /* click containing sp */
88 if (sp_click
>= base_of_stack
)
90 return(ENOMEM
); /* sp too high */
93 /* Compute size of gap between stack and data segments. */
94 sp_delta
= (long) mem_sp
->mem_vir
- (long) sp_click
;
95 sp_lower
= (sp_delta
> 0 ? sp_click
: mem_sp
->mem_vir
);
97 /* Add a safety margin for future stack growth. Impossible to do right. */
98 #define SAFETY_BYTES (384 * sizeof(char *))
99 #define SAFETY_CLICKS ((vir_clicks) (CLICK_CEIL(SAFETY_BYTES) >> CLICK_SHIFT))
100 gap_base
= mem_dp
->mem_vir
+ data_clicks
+ SAFETY_CLICKS
;
101 if (sp_lower
< gap_base
)
103 return(ENOMEM
); /* data and stack collided */
106 /* Update data length (but not data orgin) on behalf of brk() system call. */
107 old_clicks
= mem_dp
->mem_len
;
108 if (data_clicks
!= mem_dp
->mem_len
) {
109 mem_dp
->mem_len
= data_clicks
;
110 changed
|= DATA_CHANGED
;
113 /* Update stack length and origin due to change in stack pointer. */
115 mem_sp
->mem_vir
-= sp_delta
;
116 mem_sp
->mem_phys
-= sp_delta
;
117 mem_sp
->mem_len
+= sp_delta
;
118 changed
|= STACK_CHANGED
;
121 /* Do the new data and stack segment sizes fit in the address space? */
122 r
= (rmp
->vm_arch
.vm_seg
[D
].mem_vir
+ rmp
->vm_arch
.vm_seg
[D
].mem_len
>
123 rmp
->vm_arch
.vm_seg
[S
].mem_vir
) ? ENOMEM
: OK
;
125 if(r
== OK
&& (rmp
->vm_flags
& VMF_HASPT
) &&
126 rmp
->vm_endpoint
!= VM_PROC_NR
&& rmp
->vm_heap
) {
127 if(old_clicks
< data_clicks
) {
129 more
= (data_clicks
- old_clicks
) << CLICK_SHIFT
;
130 if(map_region_extend(rmp
, rmp
->vm_heap
, more
) != OK
) {
131 printf("VM: brk: map_region_extend failed\n");
134 } else if(old_clicks
> data_clicks
) {
136 less
= (old_clicks
- data_clicks
) << CLICK_SHIFT
;
137 if(map_region_shrink(rmp
->vm_heap
, less
) != OK
) {
138 printf("VM: brk: map_region_shrink failed\n");
147 /* New sizes don't fit or require too many page/segment registers. Restore.*/
148 if (changed
& DATA_CHANGED
) mem_dp
->mem_len
= old_clicks
;
149 if (changed
& STACK_CHANGED
) {
150 mem_sp
->mem_vir
+= sp_delta
;
151 mem_sp
->mem_phys
+= sp_delta
;
152 mem_sp
->mem_len
-= sp_delta
;
157 /*===========================================================================*
159 *===========================================================================*/
160 PUBLIC
int real_brk(vmp
, v
)
165 vir_clicks new_clicks
;
168 new_clicks
= (vir_clicks
) (CLICK_CEIL(v
) >> CLICK_SHIFT
);
169 if (new_clicks
< vmp
->vm_arch
.vm_seg
[D
].mem_vir
) {
170 printf("VM: real_brk failed because new_clicks too high: %d\n",
174 new_clicks
-= vmp
->vm_arch
.vm_seg
[D
].mem_vir
;
175 if ((r
=get_stack_ptr(vmp
->vm_endpoint
, &new_sp
)) != OK
)
176 panic("couldn't get stack pointer: %d", r
);
177 r
= adjust(vmp
, new_clicks
, new_sp
);