VM: fix kernel mappings for children of non-paged parents.
[minix.git] / servers / vm / main.c
blob2ee3b0491fd3d6bccc8737f3a747907d3fb0ee6d
2 #define _POSIX_SOURCE 1
3 #define _MINIX 1
4 #define _SYSTEM 1
6 #include <minix/callnr.h>
7 #include <minix/com.h>
8 #include <minix/config.h>
9 #include <minix/const.h>
10 #include <minix/ds.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>
21 #include <minix/rs.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <env.h>
26 #include <stdio.h>
28 #include <memory.h>
30 #define _MAIN 1
31 #include "glo.h"
32 #include "proto.h"
33 #include "util.h"
34 #include "vm.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"
44 #include <signal.h>
46 /* Table of calls and a macro to test for being in range. */
47 struct {
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));
63 extern int unmap_ok;
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 /*===========================================================================*
71 * main *
72 *===========================================================================*/
73 PUBLIC int main(void)
75 message msg;
76 int result, who_e;
77 sigset_t sigset;
79 /* SEF local startup. */
80 sef_local_startup();
82 /* This is VM's main loop. */
83 while (TRUE) {
84 int r, c;
86 SANITYCHECK(SCL_TOP);
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);
100 continue;
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",
107 msg.m_type, who_e);
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);
111 } else {
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);
122 msg.m_type = result;
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);
132 return(OK);
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. */
150 sef_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. */
159 int s, i;
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;
167 #if SANITYCHECKS
168 incheck = nocheck = 0;
169 FIXME("VM SANITYCHECKS are on");
170 #endif
172 vm_paged = 1;
173 env_parse("vm_paged", "d", 0, &vm_paged, 0, 1);
174 #if SANITYCHECKS
175 env_parse("vm_sanitychecklevel", "d", 0, &vm_sanitychecklevel, 0, SCL_MAX);
176 #endif
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
183 * slots to fill in.
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;
200 struct vmproc *vmp;
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) \
206 if(nr >= 0) { \
207 vmp = &vmproc[ip->proc_nr]; \
208 } else if(nr == SYSTEM) { \
209 vmp = &vmproc[VMP_SYSTEM]; \
210 } else { \
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 */
220 clear_proc(vmp);
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)
234 limit = proclimit;
236 vmp->vm_flags = VMF_INUSE;
237 vmp->vm_endpoint = ip->endpoint;
238 vmp->vm_stacktop =
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. */
247 pt_init(limit);
249 /* Initialize tables to all physical memory. */
250 mem_init(mem_chunks);
251 meminit_done = 1;
253 /* Give these processes their own page table. */
254 for (ip = &image[0]; ip < &image[NR_BOOT_PROCS]; ip++) {
255 int s;
256 struct vmproc *vmp;
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))
264 continue;
266 old_stack =
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,
283 old_stack);
285 if(proc_new(vmp,
286 VM_PROCSTART,
287 CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_len),
288 CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_len),
289 BASICSTACK,
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
309 * vmc_func).
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);
320 /* Calls from PM. */
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);
332 /* Calls from RS */
333 CALLMAP(VM_RS_SET_PRIV, do_rs_set_priv);
334 CALLMAP(VM_RS_UPDATE, do_rs_update);
336 /* Generic calls. */
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);
344 /* Sanity checks */
345 if(find_kernel_top() >= VM_PROCSTART)
346 panic("kernel loaded too high");
348 /* Initialize the structures for queryexit */
349 init_query_exit();
351 /* Unmap our own low pages. */
352 unmap_ok = 1;
353 _minix_unmapzero();
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);
368 return(OK);
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. */
377 switch(signo) {
378 /* There is a pending memory request from the kernel. */
379 case SIGKMEM:
380 do_memory();
381 break;
382 /* There is a pending page fault request from the kernel. */
383 case SIGKPF:
384 do_pagefaults();
385 break;
389 /*===========================================================================*
390 * map_service *
391 *===========================================================================*/
392 PRIVATE int map_service(rpub)
393 struct rprocpub *rpub;
395 /* Map a new service by initializing its call mask. */
396 int r, proc_nr;
398 if ((r = vm_isokendpt(rpub->endpoint, &proc_nr)) != OK) {
399 return r;
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));
406 return(OK);
409 /*===========================================================================*
410 * vm_acl_ok *
411 *===========================================================================*/
412 PRIVATE int vm_acl_ok(endpoint_t caller, int call)
414 int n, r;
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)) {
421 return EPERM;
424 return OK;