2 #define _POSIX_SOURCE 1
6 #include <minix/callnr.h>
8 #include <minix/config.h>
9 #include <minix/const.h>
11 #include <minix/endpoint.h>
12 #include <minix/keymap.h>
13 #include <minix/minlib.h>
14 #include <minix/type.h>
15 #include <minix/ipc.h>
16 #include <minix/sysutil.h>
17 #include <minix/syslib.h>
18 #include <minix/const.h>
19 #include <minix/bitmap.h>
20 #include <minix/crtso.h>
35 #include "sanitycheck.h"
37 extern int missing_spares
;
39 #include <machine/archtypes.h>
40 #include "../../kernel/const.h"
41 #include "../../kernel/config.h"
42 #include "../../kernel/proc.h"
46 /* Table of calls and a macro to test for being in range. */
48 int (*vmc_func
)(message
*); /* Call handles message. */
49 char *vmc_name
; /* Human-readable string. */
50 } vm_calls
[NR_VM_CALLS
];
52 /* Macro to verify call range and map 'high' range to 'base' range
53 * (starting at 0) in one. Evaluates to zero-based call number if call
54 * number is valid, returns -1 otherwise.
56 #define CALLNUMBER(c) (((c) >= VM_RQ_BASE && \
57 (c) < VM_RQ_BASE + ELEMENTS(vm_calls)) ? \
58 ((c) - VM_RQ_BASE) : -1)
60 FORWARD
_PROTOTYPE(int map_service
, (struct rprocpub
*rpub
));
61 FORWARD
_PROTOTYPE(int vm_acl_ok
, (endpoint_t caller
, int call
));
65 /* SEF functions and variables. */
66 FORWARD
_PROTOTYPE( void sef_local_startup
, (void) );
67 FORWARD
_PROTOTYPE( int sef_cb_init_fresh
, (int type
, sef_init_info_t
*info
) );
68 FORWARD
_PROTOTYPE( void sef_cb_signal_handler
, (int signo
) );
70 /*===========================================================================*
72 *===========================================================================*/
79 /* SEF local startup. */
82 /* This is VM's main loop. */
87 if(missing_spares
> 0) {
88 pt_cycle(); /* pagetable code wants to be called */
90 SANITYCHECK(SCL_DETAIL
);
92 if ((r
=sef_receive(ANY
, &msg
)) != OK
)
93 panic("sef_receive() error: %d", r
);
95 SANITYCHECK(SCL_DETAIL
);
97 if(msg
.m_type
& NOTIFY_MESSAGE
) {
98 /* Unexpected notify(). */
99 printf("VM: ignoring notify() from %d\n", msg
.m_source
);
102 who_e
= msg
.m_source
;
103 c
= CALLNUMBER(msg
.m_type
);
104 result
= ENOSYS
; /* Out of range or restricted calls return this. */
105 if(c
< 0 || !vm_calls
[c
].vmc_func
) {
106 printf("VM: out of range or missing callnr %d from %d\n",
108 } else if (vm_acl_ok(who_e
, c
) != OK
) {
109 printf("VM: unauthorized %s by %d\n",
110 vm_calls
[c
].vmc_name
, who_e
);
112 SANITYCHECK(SCL_FUNCTIONS
);
113 result
= vm_calls
[c
].vmc_func(&msg
);
114 SANITYCHECK(SCL_FUNCTIONS
);
117 /* Send reply message, unless the return code is SUSPEND,
118 * which is a pseudo-result suppressing the reply message.
120 if(result
!= SUSPEND
) {
121 SANITYCHECK(SCL_DETAIL
);
123 if((r
=send(who_e
, &msg
)) != OK
) {
124 printf("VM: couldn't send %d to %d (err %d)\n",
125 msg
.m_type
, who_e
, r
);
126 panic("send() error");
128 SANITYCHECK(SCL_DETAIL
);
130 SANITYCHECK(SCL_DETAIL
);
135 /*===========================================================================*
136 * sef_local_startup *
137 *===========================================================================*/
138 PRIVATE
void sef_local_startup()
140 /* Register init callbacks. */
141 sef_setcb_init_fresh(sef_cb_init_fresh
);
142 sef_setcb_init_restart(sef_cb_init_fail
);
144 /* No live update support for now. */
146 /* Register signal callbacks. */
147 sef_setcb_signal_handler(sef_cb_signal_handler
);
149 /* Let SEF perform startup. */
153 /*===========================================================================*
154 * sef_cb_init_fresh *
155 *===========================================================================*/
156 PRIVATE
int sef_cb_init_fresh(int type
, sef_init_info_t
*info
)
158 /* Initialize the vm server. */
160 int click
, clicksforgotten
= 0;
161 struct memory mem_chunks
[NR_MEMS
];
162 struct boot_image image
[NR_BOOT_PROCS
];
163 struct boot_image
*ip
;
164 struct rprocpub rprocpub
[NR_BOOT_PROCS
];
165 phys_bytes limit
= 0;
168 incheck
= nocheck
= 0;
169 FIXME("VM SANITYCHECKS are on");
173 env_parse("vm_paged", "d", 0, &vm_paged
, 0, 1);
175 env_parse("vm_sanitychecklevel", "d", 0, &vm_sanitychecklevel
, 0, SCL_MAX
);
178 /* Get chunks of available memory. */
179 get_mem_chunks(mem_chunks
);
181 /* Initialize VM's process table. Request a copy of the system
182 * image table that is defined at the kernel level to see which
185 if (OK
!= (s
=sys_getimage(image
)))
186 panic("couldn't get image table: %d", s
);
188 /* Set table to 0. This invalidates all slots (clear VMF_INUSE). */
189 memset(vmproc
, 0, sizeof(vmproc
));
191 for(i
= 0; i
< ELEMENTS(vmproc
); i
++) {
192 vmproc
[i
].vm_slot
= i
;
195 /* Walk through boot-time system processes that are alive
196 * now and make valid slot entries for them.
198 for (ip
= &image
[0]; ip
< &image
[NR_BOOT_PROCS
]; ip
++) {
199 phys_bytes proclimit
;
202 if(ip
->proc_nr
>= _NR_PROCS
) { panic("proc: %d", ip
->proc_nr
); }
203 if(ip
->proc_nr
< 0 && ip
->proc_nr
!= SYSTEM
) continue;
205 #define GETVMP(v, nr) \
207 vmp = &vmproc[ip->proc_nr]; \
208 } else if(nr == SYSTEM) { \
209 vmp = &vmproc[VMP_SYSTEM]; \
211 panic("init: crazy proc_nr: %d", nr); \
214 /* Initialize normal process table slot or special SYSTEM
215 * table slot. Kernel memory is already reserved.
217 GETVMP(vmp
, ip
->proc_nr
);
219 /* reset fields as if exited */
222 /* Get memory map for this process from the kernel. */
223 if ((s
=get_mem_map(ip
->proc_nr
, vmp
->vm_arch
.vm_seg
)) != OK
)
224 panic("couldn't get process mem_map: %d", s
);
226 /* Remove this memory from the free list. */
227 reserve_proc_mem(mem_chunks
, vmp
->vm_arch
.vm_seg
);
229 /* Set memory limit. */
230 proclimit
= CLICK2ABS(vmp
->vm_arch
.vm_seg
[S
].mem_phys
+
231 vmp
->vm_arch
.vm_seg
[S
].mem_len
) - 1;
233 if(proclimit
> limit
)
236 vmp
->vm_flags
= VMF_INUSE
;
237 vmp
->vm_endpoint
= ip
->endpoint
;
239 CLICK2ABS(vmp
->vm_arch
.vm_seg
[S
].mem_vir
+
240 vmp
->vm_arch
.vm_seg
[S
].mem_len
);
242 if (vmp
->vm_arch
.vm_seg
[T
].mem_len
!= 0)
243 vmp
->vm_flags
|= VMF_SEPARATE
;
246 /* Architecture-dependent initialization. */
249 /* Initialize tables to all physical memory. */
250 mem_init(mem_chunks
);
253 /* Give these processes their own page table. */
254 for (ip
= &image
[0]; ip
< &image
[NR_BOOT_PROCS
]; ip
++) {
257 vir_bytes old_stacktop
, old_stack
;
259 if(ip
->proc_nr
< 0) continue;
261 GETVMP(vmp
, ip
->proc_nr
);
263 if(!(ip
->flags
& PROC_FULLVM
))
267 vmp
->vm_arch
.vm_seg
[S
].mem_vir
+
268 vmp
->vm_arch
.vm_seg
[S
].mem_len
-
269 vmp
->vm_arch
.vm_seg
[D
].mem_len
;
271 if(pt_new(&vmp
->vm_pt
) != OK
)
272 panic("VM: no new pagetable");
273 #define BASICSTACK VM_PAGE_SIZE
274 old_stacktop
= CLICK2ABS(vmp
->vm_arch
.vm_seg
[S
].mem_vir
+
275 vmp
->vm_arch
.vm_seg
[S
].mem_len
);
276 if(sys_vmctl(vmp
->vm_endpoint
, VMCTL_INCSP
,
277 VM_STACKTOP
- old_stacktop
) != OK
) {
278 panic("VM: vmctl for new stack failed");
281 FREE_MEM(vmp
->vm_arch
.vm_seg
[D
].mem_phys
+
282 vmp
->vm_arch
.vm_seg
[D
].mem_len
,
287 CLICK2ABS(vmp
->vm_arch
.vm_seg
[T
].mem_len
),
288 CLICK2ABS(vmp
->vm_arch
.vm_seg
[D
].mem_len
),
290 CLICK2ABS(vmp
->vm_arch
.vm_seg
[S
].mem_vir
+
291 vmp
->vm_arch
.vm_seg
[S
].mem_len
-
292 vmp
->vm_arch
.vm_seg
[D
].mem_len
) - BASICSTACK
,
293 CLICK2ABS(vmp
->vm_arch
.vm_seg
[T
].mem_phys
),
294 CLICK2ABS(vmp
->vm_arch
.vm_seg
[D
].mem_phys
),
295 VM_STACKTOP
, 0) != OK
) {
296 panic("failed proc_new for boot process");
300 /* Set up table of calls. */
301 #define CALLMAP(code, func) { int i; \
302 if((i=CALLNUMBER(code)) < 0) { panic(#code " invalid: %d", (code)); } \
303 if(i >= NR_VM_CALLS) { panic(#code " invalid: %d", (code)); } \
304 vm_calls[i].vmc_func = (func); \
305 vm_calls[i].vmc_name = #code; \
308 /* Set call table to 0. This invalidates all calls (clear
311 memset(vm_calls
, 0, sizeof(vm_calls
));
313 /* Basic VM calls. */
314 CALLMAP(VM_MMAP
, do_mmap
);
315 CALLMAP(VM_MUNMAP
, do_munmap
);
316 CALLMAP(VM_MUNMAP_TEXT
, do_munmap
);
317 CALLMAP(VM_MAP_PHYS
, do_map_phys
);
318 CALLMAP(VM_UNMAP_PHYS
, do_unmap_phys
);
321 CALLMAP(VM_EXIT
, do_exit
);
322 CALLMAP(VM_FORK
, do_fork
);
323 CALLMAP(VM_BRK
, do_brk
);
324 CALLMAP(VM_EXEC_NEWMEM
, do_exec_newmem
);
325 CALLMAP(VM_PUSH_SIG
, do_push_sig
);
326 CALLMAP(VM_WILLEXIT
, do_willexit
);
327 CALLMAP(VM_ADDDMA
, do_adddma
);
328 CALLMAP(VM_DELDMA
, do_deldma
);
329 CALLMAP(VM_GETDMA
, do_getdma
);
330 CALLMAP(VM_NOTIFY_SIG
, do_notify_sig
);
333 CALLMAP(VM_RS_SET_PRIV
, do_rs_set_priv
);
334 CALLMAP(VM_RS_UPDATE
, do_rs_update
);
337 CALLMAP(VM_REMAP
, do_remap
);
338 CALLMAP(VM_GETPHYS
, do_get_phys
);
339 CALLMAP(VM_SHM_UNMAP
, do_shared_unmap
);
340 CALLMAP(VM_GETREF
, do_get_refcount
);
341 CALLMAP(VM_INFO
, do_info
);
342 CALLMAP(VM_QUERY_EXIT
, do_query_exit
);
345 if(find_kernel_top() >= VM_PROCSTART
)
346 panic("kernel loaded too high");
348 /* Initialize the structures for queryexit */
351 /* Unmap our own low pages. */
355 /* Map all the services in the boot image. */
356 if((s
= sys_safecopyfrom(RS_PROC_NR
, info
->rproctab_gid
, 0,
357 (vir_bytes
) rprocpub
, sizeof(rprocpub
), S
)) != OK
) {
358 panic("sys_safecopyfrom failed: %d", s
);
360 for(i
=0;i
< NR_BOOT_PROCS
;i
++) {
361 if(rprocpub
[i
].in_use
) {
362 if((s
= map_service(&rprocpub
[i
])) != OK
) {
363 panic("unable to map service: %d", s
);
371 /*===========================================================================*
372 * sef_cb_signal_handler *
373 *===========================================================================*/
374 PRIVATE
void sef_cb_signal_handler(int signo
)
376 /* Check for known kernel signals, ignore anything else. */
378 /* There is a pending memory request from the kernel. */
382 /* There is a pending page fault request from the kernel. */
389 /*===========================================================================*
391 *===========================================================================*/
392 PRIVATE
int map_service(rpub
)
393 struct rprocpub
*rpub
;
395 /* Map a new service by initializing its call mask. */
398 if ((r
= vm_isokendpt(rpub
->endpoint
, &proc_nr
)) != OK
) {
402 /* Copy the call mask. */
403 memcpy(&vmproc
[proc_nr
].vm_call_mask
, &rpub
->vm_call_mask
,
404 sizeof(vmproc
[proc_nr
].vm_call_mask
));
409 /*===========================================================================*
411 *===========================================================================*/
412 PRIVATE
int vm_acl_ok(endpoint_t caller
, int call
)
416 if ((r
= vm_isokendpt(caller
, &n
)) != OK
)
417 panic("VM: from strange source: %d", caller
);
419 /* See if the call is allowed. */
420 if (!GET_BIT(vmproc
[n
].vm_call_mask
, call
)) {