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 assert(vmc
->vm_slot
== childproc
);
61 if(vmp
->vm_flags
& VMF_HAS_DMA
) {
62 printf("VM: %d has DMA memory and may not fork\n", msg
->VMF_ENDPOINT
);
66 fullvm
= vmp
->vm_flags
& VMF_HASPT
;
68 /* The child is basically a copy of the parent. */
71 vmc
->vm_slot
= childproc
;
72 vmc
->vm_regions
= NULL
;
73 yielded_init(&vmc
->vm_yielded_blocks
);
74 vmc
->vm_endpoint
= NONE
; /* In case someone tries to use it. */
76 vmc
->vm_flags
&= ~VMF_HASPT
;
79 vmc
->vm_bytecopies
= 0;
82 if(pt_new(&vmc
->vm_pt
) != OK
) {
83 printf("VM: fork: pt_new failed\n");
87 vmc
->vm_flags
|= VMF_HASPT
;
90 SANITYCHECK(SCL_DETAIL
);
92 if(map_proc_copy(vmc
, vmp
) != OK
) {
93 printf("VM: fork: map_proc_copy failed\n");
99 vmc
->vm_heap
= map_region_lookup_tag(vmc
, VRT_HEAP
);
100 assert(vmc
->vm_heap
);
103 SANITYCHECK(SCL_DETAIL
);
106 struct vir_region
*heap
, *stack
;
107 vir_bytes text_bytes
, data_bytes
, stack_bytes
, parent_gap_bytes
,
110 /* Get SP of new process (using parent). */
111 if(get_stack_ptr(vmp
->vm_endpoint
, &sp
) != OK
) {
112 printf("VM: fork: get_stack_ptr failed for %d\n",
117 /* Update size of stack segment using current SP. */
118 if(adjust(vmp
, vmp
->vm_arch
.vm_seg
[D
].mem_len
, sp
) != OK
) {
119 printf("VM: fork: adjust failed for %d\n",
124 /* Copy newly adjust()ed stack segment size to child. */
125 vmc
->vm_arch
.vm_seg
[S
] = vmp
->vm_arch
.vm_seg
[S
];
127 text_bytes
= CLICK2ABS(vmc
->vm_arch
.vm_seg
[T
].mem_len
);
128 data_bytes
= CLICK2ABS(vmc
->vm_arch
.vm_seg
[D
].mem_len
);
129 stack_bytes
= CLICK2ABS(vmc
->vm_arch
.vm_seg
[S
].mem_len
);
131 /* how much space after break and before lower end (which is the
132 * logical top) of stack for the parent
134 parent_gap_bytes
= CLICK2ABS(vmc
->vm_arch
.vm_seg
[S
].mem_vir
-
135 vmc
->vm_arch
.vm_seg
[D
].mem_len
);
137 /* how much space can the child stack grow downwards, below
138 * the current SP? The rest of the gap is available for the
139 * heap to grow upwards.
141 child_gap_bytes
= VM_PAGE_SIZE
;
143 if((r
=proc_new(vmc
, VM_PROCSTART
,
144 text_bytes
, data_bytes
, stack_bytes
, child_gap_bytes
, 0, 0,
145 CLICK2ABS(vmc
->vm_arch
.vm_seg
[S
].mem_vir
+
146 vmc
->vm_arch
.vm_seg
[S
].mem_len
), 1)) != OK
) {
147 printf("VM: fork: proc_new failed\n");
151 if(!(heap
= map_region_lookup_tag(vmc
, VRT_HEAP
)))
152 panic("couldn't lookup heap");
154 if(!(stack
= map_region_lookup_tag(vmc
, VRT_STACK
)))
155 panic("couldn't lookup stack");
158 /* Now copy the memory regions. */
160 if(vmc
->vm_arch
.vm_seg
[T
].mem_len
> 0) {
161 struct vir_region
*text
;
162 if(!(text
= map_region_lookup_tag(vmc
, VRT_TEXT
)))
163 panic("couldn't lookup text");
165 if(copy_abs2region(CLICK2ABS(vmp
->vm_arch
.vm_seg
[T
].mem_phys
),
166 text
, 0, text_bytes
) != OK
)
167 panic("couldn't copy text");
170 if(copy_abs2region(CLICK2ABS(vmp
->vm_arch
.vm_seg
[D
].mem_phys
),
171 heap
, 0, data_bytes
) != OK
)
172 panic("couldn't copy heap");
174 if(copy_abs2region(CLICK2ABS(vmp
->vm_arch
.vm_seg
[D
].mem_phys
+
175 vmc
->vm_arch
.vm_seg
[D
].mem_len
) + parent_gap_bytes
,
176 stack
, child_gap_bytes
, stack_bytes
) != OK
)
177 panic("couldn't copy stack");
180 /* Only inherit these flags. */
181 vmc
->vm_flags
&= (VMF_INUSE
|VMF_SEPARATE
|VMF_HASPT
);
183 /* inherit the priv call bitmaps */
184 memcpy(&vmc
->vm_call_mask
, &vmp
->vm_call_mask
, sizeof(vmc
->vm_call_mask
));
186 /* Tell kernel about the (now successful) FORK. */
187 if((r
=sys_fork(vmp
->vm_endpoint
, childproc
,
188 &vmc
->vm_endpoint
, vmc
->vm_arch
.vm_seg
,
189 PFF_VMINHIBIT
, &msgaddr
)) != OK
) {
190 panic("do_fork can't sys_fork: %d", r
);
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
);