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>
27 #include "sanitycheck.h"
30 /*===========================================================================*
32 *===========================================================================*/
33 PUBLIC
int do_fork(message
*msg
)
35 int r
, proc
, s
, childproc
, fullvm
;
36 struct vmproc
*vmp
, *vmc
;
40 SANITYCHECK(SCL_FUNCTIONS
);
42 if(vm_isokendpt(msg
->VMF_ENDPOINT
, &proc
) != OK
) {
43 printf("VM: bogus endpoint VM_FORK %d\n", msg
->VMF_ENDPOINT
);
44 SANITYCHECK(SCL_FUNCTIONS
);
48 childproc
= msg
->VMF_SLOTNO
;
49 if(childproc
< 0 || childproc
>= NR_PROCS
) {
50 printf("VM: bogus slotno VM_FORK %d\n", msg
->VMF_SLOTNO
);
51 SANITYCHECK(SCL_FUNCTIONS
);
55 vmp
= &vmproc
[proc
]; /* parent */
56 vmc
= &vmproc
[childproc
]; /* child */
57 vm_assert(vmc
->vm_slot
== childproc
);
59 NOTRUNNABLE(vmp
->vm_endpoint
);
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 vmc
->vm_endpoint
= NONE
; /* In case someone tries to use it. */
75 vmc
->vm_flags
|= VMF_HASPT
;
78 vmc
->vm_bytecopies
= 0;
81 SANITYCHECK(SCL_DETAIL
);
84 SANITYCHECK(SCL_DETAIL
);
86 if(pt_new(&vmc
->vm_pt
) != OK
) {
87 printf("VM: fork: pt_new failed\n");
91 SANITYCHECK(SCL_DETAIL
);
93 if(map_proc_copy(vmc
, vmp
) != OK
) {
94 printf("VM: fork: map_proc_copy failed\n");
100 vmc
->vm_heap
= map_region_lookup_tag(vmc
, VRT_HEAP
);
101 vm_assert(vmc
->vm_heap
);
104 SANITYCHECK(SCL_DETAIL
);
106 phys_bytes prog_bytes
, parent_abs
, child_abs
; /* Intel only */
107 phys_clicks prog_clicks
, child_base
;
109 /* Determine how much memory to allocate. Only the data and stack
110 * need to be copied, because the text segment is either shared or
114 prog_clicks
= (phys_clicks
) vmp
->vm_arch
.vm_seg
[S
].mem_len
;
115 prog_clicks
+= (vmp
->vm_arch
.vm_seg
[S
].mem_vir
- vmp
->vm_arch
.vm_seg
[D
].mem_vir
);
116 prog_bytes
= (phys_bytes
) prog_clicks
<< CLICK_SHIFT
;
117 if ( (child_base
= ALLOC_MEM(prog_clicks
, 0)) == NO_MEM
) {
118 SANITYCHECK(SCL_FUNCTIONS
);
122 /* Create a copy of the parent's core image for the child. */
123 child_abs
= (phys_bytes
) child_base
<< CLICK_SHIFT
;
124 parent_abs
= (phys_bytes
) vmp
->vm_arch
.vm_seg
[D
].mem_phys
<< CLICK_SHIFT
;
125 s
= sys_abscopy(parent_abs
, child_abs
, prog_bytes
);
126 if (s
< 0) panic("do_fork can't copy: %d", s
);
128 /* A separate I&D child keeps the parents text segment. The data and stack
129 * segments must refer to the new copy.
131 if (!(vmc
->vm_flags
& VMF_SEPARATE
))
132 vmc
->vm_arch
.vm_seg
[T
].mem_phys
= child_base
;
133 vmc
->vm_arch
.vm_seg
[D
].mem_phys
= child_base
;
134 vmc
->vm_arch
.vm_seg
[S
].mem_phys
= vmc
->vm_arch
.vm_seg
[D
].mem_phys
+
135 (vmp
->vm_arch
.vm_seg
[S
].mem_vir
- vmp
->vm_arch
.vm_seg
[D
].mem_vir
);
137 if(pt_identity(&vmc
->vm_pt
) != OK
) {
138 printf("VM: fork: pt_identity failed\n");
143 /* Only inherit these flags. */
144 vmc
->vm_flags
&= (VMF_INUSE
|VMF_SEPARATE
|VMF_HASPT
);
146 /* inherit the priv call bitmaps */
147 memcpy(&vmc
->vm_call_mask
, &vmp
->vm_call_mask
, sizeof(vmc
->vm_call_mask
));
149 /* Tell kernel about the (now successful) FORK. */
150 if((r
=sys_fork(vmp
->vm_endpoint
, childproc
,
151 &vmc
->vm_endpoint
, vmc
->vm_arch
.vm_seg
,
152 PFF_VMINHIBIT
, &msgaddr
)) != OK
) {
153 panic("do_fork can't sys_fork: %d", r
);
156 NOTRUNNABLE(vmp
->vm_endpoint
);
157 NOTRUNNABLE(vmc
->vm_endpoint
);
161 /* making these messages writable is an optimisation
162 * and its return value needn't be checked.
164 vir
= arch_vir2map(vmc
, msgaddr
);
165 handle_memory(vmc
, vir
, sizeof(message
), 1);
166 vir
= arch_vir2map(vmp
, msgaddr
);
167 handle_memory(vmp
, vir
, sizeof(message
), 1);
170 if((r
=pt_bind(&vmc
->vm_pt
, vmc
)) != OK
)
171 panic("fork can't pt_bind: %d", r
);
173 /* Inform caller of new child endpoint. */
174 msg
->VMF_CHILD_ENDPOINT
= vmc
->vm_endpoint
;
176 SANITYCHECK(SCL_FUNCTIONS
);