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>
36 #include "sanitycheck.h"
38 extern int missing_spares
;
40 #include <machine/archtypes.h>
41 #include <sys/param.h>
42 #include "kernel/const.h"
43 #include "kernel/config.h"
44 #include "kernel/proc.h"
48 /* Table of calls and a macro to test for being in range. */
50 int (*vmc_func
)(message
*); /* Call handles message. */
51 char *vmc_name
; /* Human-readable string. */
52 } vm_calls
[NR_VM_CALLS
];
54 /* Macro to verify call range and map 'high' range to 'base' range
55 * (starting at 0) in one. Evaluates to zero-based call number if call
56 * number is valid, returns -1 otherwise.
58 #define CALLNUMBER(c) (((c) >= VM_RQ_BASE && \
59 (c) < VM_RQ_BASE + ELEMENTS(vm_calls)) ? \
60 ((c) - VM_RQ_BASE) : -1)
62 static int map_service(struct rprocpub
*rpub
);
63 static int vm_acl_ok(endpoint_t caller
, int call
);
64 static int do_rs_init(message
*m
);
66 /* SEF functions and variables. */
67 static void sef_cb_signal_handler(int signo
);
71 /*===========================================================================*
73 *===========================================================================*/
77 int result
, who_e
, rcv_sts
;
80 /* Initialize system so that all processes are runnable */
83 /* Register init callbacks. */
84 sef_setcb_init_restart(sef_cb_init_fail
);
85 sef_setcb_signal_handler(sef_cb_signal_handler
);
87 /* Let SEF perform startup. */
92 /* This is VM's main loop. */
97 if(missing_spares
> 0) {
98 pt_cycle(); /* pagetable code wants to be called */
101 if ((r
=sef_receive_status(ANY
, &msg
, &rcv_sts
)) != OK
)
102 panic("sef_receive_status() error: %d", r
);
104 if (is_ipc_notify(rcv_sts
)) {
105 /* Unexpected notify(). */
106 printf("VM: ignoring notify() from %d\n", msg
.m_source
);
109 who_e
= msg
.m_source
;
110 if(vm_isokendpt(who_e
, &caller_slot
) != OK
)
111 panic("invalid caller %d", who_e
);
112 c
= CALLNUMBER(msg
.m_type
);
113 result
= ENOSYS
; /* Out of range or restricted calls return this. */
115 if(msg
.m_type
== RS_INIT
&& msg
.m_source
== RS_PROC_NR
) {
116 result
= do_rs_init(&msg
);
117 } else if (msg
.m_type
== VM_PAGEFAULT
) {
118 if (!IPC_STATUS_FLAGS_TEST(rcv_sts
, IPC_FLG_MSG_FROM_KERNEL
)) {
119 printf("VM: process %d faked VM_PAGEFAULT "
120 "message!\n", msg
.m_source
);
125 * do not reply to this call, the caller is unblocked by
126 * a sys_vmctl() call in do_pagefaults if success. VM panics
130 } else if(c
< 0 || !vm_calls
[c
].vmc_func
) {
131 /* out of range or missing callnr */
133 if (vm_acl_ok(who_e
, c
) != OK
) {
134 printf("VM: unauthorized %s by %d\n",
135 vm_calls
[c
].vmc_name
, who_e
);
137 SANITYCHECK(SCL_FUNCTIONS
);
138 result
= vm_calls
[c
].vmc_func(&msg
);
139 SANITYCHECK(SCL_FUNCTIONS
);
143 /* Send reply message, unless the return code is SUSPEND,
144 * which is a pseudo-result suppressing the reply message.
146 if(result
!= SUSPEND
) {
148 if((r
=send(who_e
, &msg
)) != OK
) {
149 printf("VM: couldn't send %d to %d (err %d)\n",
150 msg
.m_type
, who_e
, r
);
151 panic("send() error");
158 static int do_rs_init(message
*m
)
161 static struct rprocpub rprocpub
[NR_BOOT_PROCS
];
163 /* Map all the services in the boot image. */
164 if((s
= sys_safecopyfrom(RS_PROC_NR
, m
->RS_INIT_RPROCTAB_GID
, 0,
165 (vir_bytes
) rprocpub
, sizeof(rprocpub
))) != OK
) {
166 panic("vm: sys_safecopyfrom (rs) failed: %d", s
);
169 for(i
=0;i
< NR_BOOT_PROCS
;i
++) {
170 if(rprocpub
[i
].in_use
) {
171 if((s
= map_service(&rprocpub
[i
])) != OK
) {
172 panic("unable to map service: %d", s
);
177 /* RS expects this response that it then again wants to reply to: */
178 m
->RS_INIT_RESULT
= OK
;
179 sendrec(RS_PROC_NR
, m
);
184 struct vmproc
*init_proc(endpoint_t ep_nr
)
186 static struct boot_image
*ip
;
188 for (ip
= &kernel_boot_info
.boot_procs
[0];
189 ip
< &kernel_boot_info
.boot_procs
[NR_BOOT_PROCS
]; ip
++) {
192 if(ip
->proc_nr
!= ep_nr
) continue;
194 if(ip
->proc_nr
>= _NR_PROCS
|| ip
->proc_nr
< 0)
195 panic("proc: %d", ip
->proc_nr
);
197 vmp
= &vmproc
[ip
->proc_nr
];
198 assert(!(vmp
->vm_flags
& VMF_INUSE
)); /* no double procs */
200 vmp
->vm_flags
= VMF_INUSE
;
201 vmp
->vm_endpoint
= ip
->endpoint
;
207 panic("no init_proc");
210 struct vm_exec_info
{
211 struct exec_info execi
;
212 struct boot_image
*ip
;
216 static int libexec_copy_physcopy(struct exec_info
*execi
,
217 off_t off
, off_t vaddr
, size_t len
)
220 struct vm_exec_info
*ei
= execi
->opaque
;
221 end
= ei
->ip
->start_addr
+ ei
->ip
->len
;
222 assert(ei
->ip
->start_addr
+ off
+ len
<= end
);
223 return sys_physcopy(NONE
, ei
->ip
->start_addr
+ off
,
224 execi
->proc_e
, vaddr
, len
);
227 static void boot_alloc(struct exec_info
*execi
, off_t vaddr
,
228 size_t len
, int flags
)
230 struct vmproc
*vmp
= ((struct vm_exec_info
*) execi
->opaque
)->vmp
;
232 if(!(map_page_region(vmp
, vaddr
, 0, len
,
233 VR_ANON
| VR_WRITABLE
| VR_UNINITIALIZED
, flags
,
235 panic("VM: exec: map_page_region for boot process failed");
239 static int libexec_alloc_vm_prealloc(struct exec_info
*execi
,
240 off_t vaddr
, size_t len
)
242 boot_alloc(execi
, vaddr
, len
, MF_PREALLOC
);
246 static int libexec_alloc_vm_ondemand(struct exec_info
*execi
,
247 off_t vaddr
, size_t len
)
249 boot_alloc(execi
, vaddr
, len
, 0);
253 void exec_bootproc(struct vmproc
*vmp
, struct boot_image
*ip
)
255 struct vm_exec_info vmexeci
;
256 struct exec_info
*execi
= &vmexeci
.execi
;
257 char hdr
[VM_PAGE_SIZE
];
259 memset(&vmexeci
, 0, sizeof(vmexeci
));
261 if(pt_new(&vmp
->vm_pt
) != OK
)
262 panic("VM: no new pagetable");
264 if(pt_bind(&vmp
->vm_pt
, vmp
) != OK
)
265 panic("VM: pt_bind failed");
267 if(sys_physcopy(NONE
, ip
->start_addr
, SELF
,
268 (vir_bytes
) hdr
, sizeof(hdr
)) != OK
)
269 panic("can't look at boot proc header");
271 execi
->stack_high
= kernel_boot_info
.user_sp
;
272 execi
->stack_size
= DEFAULT_STACK_LIMIT
;
273 execi
->proc_e
= vmp
->vm_endpoint
;
275 execi
->hdr_len
= sizeof(hdr
);
276 strlcpy(execi
->progname
, ip
->proc_name
, sizeof(execi
->progname
));
277 execi
->frame_len
= 0;
278 execi
->opaque
= &vmexeci
;
283 /* callback functions and data */
284 execi
->copymem
= libexec_copy_physcopy
;
285 execi
->clearproc
= NULL
;
286 execi
->clearmem
= libexec_clear_sys_memset
;
287 execi
->allocmem_prealloc
= libexec_alloc_vm_prealloc
;
288 execi
->allocmem_ondemand
= libexec_alloc_vm_ondemand
;
290 if(libexec_load_elf(execi
) != OK
)
291 panic("vm: boot process load of %d failed\n", vmp
->vm_endpoint
);
293 if(sys_exec(vmp
->vm_endpoint
, (char *) execi
->stack_high
- 12,
294 (char *) ip
->proc_name
, execi
->pc
) != OK
)
295 panic("vm: boot process exec of %d failed\n", vmp
->vm_endpoint
);
297 /* make it runnable */
298 if(sys_vmctl(vmp
->vm_endpoint
, VMCTL_BOOTINHIBIT_CLEAR
, 0) != OK
)
299 panic("VMCTL_BOOTINHIBIT_CLEAR failed");
305 static struct memory mem_chunks
[NR_MEMS
];
306 static struct boot_image
*ip
;
307 extern void __minix_init(void);
310 incheck
= nocheck
= 0;
313 /* Retrieve various crucial boot parameters */
314 if(OK
!= (s
=sys_getkinfo(&kernel_boot_info
))) {
315 panic("couldn't get bootinfo: %d", s
);
319 assert(kernel_boot_info
.mmap_size
> 0);
320 assert(kernel_boot_info
.mods_with_kernel
> 0);
323 env_parse("vm_sanitychecklevel", "d", 0, &vm_sanitychecklevel
, 0, SCL_MAX
);
326 /* Get chunks of available memory. */
327 get_mem_chunks(mem_chunks
);
329 /* Set table to 0. This invalidates all slots (clear VMF_INUSE). */
330 memset(vmproc
, 0, sizeof(vmproc
));
332 for(i
= 0; i
< ELEMENTS(vmproc
); i
++) {
333 vmproc
[i
].vm_slot
= i
;
336 /* region management initialization. */
339 /* Initialize tables to all physical memory. */
340 mem_init(mem_chunks
);
342 /* Architecture-dependent initialization. */
343 init_proc(VM_PROC_NR
);
346 /* Give these processes their own page table. */
347 for (ip
= &kernel_boot_info
.boot_procs
[0];
348 ip
< &kernel_boot_info
.boot_procs
[NR_BOOT_PROCS
]; ip
++) {
351 if(ip
->proc_nr
< 0) continue;
353 assert(ip
->start_addr
);
355 /* VM has already been set up by the kernel and pt_init().
356 * Any other boot process is already in memory and is set up
359 if(ip
->proc_nr
== VM_PROC_NR
) continue;
361 vmp
= init_proc(ip
->proc_nr
);
363 exec_bootproc(vmp
, ip
);
365 /* Free the file blob */
366 assert(!(ip
->start_addr
% VM_PAGE_SIZE
));
367 ip
->len
= roundup(ip
->len
, VM_PAGE_SIZE
);
368 free_mem(ABS2CLICK(ip
->start_addr
), ABS2CLICK(ip
->len
));
371 /* Set up table of calls. */
372 #define CALLMAP(code, func) { int i; \
373 i=CALLNUMBER(code); \
375 assert(i < NR_VM_CALLS); \
376 vm_calls[i].vmc_func = (func); \
377 vm_calls[i].vmc_name = #code; \
380 /* Set call table to 0. This invalidates all calls (clear
383 memset(vm_calls
, 0, sizeof(vm_calls
));
385 /* Basic VM calls. */
386 CALLMAP(VM_MMAP
, do_mmap
);
387 CALLMAP(VM_MUNMAP
, do_munmap
);
388 CALLMAP(VM_MAP_PHYS
, do_map_phys
);
389 CALLMAP(VM_UNMAP_PHYS
, do_munmap
);
392 CALLMAP(VM_EXIT
, do_exit
);
393 CALLMAP(VM_FORK
, do_fork
);
394 CALLMAP(VM_BRK
, do_brk
);
395 CALLMAP(VM_WILLEXIT
, do_willexit
);
396 CALLMAP(VM_NOTIFY_SIG
, do_notify_sig
);
399 CALLMAP(VM_RS_SET_PRIV
, do_rs_set_priv
);
400 CALLMAP(VM_RS_UPDATE
, do_rs_update
);
401 CALLMAP(VM_RS_MEMCTL
, do_rs_memctl
);
403 /* Calls from RS/VFS */
404 CALLMAP(VM_PROCCTL
, do_procctl
);
407 CALLMAP(VM_REMAP
, do_remap
);
408 CALLMAP(VM_REMAP_RO
, do_remap
);
409 CALLMAP(VM_GETPHYS
, do_get_phys
);
410 CALLMAP(VM_SHM_UNMAP
, do_munmap
);
411 CALLMAP(VM_GETREF
, do_get_refcount
);
412 CALLMAP(VM_INFO
, do_info
);
413 CALLMAP(VM_QUERY_EXIT
, do_query_exit
);
414 CALLMAP(VM_WATCH_EXIT
, do_watch_exit
);
415 CALLMAP(VM_FORGETBLOCKS
, do_forgetblocks
);
416 CALLMAP(VM_FORGETBLOCK
, do_forgetblock
);
417 CALLMAP(VM_YIELDBLOCKGETBLOCK
, do_yieldblockgetblock
);
419 /* Initialize the structures for queryexit */
422 /* Acquire kernel ipc vectors that weren't available
423 * before VM had determined kernel mappings
428 /*===========================================================================*
429 * sef_cb_signal_handler *
430 *===========================================================================*/
431 static void sef_cb_signal_handler(int signo
)
433 /* Check for known kernel signals, ignore anything else. */
435 /* There is a pending memory request from the kernel. */
441 /* It can happen that we get stuck receiving signals
442 * without sef_receive() returning. We could need more memory
445 if(missing_spares
> 0) {
446 pt_cycle(); /* pagetable code wants to be called */
452 /*===========================================================================*
454 *===========================================================================*/
455 static int map_service(rpub
)
456 struct rprocpub
*rpub
;
458 /* Map a new service by initializing its call mask. */
461 if ((r
= vm_isokendpt(rpub
->endpoint
, &proc_nr
)) != OK
) {
465 /* Copy the call mask. */
466 memcpy(&vmproc
[proc_nr
].vm_call_mask
, &rpub
->vm_call_mask
,
467 sizeof(vmproc
[proc_nr
].vm_call_mask
));
472 /*===========================================================================*
474 *===========================================================================*/
475 static int vm_acl_ok(endpoint_t caller
, int call
)
479 if ((r
= vm_isokendpt(caller
, &n
)) != OK
)
480 panic("VM: from strange source: %d", caller
);
482 /* See if the call is allowed. */
483 if (!GET_BIT(vmproc
[n
].vm_call_mask
, call
)) {