1 2 #define _SYSTEM 1 3 4 #include <minix/callnr.h> 5 #include <minix/com.h> 6 #include <minix/config.h> 7 #include <minix/const.h> 8 #include <minix/ds.h> 9 #include <minix/endpoint.h> 10 #include <minix/minlib.h> 11 #include <minix/type.h> 12 #include <minix/ipc.h> 13 #include <minix/sysutil.h> 14 #include <minix/syslib.h> 15 #include <minix/const.h> 16 #include <minix/bitmap.h> 17 #include <minix/rs.h> 18 #include <minix/vfsif.h> 19 20 #include <sys/exec.h> 21 22 #include <libexec.h> 23 #include <ctype.h> 24 #include <errno.h> 25 #include <string.h> 26 #include <stdio.h> 27 #include <assert.h> 28 29 #define _MAIN 1 30 #include "glo.h" 31 #include "proto.h" 32 #include "util.h" 33 #include "vm.h" 34 #include "sanitycheck.h" 35 36 extern int missing_spares; 37 38 #include <machine/archtypes.h> 39 #include <sys/param.h> 40 #include "kernel/const.h" 41 #include "kernel/config.h" 42 #include "kernel/proc.h" 43 44 #include <signal.h> 45 #include <lib.h> 46 47 /* Table of calls and a macro to test for being in range. */ 48 struct { 49 int (*vmc_func)(message *); /* Call handles message. */ 50 const char *vmc_name; /* Human-readable string. */ 51 } vm_calls[NR_VM_CALLS]; 52 53 /* Macro to verify call range and map 'high' range to 'base' range 54 * (starting at 0) in one. Evaluates to zero-based call number if call 55 * number is valid, returns -1 otherwise. 56 */ 57 #define CALLNUMBER(c) (((c) >= VM_RQ_BASE && \ 58 (c) < VM_RQ_BASE + ELEMENTS(vm_calls)) ? \ 59 ((c) - VM_RQ_BASE) : -1) 60 61 static int map_service(struct rprocpub *rpub); 62 63 static struct rprocpub rprocpub[NR_SYS_PROCS]; 64 int __vm_init_fresh; 65 66 /* SEF functions and variables. */ 67 static void sef_local_startup(void); 68 static int sef_cb_init_lu_restart(int type, sef_init_info_t *info); 69 static int sef_cb_init_fresh(int type, sef_init_info_t *info); 70 static void sef_cb_signal_handler(int signo); 71 72 void init_vm(void); 73 74 int do_sef_init_request(message *); 75 76 /*===========================================================================* 77 * is_first_time * 78 *===========================================================================*/ 79 static int is_first_time(void) 80 { 81 struct proc rs_proc; 82 int r; 83 84 if ((r = sys_getproc(&rs_proc, RS_PROC_NR)) != OK) 85 panic("VM: couldn't get RS process data: %d", r); 86 87 return RTS_ISSET(&rs_proc, RTS_BOOTINHIBIT); 88 } 89 90 /*===========================================================================* 91 * main * 92 *===========================================================================*/ 93 int main(void) 94 { 95 message msg; 96 int result, who_e, rcv_sts; 97 int caller_slot; 98 99 /* Initialize system so that all processes are runnable the first time. */ 100 if (is_first_time()) { 101 init_vm(); 102 __vm_init_fresh=1; 103 } 104 105 /* SEF local startup. */ 106 sef_local_startup(); 107 __vm_init_fresh=0; 108 109 SANITYCHECK(SCL_TOP); 110 111 /* This is VM's main loop. */ 112 while (TRUE) { 113 int r, c; 114 int type; 115 int transid = 0; /* VFS transid if any */ 116 117 SANITYCHECK(SCL_TOP); 118 if(missing_spares > 0) { 119 alloc_cycle(); /* mem alloc code wants to be called */ 120 } 121 122 if ((r=sef_receive_status(ANY, &msg, &rcv_sts)) != OK) 123 panic("sef_receive_status() error: %d", r); 124 125 if (is_ipc_notify(rcv_sts)) { 126 /* Unexpected ipc_notify(). */ 127 printf("VM: ignoring ipc_notify() from %d\n", msg.m_source); 128 continue; 129 } 130 who_e = msg.m_source; 131 if(vm_isokendpt(who_e, &caller_slot) != OK) 132 panic("invalid caller %d", who_e); 133 134 /* We depend on this being false for the initialized value. */ 135 assert(!IS_VFS_FS_TRANSID(transid)); 136 137 type = msg.m_type; 138 c = CALLNUMBER(type); 139 result = ENOSYS; /* Out of range or restricted calls return this. */ 140 141 transid = TRNS_GET_ID(msg.m_type); 142 143 if((msg.m_source == VFS_PROC_NR) && IS_VFS_FS_TRANSID(transid)) { 144 /* If it's a request from VFS, it might have a transaction id. */ 145 msg.m_type = TRNS_DEL_ID(msg.m_type); 146 147 /* Calls that use the transid */ 148 result = do_procctl(&msg, transid); 149 } else if(msg.m_type == RS_INIT && msg.m_source == RS_PROC_NR) { 150 result = do_sef_init_request(&msg); 151 if(result != OK) panic("do_sef_init_request failed!\n"); 152 result = SUSPEND; /* do not reply to RS */ 153 } else if (msg.m_type == VM_PAGEFAULT) { 154 if (!IPC_STATUS_FLAGS_TEST(rcv_sts, IPC_FLG_MSG_FROM_KERNEL)) { 155 printf("VM: process %d faked VM_PAGEFAULT " 156 "message!\n", msg.m_source); 157 } 158 do_pagefaults(&msg); 159 /* 160 * do not reply to this call, the caller is unblocked by 161 * a sys_vmctl() call in do_pagefaults if success. VM panics 162 * otherwise 163 */ 164 continue; 165 } else if(c < 0 || !vm_calls[c].vmc_func) { 166 /* out of range or missing callnr */ 167 } else { 168 if (acl_check(&vmproc[caller_slot], c) != OK) { 169 printf("VM: unauthorized %s by %d\n", 170 vm_calls[c].vmc_name, who_e); 171 } else { 172 SANITYCHECK(SCL_FUNCTIONS); 173 result = vm_calls[c].vmc_func(&msg); 174 SANITYCHECK(SCL_FUNCTIONS); 175 } 176 } 177 178 /* Send reply message, unless the return code is SUSPEND, 179 * which is a pseudo-result suppressing the reply message. 180 */ 181 if(result != SUSPEND) { 182 msg.m_type = result; 183 184 assert(!IS_VFS_FS_TRANSID(transid)); 185 186 if((r=ipc_send(who_e, &msg)) != OK) { 187 printf("VM: couldn't send %d to %d (err %d)\n", 188 msg.m_type, who_e, r); 189 panic("ipc_send() error"); 190 } 191 } 192 } 193 return(OK); 194 } 195 196 static void sef_cb_lu_state_changed(int old_state, int state) 197 { 198 /* Called whenever the live-update state changes. We need to restore certain 199 * state in the old VM instance after a live update has failed, because some 200 * but not all memory is shared between the two VM instances. 201 */ 202 struct vmproc *vmp; 203 204 if (state == SEF_LU_STATE_NULL) { 205 /* Undo some of the changes that may have been made by the new VM 206 * instance. If the new VM instance is us, nothing happens. 207 */ 208 vmp = &vmproc[VM_PROC_NR]; 209 210 /* Rebind page tables. */ 211 pt_bind(&vmp->vm_pt, vmp); 212 pt_clearmapcache(); 213 214 /* Readjust process references. */ 215 adjust_proc_refs(); 216 } 217 } 218 219 static void sef_local_startup(void) 220 { 221 /* Register init callbacks. */ 222 sef_setcb_init_fresh(sef_cb_init_fresh); 223 sef_setcb_init_lu(sef_cb_init_lu_restart); 224 sef_setcb_init_restart(sef_cb_init_lu_restart); 225 /* In order to avoid a deadlock at boot time, send the first RS_INIT 226 * reply to RS asynchronously. After that, use sendrec as usual. 227 */ 228 if (__vm_init_fresh) 229 sef_setcb_init_response(sef_cb_init_response_rs_asyn_once); 230 231 /* Register live update callbacks. */ 232 sef_setcb_lu_state_changed(sef_cb_lu_state_changed); 233 234 /* Register signal callbacks. */ 235 sef_setcb_signal_handler(sef_cb_signal_handler); 236 237 /* Let SEF perform startup. */ 238 sef_startup(); 239 } 240 241 static int sef_cb_init_fresh(int type, sef_init_info_t *info) 242 { 243 int s, i; 244 245 /* Map all the services in the boot image. */ 246 if((s = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0, 247 (vir_bytes) rprocpub, sizeof(rprocpub))) != OK) { 248 panic("vm: sys_safecopyfrom (rs) failed: %d", s); 249 } 250 251 for(i=0;i < NR_BOOT_PROCS;i++) { 252 if(rprocpub[i].in_use) { 253 if((s = map_service(&rprocpub[i])) != OK) { 254 panic("unable to map service: %d", s); 255 } 256 } 257 } 258 259 return(OK); 260 } 261 262 static struct vmproc *init_proc(endpoint_t ep_nr) 263 { 264 struct boot_image *ip; 265 266 for (ip = &kernel_boot_info.boot_procs[0]; 267 ip < &kernel_boot_info.boot_procs[NR_BOOT_PROCS]; ip++) { 268 struct vmproc *vmp; 269 270 if(ip->proc_nr != ep_nr) continue; 271 272 if(ip->proc_nr >= _NR_PROCS || ip->proc_nr < 0) 273 panic("proc: %d", ip->proc_nr); 274 275 vmp = &vmproc[ip->proc_nr]; 276 assert(!(vmp->vm_flags & VMF_INUSE)); /* no double procs */ 277 clear_proc(vmp); 278 vmp->vm_flags = VMF_INUSE; 279 vmp->vm_endpoint = ip->endpoint; 280 vmp->vm_boot = ip; 281 282 return vmp; 283 } 284 285 panic("no init_proc"); 286 } 287 288 struct vm_exec_info { 289 struct exec_info execi; 290 struct boot_image *ip; 291 struct vmproc *vmp; 292 }; 293 294 static int libexec_copy_physcopy(struct exec_info *execi, 295 off_t off, vir_bytes vaddr, size_t len) 296 { 297 vir_bytes end; 298 struct vm_exec_info *ei = execi->opaque; 299 end = ei->ip->start_addr + ei->ip->len; 300 assert(ei->ip->start_addr + off + len <= end); 301 return sys_physcopy(NONE, ei->ip->start_addr + off, 302 execi->proc_e, vaddr, len, 0); 303 } 304 305 static void boot_alloc(struct exec_info *execi, off_t vaddr, 306 size_t len, int flags) 307 { 308 struct vmproc *vmp = ((struct vm_exec_info *) execi->opaque)->vmp; 309 310 if(!(map_page_region(vmp, vaddr, 0, len, 311 VR_ANON | VR_WRITABLE | VR_UNINITIALIZED, flags, 312 &mem_type_anon))) { 313 panic("VM: exec: map_page_region for boot process failed"); 314 } 315 } 316 317 static int libexec_alloc_vm_prealloc(struct exec_info *execi, 318 vir_bytes vaddr, size_t len) 319 { 320 boot_alloc(execi, vaddr, len, MF_PREALLOC); 321 return OK; 322 } 323 324 static int libexec_alloc_vm_ondemand(struct exec_info *execi, 325 vir_bytes vaddr, size_t len) 326 { 327 boot_alloc(execi, vaddr, len, 0); 328 return OK; 329 } 330 331 static void exec_bootproc(struct vmproc *vmp, struct boot_image *ip) 332 { 333 struct vm_exec_info vmexeci; 334 struct exec_info *execi = &vmexeci.execi; 335 /* libexec need proper alignment for casting to structures */ 336 char hdr[VM_PAGE_SIZE] __aligned(8); 337 338 size_t frame_size = 0; /* Size of the new initial stack. */ 339 int argc = 0; /* Argument count. */ 340 int envc = 0; /* Environment count */ 341 char overflow = 0; /* No overflow yet. */ 342 struct ps_strings *psp; 343 344 int vsp = 0; /* (virtual) Stack pointer in new address space. */ 345 char *argv[] = { ip->proc_name, NULL }; 346 char *envp[] = { NULL }; 347 char *path = ip->proc_name; 348 char frame[VM_PAGE_SIZE] __aligned(sizeof(void *)); 349 350 memset(&vmexeci, 0, sizeof(vmexeci)); 351 352 if(pt_new(&vmp->vm_pt) != OK) 353 panic("VM: no new pagetable"); 354 355 if(pt_bind(&vmp->vm_pt, vmp) != OK) 356 panic("VM: pt_bind failed"); 357 358 if(sys_physcopy(NONE, ip->start_addr, SELF, 359 (vir_bytes) hdr, sizeof(hdr), 0) != OK) 360 panic("can't look at boot proc header"); 361 362 execi->stack_high = kernel_boot_info.user_sp; 363 execi->stack_size = DEFAULT_STACK_LIMIT; 364 execi->proc_e = vmp->vm_endpoint; 365 execi->hdr = hdr; 366 execi->hdr_len = sizeof(hdr); 367 strlcpy(execi->progname, ip->proc_name, sizeof(execi->progname)); 368 execi->frame_len = 0; 369 execi->opaque = &vmexeci; 370 execi->filesize = ip->len; 371 372 vmexeci.ip = ip; 373 vmexeci.vmp = vmp; 374 375 /* callback functions and data */ 376 execi->copymem = libexec_copy_physcopy; 377 execi->clearproc = NULL; 378 execi->clearmem = libexec_clear_sys_memset; 379 execi->allocmem_prealloc_junk = libexec_alloc_vm_prealloc; 380 execi->allocmem_prealloc_cleared = libexec_alloc_vm_prealloc; 381 execi->allocmem_ondemand = libexec_alloc_vm_ondemand; 382 383 if (libexec_load_elf(execi) != OK) 384 panic("vm: boot process load of process %s (ep=%d) failed\n", 385 execi->progname, vmp->vm_endpoint); 386 387 /* Setup a minimal stack. */ 388 minix_stack_params(path, argv, envp, &frame_size, &overflow, &argc, 389 &envc); 390 391 /* The party is off if there is an overflow, or it is too big for our 392 * pre-allocated space. */ 393 if(overflow || frame_size > sizeof(frame)) 394 panic("vm: could not alloc stack for boot process %s (ep=%d)\n", 395 execi->progname, vmp->vm_endpoint); 396 397 minix_stack_fill(path, argc, argv, envc, envp, frame_size, frame, &vsp, 398 &psp); 399 400 if(handle_memory_once(vmp, vsp, frame_size, 1) != OK) 401 panic("vm: could not map stack for boot process %s (ep=%d)\n", 402 execi->progname, vmp->vm_endpoint); 403 404 if(sys_datacopy(SELF, (vir_bytes)frame, vmp->vm_endpoint, vsp, frame_size) != OK) 405 panic("vm: could not copy stack for boot process %s (ep=%d)\n", 406 execi->progname, vmp->vm_endpoint); 407 408 if(sys_exec(vmp->vm_endpoint, (vir_bytes)vsp, 409 (vir_bytes)execi->progname, execi->pc, 410 vsp + ((int)psp - (int)frame)) != OK) 411 panic("vm: boot process exec of process %s (ep=%d) failed\n", 412 execi->progname,vmp->vm_endpoint); 413 414 /* make it runnable */ 415 if(sys_vmctl(vmp->vm_endpoint, VMCTL_BOOTINHIBIT_CLEAR, 0) != OK) 416 panic("VMCTL_BOOTINHIBIT_CLEAR failed"); 417 } 418 419 static int do_procctl_notrans(message *msg) 420 { 421 int transid = 0; 422 423 assert(!IS_VFS_FS_TRANSID(transid)); 424 425 return do_procctl(msg, transid); 426 } 427 428 void init_vm(void) 429 { 430 int s, i; 431 static struct memory mem_chunks[NR_MEMS]; 432 struct boot_image *ip; 433 extern void __minix_init(void); 434 multiboot_module_t *mod; 435 vir_bytes kern_dyn, kern_static; 436 437 #if SANITYCHECKS 438 incheck = nocheck = 0; 439 #endif 440 441 /* Retrieve various crucial boot parameters */ 442 if(OK != (s=sys_getkinfo(&kernel_boot_info))) { 443 panic("couldn't get bootinfo: %d", s); 444 } 445 446 /* Turn file mmap on? */ 447 enable_filemap=1; /* yes by default */ 448 env_parse("filemap", "d", 0, &enable_filemap, 0, 1); 449 450 /* Sanity check */ 451 assert(kernel_boot_info.mmap_size > 0); 452 assert(kernel_boot_info.mods_with_kernel > 0); 453 454 /* Get chunks of available memory. */ 455 get_mem_chunks(mem_chunks); 456 457 /* Set table to 0. This invalidates all slots (clear VMF_INUSE). */ 458 memset(vmproc, 0, sizeof(vmproc)); 459 460 for(i = 0; i < ELEMENTS(vmproc); i++) { 461 vmproc[i].vm_slot = i; 462 } 463 464 /* Initialize ACL data structures. */ 465 acl_init(); 466 467 /* region management initialization. */ 468 map_region_init(); 469 470 /* Initialize tables to all physical memory. */ 471 mem_init(mem_chunks); 472 473 /* Architecture-dependent initialization. */ 474 init_proc(VM_PROC_NR); 475 pt_init(); 476 477 /* Acquire kernel ipc vectors that weren't available 478 * before VM had determined kernel mappings 479 */ 480 __minix_init(); 481 482 /* The kernel's freelist does not include boot-time modules; let 483 * the allocator know that the total memory is bigger. 484 */ 485 for (mod = &kernel_boot_info.module_list[0]; 486 mod < &kernel_boot_info.module_list[kernel_boot_info.mods_with_kernel-1]; mod++) { 487 phys_bytes len = mod->mod_end-mod->mod_start+1; 488 len = roundup(len, VM_PAGE_SIZE); 489 mem_add_total_pages(len/VM_PAGE_SIZE); 490 } 491 492 kern_dyn = kernel_boot_info.kernel_allocated_bytes_dynamic; 493 kern_static = kernel_boot_info.kernel_allocated_bytes; 494 kern_static = roundup(kern_static, VM_PAGE_SIZE); 495 mem_add_total_pages((kern_dyn + kern_static)/VM_PAGE_SIZE); 496 497 /* Give these processes their own page table. */ 498 for (ip = &kernel_boot_info.boot_procs[0]; 499 ip < &kernel_boot_info.boot_procs[NR_BOOT_PROCS]; ip++) { 500 struct vmproc *vmp; 501 502 if(ip->proc_nr < 0) continue; 503 504 assert(ip->start_addr); 505 506 /* VM has already been set up by the kernel and pt_init(). 507 * Any other boot process is already in memory and is set up 508 * here. 509 */ 510 if(ip->proc_nr == VM_PROC_NR) continue; 511 512 vmp = init_proc(ip->proc_nr); 513 514 exec_bootproc(vmp, ip); 515 516 /* Free the file blob */ 517 assert(!(ip->start_addr % VM_PAGE_SIZE)); 518 ip->len = roundup(ip->len, VM_PAGE_SIZE); 519 free_mem(ABS2CLICK(ip->start_addr), ABS2CLICK(ip->len)); 520 } 521 522 /* Set up table of calls. */ 523 #define CALLMAP(code, func) { int _cmi; \ 524 _cmi=CALLNUMBER(code); \ 525 assert(_cmi >= 0); \ 526 assert(_cmi < NR_VM_CALLS); \ 527 vm_calls[_cmi].vmc_func = (func); \ 528 vm_calls[_cmi].vmc_name = #code; \ 529 } 530 531 /* Set call table to 0. This invalidates all calls (clear 532 * vmc_func). 533 */ 534 memset(vm_calls, 0, sizeof(vm_calls)); 535 536 /* Basic VM calls. */ 537 CALLMAP(VM_MMAP, do_mmap); 538 CALLMAP(VM_MUNMAP, do_munmap); 539 CALLMAP(VM_MAP_PHYS, do_map_phys); 540 CALLMAP(VM_UNMAP_PHYS, do_munmap); 541 542 /* Calls from PM. */ 543 CALLMAP(VM_EXIT, do_exit); 544 CALLMAP(VM_FORK, do_fork); 545 CALLMAP(VM_BRK, do_brk); 546 CALLMAP(VM_WILLEXIT, do_willexit); 547 548 CALLMAP(VM_PROCCTL, do_procctl_notrans); 549 550 /* Calls from VFS. */ 551 CALLMAP(VM_VFS_REPLY, do_vfs_reply); 552 CALLMAP(VM_VFS_MMAP, do_vfs_mmap); 553 554 /* Calls from RS */ 555 CALLMAP(VM_RS_SET_PRIV, do_rs_set_priv); 556 CALLMAP(VM_RS_PREPARE, do_rs_prepare); 557 CALLMAP(VM_RS_UPDATE, do_rs_update); 558 CALLMAP(VM_RS_MEMCTL, do_rs_memctl); 559 560 /* Generic calls. */ 561 CALLMAP(VM_REMAP, do_remap); 562 CALLMAP(VM_REMAP_RO, do_remap); 563 CALLMAP(VM_GETPHYS, do_get_phys); 564 CALLMAP(VM_SHM_UNMAP, do_munmap); 565 CALLMAP(VM_GETREF, do_get_refcount); 566 CALLMAP(VM_INFO, do_info); 567 568 /* Cache blocks. */ 569 CALLMAP(VM_MAPCACHEPAGE, do_mapcache); 570 CALLMAP(VM_SETCACHEPAGE, do_setcache); 571 CALLMAP(VM_FORGETCACHEPAGE, do_forgetcache); 572 CALLMAP(VM_CLEARCACHE, do_clearcache); 573 574 /* getrusage */ 575 CALLMAP(VM_GETRUSAGE, do_getrusage); 576 577 /* Mark VM instances. */ 578 num_vm_instances = 1; 579 vmproc[VM_PROC_NR].vm_flags |= VMF_VM_INSTANCE; 580 581 /* Let SEF know about VM mmapped regions. */ 582 s = sef_llvm_add_special_mem_region((void*)VM_OWN_HEAPBASE, 583 VM_OWN_MMAPTOP-VM_OWN_HEAPBASE, "%MMAP_ALL"); 584 if(s < 0) { 585 printf("VM: st_add_special_mmapped_region failed %d\n", s); 586 } 587 } 588 589 /*===========================================================================* 590 * sef_cb_init_vm_multi_lu * 591 *===========================================================================*/ 592 static int sef_cb_init_vm_multi_lu(int type, sef_init_info_t *info) 593 { 594 message m; 595 int i, r; 596 ipc_filter_el_t ipc_filter[IPCF_MAX_ELEMENTS]; 597 int num_elements; 598 599 if(type != SEF_INIT_LU || !(info->flags & SEF_LU_MULTI)) { 600 return OK; 601 } 602 603 /* If this is a multi-component update, we need to perform the update 604 * for services that need to be updated. In addition, make sure VM 605 * can only receive messages from RS, tasks, and other services being 606 * updated until RS specifically sends a special update cancel message. 607 * This is necessary to limit the number of VM state changes to support 608 * rollback. Allow only safe message types for safe updates. 609 */ 610 memset(ipc_filter, 0, sizeof(ipc_filter)); 611 num_elements = 0; 612 ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE; 613 ipc_filter[num_elements++].m_source = RS_PROC_NR; 614 if((r = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0, 615 (vir_bytes) rprocpub, NR_SYS_PROCS*sizeof(struct rprocpub))) != OK) { 616 panic("sys_safecopyfrom failed: %d", r); 617 } 618 m.m_source = VM_PROC_NR; 619 for(i=0;i < NR_SYS_PROCS;i++) { 620 if(rprocpub[i].in_use && rprocpub[i].old_endpoint != NONE) { 621 if(num_elements <= IPCF_MAX_ELEMENTS-5) { 622 /* VM_BRK is needed for normal operation during the live 623 * update. VM_INFO is needed for state transfer in the 624 * light of holes. Pagefaults and handle-memory requests 625 * are blocked intentionally, as handling these would 626 * prevent VM from being able to roll back. 627 */ 628 ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE | IPCF_MATCH_M_TYPE; 629 ipc_filter[num_elements].m_source = rprocpub[i].old_endpoint; 630 ipc_filter[num_elements++].m_type = VM_BRK; 631 ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE | IPCF_MATCH_M_TYPE; 632 ipc_filter[num_elements].m_source = rprocpub[i].new_endpoint; 633 ipc_filter[num_elements++].m_type = VM_BRK; 634 ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE | IPCF_MATCH_M_TYPE; 635 ipc_filter[num_elements].m_source = rprocpub[i].old_endpoint; 636 ipc_filter[num_elements++].m_type = VM_INFO; 637 ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE | IPCF_MATCH_M_TYPE; 638 ipc_filter[num_elements].m_source = rprocpub[i].new_endpoint; 639 ipc_filter[num_elements++].m_type = VM_INFO; 640 /* Make sure we can talk to any RS instance. */ 641 if(rprocpub[i].old_endpoint == RS_PROC_NR) { 642 ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE; 643 ipc_filter[num_elements++].m_source = rprocpub[i].new_endpoint; 644 } 645 else if(rprocpub[i].new_endpoint == RS_PROC_NR) { 646 ipc_filter[num_elements].flags = IPCF_MATCH_M_SOURCE; 647 ipc_filter[num_elements++].m_source = rprocpub[i].old_endpoint; 648 } 649 } 650 else { 651 printf("sef_cb_init_vm_multi_lu: skipping ipc filter elements for %d and %d\n", 652 rprocpub[i].old_endpoint, rprocpub[i].new_endpoint); 653 } 654 if(rprocpub[i].sys_flags & SF_VM_UPDATE) { 655 m.m_lsys_vm_update.src = rprocpub[i].new_endpoint; 656 m.m_lsys_vm_update.dst = rprocpub[i].old_endpoint; 657 m.m_lsys_vm_update.flags = rprocpub[i].sys_flags; 658 r = do_rs_update(&m); 659 if(r != OK && r != SUSPEND) { 660 printf("sef_cb_init_vm_multi_lu: do_rs_update failed: %d", r); 661 } 662 } 663 } 664 } 665 666 r = sys_statectl(SYS_STATE_ADD_IPC_WL_FILTER, ipc_filter, num_elements*sizeof(ipc_filter_el_t)); 667 if(r != OK) { 668 printf("sef_cb_init_vm_multi_lu: sys_statectl failed: %d", r); 669 } 670 671 return OK; 672 } 673 674 /*===========================================================================* 675 * sef_cb_init_lu_restart * 676 *===========================================================================*/ 677 static int sef_cb_init_lu_restart(int type, sef_init_info_t *info) 678 { 679 /* Restart the vm server. */ 680 int r; 681 endpoint_t old_e; 682 int old_p; 683 struct vmproc *old_vmp, *new_vmp; 684 685 /* Perform default state transfer first. */ 686 if(type == SEF_INIT_LU) { 687 sef_setcb_init_restart(SEF_CB_INIT_RESTART_STATEFUL); 688 r = SEF_CB_INIT_LU_DEFAULT(type, info); 689 } 690 else { 691 r = SEF_CB_INIT_RESTART_STATEFUL(type, info); 692 } 693 if(r != OK) { 694 return r; 695 } 696 697 /* Lookup slots for old process. */ 698 old_e = info->old_endpoint; 699 if(vm_isokendpt(old_e, &old_p) != OK) { 700 printf("sef_cb_init_lu_restart: bad old endpoint %d\n", old_e); 701 return EINVAL; 702 } 703 old_vmp = &vmproc[old_p]; 704 new_vmp = &vmproc[VM_PROC_NR]; 705 706 /* Swap proc slots and dynamic data. */ 707 if((r = swap_proc_slot(old_vmp, new_vmp)) != OK) { 708 printf("sef_cb_init_lu_restart: swap_proc_slot failed\n"); 709 return r; 710 } 711 if((r = swap_proc_dyn_data(old_vmp, new_vmp, 0)) != OK) { 712 printf("sef_cb_init_lu_restart: swap_proc_dyn_data failed\n"); 713 return r; 714 } 715 716 /* Rebind page tables. */ 717 pt_bind(&new_vmp->vm_pt, new_vmp); 718 pt_bind(&old_vmp->vm_pt, old_vmp); 719 pt_clearmapcache(); 720 721 /* Adjust process references. */ 722 adjust_proc_refs(); 723 724 /* Handle multi-component live update when necessary. */ 725 return sef_cb_init_vm_multi_lu(type, info); 726 } 727 728 /*===========================================================================* 729 * sef_cb_signal_handler * 730 *===========================================================================*/ 731 static void sef_cb_signal_handler(int signo) 732 { 733 /* Check for known kernel signals, ignore anything else. */ 734 switch(signo) { 735 /* There is a pending memory request from the kernel. */ 736 case SIGKMEM: 737 do_memory(); 738 break; 739 } 740 741 /* It can happen that we get stuck receiving signals 742 * without sef_receive() returning. We could need more memory 743 * though. 744 */ 745 if(missing_spares > 0) { 746 alloc_cycle(); /* pagetable code wants to be called */ 747 } 748 749 pt_clearmapcache(); 750 } 751 752 /*===========================================================================* 753 * map_service * 754 *===========================================================================*/ 755 static int map_service(struct rprocpub *rpub) 756 { 757 /* Map a new service by initializing its call mask. */ 758 int r, proc_nr; 759 760 if ((r = vm_isokendpt(rpub->endpoint, &proc_nr)) != OK) { 761 return r; 762 } 763 764 /* Copy the call mask. */ 765 acl_set(&vmproc[proc_nr], rpub->vm_call_mask, !IS_RPUB_BOOT_USR(rpub)); 766 767 return(OK); 768 } 769