4 #include <minix/callnr.h>
6 #include <minix/config.h>
7 #include <minix/const.h>
9 #include <minix/endpoint.h>
10 #include <minix/keymap.h>
11 #include <minix/minlib.h>
12 #include <minix/type.h>
13 #include <minix/ipc.h>
14 #include <minix/sysutil.h>
15 #include <minix/syslib.h>
16 #include <minix/debug.h>
17 #include <minix/bitmap.h>
28 #include "sanitycheck.h"
32 /*===========================================================================*
34 *===========================================================================*/
35 PUBLIC
int do_fork(message
*msg
)
37 int r
, proc
, s
, childproc
, fullvm
;
38 struct vmproc
*vmp
, *vmc
;
42 SANITYCHECK(SCL_FUNCTIONS
);
44 if(vm_isokendpt(msg
->VMF_ENDPOINT
, &proc
) != OK
) {
45 printf("VM: bogus endpoint VM_FORK %d\n", msg
->VMF_ENDPOINT
);
46 SANITYCHECK(SCL_FUNCTIONS
);
50 childproc
= msg
->VMF_SLOTNO
;
51 if(childproc
< 0 || childproc
>= NR_PROCS
) {
52 printf("VM: bogus slotno VM_FORK %d\n", msg
->VMF_SLOTNO
);
53 SANITYCHECK(SCL_FUNCTIONS
);
57 vmp
= &vmproc
[proc
]; /* parent */
58 vmc
= &vmproc
[childproc
]; /* child */
59 vm_assert(vmc
->vm_slot
== childproc
);
61 NOTRUNNABLE(vmp
->vm_endpoint
);
63 if(vmp
->vm_flags
& VMF_HAS_DMA
) {
64 printf("VM: %d has DMA memory and may not fork\n", msg
->VMF_ENDPOINT
);
68 fullvm
= vmp
->vm_flags
& VMF_HASPT
;
70 /* The child is basically a copy of the parent. */
73 vmc
->vm_slot
= childproc
;
74 vmc
->vm_regions
= NULL
;
75 vmc
->vm_endpoint
= NONE
; /* In case someone tries to use it. */
77 vmc
->vm_flags
|= VMF_HASPT
;
80 vmc
->vm_bytecopies
= 0;
83 if(pt_new(&vmc
->vm_pt
) != OK
) {
84 printf("VM: fork: pt_new failed\n");
89 SANITYCHECK(SCL_DETAIL
);
91 if(map_proc_copy(vmc
, vmp
) != OK
) {
92 printf("VM: fork: map_proc_copy failed\n");
98 vmc
->vm_heap
= map_region_lookup_tag(vmc
, VRT_HEAP
);
99 vm_assert(vmc
->vm_heap
);
102 SANITYCHECK(SCL_DETAIL
);
105 phys_bytes d_abs
, s_abs
;
106 vir_bytes text_bytes
, data_bytes
, stack_bytes
, parent_gap_bytes
,
109 /* Get SP of new process (using parent). */
110 if(get_stack_ptr(vmp
->vm_endpoint
, &sp
) != OK
) {
111 printf("VM: fork: get_stack_ptr failed for %d\n",
116 /* Update size of stack segment using current SP. */
117 if(adjust(vmp
, vmp
->vm_arch
.vm_seg
[D
].mem_len
, sp
) != OK
) {
118 printf("VM: fork: adjust failed for %d\n",
123 /* Copy newly adjust()ed stack segment size to child. */
124 vmc
->vm_arch
.vm_seg
[S
] = vmp
->vm_arch
.vm_seg
[S
];
126 text_bytes
= CLICK2ABS(vmc
->vm_arch
.vm_seg
[T
].mem_len
);
127 data_bytes
= CLICK2ABS(vmc
->vm_arch
.vm_seg
[D
].mem_len
);
128 stack_bytes
= CLICK2ABS(vmc
->vm_arch
.vm_seg
[S
].mem_len
);
130 /* how much space after break and before lower end (which is the
131 * logical top) of stack for the parent
133 parent_gap_bytes
= CLICK2ABS(vmc
->vm_arch
.vm_seg
[S
].mem_vir
-
134 vmc
->vm_arch
.vm_seg
[D
].mem_len
);
136 /* how much space can the child stack grow downwards, below
137 * the current SP? The rest of the gap is available for the
138 * heap to grow upwards.
140 child_gap_bytes
= VM_PAGE_SIZE
;
142 if((r
=proc_new(vmc
, VM_PROCSTART
,
143 text_bytes
, data_bytes
, stack_bytes
, child_gap_bytes
, 0, 0,
144 CLICK2ABS(vmc
->vm_arch
.vm_seg
[S
].mem_vir
+
145 vmc
->vm_arch
.vm_seg
[S
].mem_len
), 1)) != OK
) {
146 printf("VM: fork: proc_new failed\n");
150 if((d_abs
= map_lookup_phys(vmc
, VRT_HEAP
)) == MAP_NONE
)
151 panic("couldn't lookup data");
152 if((s_abs
= map_lookup_phys(vmc
, VRT_STACK
)) == MAP_NONE
)
153 panic("couldn't lookup stack");
155 /* Now copy the memory regions. */
157 if(vmc
->vm_arch
.vm_seg
[T
].mem_len
> 0) {
159 if((t_abs
= map_lookup_phys(vmc
, VRT_TEXT
)) == MAP_NONE
)
160 panic("couldn't lookup text");
161 if(sys_abscopy(CLICK2ABS(vmp
->vm_arch
.vm_seg
[T
].mem_phys
),
162 t_abs
, text_bytes
) != OK
)
163 panic("couldn't copy text");
166 if(sys_abscopy(CLICK2ABS(vmp
->vm_arch
.vm_seg
[D
].mem_phys
),
167 d_abs
, data_bytes
) != OK
)
168 panic("couldn't copy data");
171 CLICK2ABS(vmp
->vm_arch
.vm_seg
[D
].mem_phys
+
172 vmc
->vm_arch
.vm_seg
[D
].mem_len
) + parent_gap_bytes
,
173 s_abs
+ child_gap_bytes
, stack_bytes
) != OK
)
174 panic("couldn't copy stack");
177 /* Only inherit these flags. */
178 vmc
->vm_flags
&= (VMF_INUSE
|VMF_SEPARATE
|VMF_HASPT
);
180 /* inherit the priv call bitmaps */
181 memcpy(&vmc
->vm_call_mask
, &vmp
->vm_call_mask
, sizeof(vmc
->vm_call_mask
));
183 /* Tell kernel about the (now successful) FORK. */
184 if((r
=sys_fork(vmp
->vm_endpoint
, childproc
,
185 &vmc
->vm_endpoint
, vmc
->vm_arch
.vm_seg
,
186 PFF_VMINHIBIT
, &msgaddr
)) != OK
) {
187 panic("do_fork can't sys_fork: %d", r
);
190 NOTRUNNABLE(vmp
->vm_endpoint
);
191 NOTRUNNABLE(vmc
->vm_endpoint
);
195 /* making these messages writable is an optimisation
196 * and its return value needn't be checked.
198 vir
= arch_vir2map(vmc
, msgaddr
);
199 handle_memory(vmc
, vir
, sizeof(message
), 1);
200 vir
= arch_vir2map(vmp
, msgaddr
);
201 handle_memory(vmp
, vir
, sizeof(message
), 1);
204 if((r
=pt_bind(&vmc
->vm_pt
, vmc
)) != OK
)
205 panic("fork can't pt_bind: %d", r
);
207 /* Inform caller of new child endpoint. */
208 msg
->VMF_CHILD_ENDPOINT
= vmc
->vm_endpoint
;
210 SANITYCHECK(SCL_FUNCTIONS
);