/*===========================================================================* * do_exit * *===========================================================================*/ int do_exit(message *msg) { int proc; struct vmproc *vmp; SANITYCHECK(SCL_FUNCTIONS); if(vm_isokendpt(msg->VME_ENDPOINT, &proc) != OK) { printf("VM: bogus endpoint VM_EXIT %d\n", msg->VME_ENDPOINT); return EINVAL; } vmp = &vmproc[proc]; if(!(vmp->vm_flags & VMF_EXITING)) { printf("VM: unannounced VM_EXIT %d\n", msg->VME_ENDPOINT); return EINVAL; } { /* Free pagetable and pages allocated by pt code. */ SANITYCHECK(SCL_DETAIL); free_proc(vmp); SANITYCHECK(SCL_DETAIL); } SANITYCHECK(SCL_DETAIL); /* Reset process slot fields. */ clear_proc(vmp); SANITYCHECK(SCL_FUNCTIONS); return OK; }
/*===========================================================================* * do_fork * *===========================================================================*/ int do_fork(message *msg) { int r, proc, childproc; struct vmproc *vmp, *vmc; pt_t origpt; vir_bytes msgaddr; SANITYCHECK(SCL_FUNCTIONS); if(vm_isokendpt(msg->VMF_ENDPOINT, &proc) != OK) { printf("VM: bogus endpoint VM_FORK %d\n", msg->VMF_ENDPOINT); SANITYCHECK(SCL_FUNCTIONS); return EINVAL; } childproc = msg->VMF_SLOTNO; if(childproc < 0 || childproc >= NR_PROCS) { printf("VM: bogus slotno VM_FORK %d\n", msg->VMF_SLOTNO); SANITYCHECK(SCL_FUNCTIONS); return EINVAL; } vmp = &vmproc[proc]; /* parent */ vmc = &vmproc[childproc]; /* child */ assert(vmc->vm_slot == childproc); /* The child is basically a copy of the parent. */ origpt = vmc->vm_pt; *vmc = *vmp; vmc->vm_slot = childproc; region_init(&vmc->vm_regions_avl); vmc->vm_endpoint = NONE; /* In case someone tries to use it. */ vmc->vm_pt = origpt; #if VMSTATS vmc->vm_bytecopies = 0; #endif if(pt_new(&vmc->vm_pt) != OK) { printf("VM: fork: pt_new failed\n"); return ENOMEM; } SANITYCHECK(SCL_DETAIL); if(map_proc_copy(vmc, vmp) != OK) { printf("VM: fork: map_proc_copy failed\n"); pt_free(&vmc->vm_pt); return(ENOMEM); } /* Only inherit these flags. */ vmc->vm_flags &= VMF_INUSE; /* inherit the priv call bitmaps */ memcpy(&vmc->vm_call_mask, &vmp->vm_call_mask, sizeof(vmc->vm_call_mask)); /* Tell kernel about the (now successful) FORK. */ if((r=sys_fork(vmp->vm_endpoint, childproc, &vmc->vm_endpoint, PFF_VMINHIBIT, &msgaddr)) != OK) { panic("do_fork can't sys_fork: %d", r); } if((r=pt_bind(&vmc->vm_pt, vmc)) != OK) panic("fork can't pt_bind: %d", r); { vir_bytes vir; /* making these messages writable is an optimisation * and its return value needn't be checked. */ vir = msgaddr; if (handle_memory(vmc, vir, sizeof(message), 1) != OK) panic("do_fork: handle_memory for child failed\n"); vir = msgaddr; if (handle_memory(vmp, vir, sizeof(message), 1) != OK) panic("do_fork: handle_memory for parent failed\n"); } /* Inform caller of new child endpoint. */ msg->VMF_CHILD_ENDPOINT = vmc->vm_endpoint; SANITYCHECK(SCL_FUNCTIONS); return OK; }
/*===========================================================================* * do_fork * *===========================================================================*/ PUBLIC int do_fork(message *msg) { int r, proc, s, childproc, fullvm; struct vmproc *vmp, *vmc; pt_t origpt; vir_bytes msgaddr; SANITYCHECK(SCL_FUNCTIONS); if(vm_isokendpt(msg->VMF_ENDPOINT, &proc) != OK) { printf("VM: bogus endpoint VM_FORK %d\n", msg->VMF_ENDPOINT); SANITYCHECK(SCL_FUNCTIONS); return EINVAL; } childproc = msg->VMF_SLOTNO; if(childproc < 0 || childproc >= NR_PROCS) { printf("VM: bogus slotno VM_FORK %d\n", msg->VMF_SLOTNO); SANITYCHECK(SCL_FUNCTIONS); return EINVAL; } vmp = &vmproc[proc]; /* parent */ vmc = &vmproc[childproc]; /* child */ assert(vmc->vm_slot == childproc); if(vmp->vm_flags & VMF_HAS_DMA) { printf("VM: %d has DMA memory and may not fork\n", msg->VMF_ENDPOINT); return EINVAL; } fullvm = vmp->vm_flags & VMF_HASPT; /* The child is basically a copy of the parent. */ origpt = vmc->vm_pt; *vmc = *vmp; vmc->vm_slot = childproc; vmc->vm_regions = NULL; yielded_init(&vmc->vm_yielded_blocks); vmc->vm_endpoint = NONE; /* In case someone tries to use it. */ vmc->vm_pt = origpt; vmc->vm_flags &= ~VMF_HASPT; #if VMSTATS vmc->vm_bytecopies = 0; #endif if(pt_new(&vmc->vm_pt) != OK) { printf("VM: fork: pt_new failed\n"); return ENOMEM; } vmc->vm_flags |= VMF_HASPT; if(fullvm) { SANITYCHECK(SCL_DETAIL); if(map_proc_copy(vmc, vmp) != OK) { printf("VM: fork: map_proc_copy failed\n"); pt_free(&vmc->vm_pt); return(ENOMEM); } if(vmp->vm_heap) { vmc->vm_heap = map_region_lookup_tag(vmc, VRT_HEAP); assert(vmc->vm_heap); } SANITYCHECK(SCL_DETAIL); } else { vir_bytes sp; struct vir_region *heap, *stack; vir_bytes text_bytes, data_bytes, stack_bytes, parent_gap_bytes, child_gap_bytes; /* Get SP of new process (using parent). */ if(get_stack_ptr(vmp->vm_endpoint, &sp) != OK) { printf("VM: fork: get_stack_ptr failed for %d\n", vmp->vm_endpoint); return ENOMEM; } /* Update size of stack segment using current SP. */ if(adjust(vmp, vmp->vm_arch.vm_seg[D].mem_len, sp) != OK) { printf("VM: fork: adjust failed for %d\n", vmp->vm_endpoint); return ENOMEM; } /* Copy newly adjust()ed stack segment size to child. */ vmc->vm_arch.vm_seg[S] = vmp->vm_arch.vm_seg[S]; text_bytes = CLICK2ABS(vmc->vm_arch.vm_seg[T].mem_len); data_bytes = CLICK2ABS(vmc->vm_arch.vm_seg[D].mem_len); stack_bytes = CLICK2ABS(vmc->vm_arch.vm_seg[S].mem_len); /* how much space after break and before lower end (which is the * logical top) of stack for the parent */ parent_gap_bytes = CLICK2ABS(vmc->vm_arch.vm_seg[S].mem_vir - vmc->vm_arch.vm_seg[D].mem_len); /* how much space can the child stack grow downwards, below * the current SP? The rest of the gap is available for the * heap to grow upwards. */ child_gap_bytes = VM_PAGE_SIZE; if((r=proc_new(vmc, VM_PROCSTART, text_bytes, data_bytes, stack_bytes, child_gap_bytes, 0, 0, CLICK2ABS(vmc->vm_arch.vm_seg[S].mem_vir + vmc->vm_arch.vm_seg[S].mem_len), 1)) != OK) { printf("VM: fork: proc_new failed\n"); return r; } if(!(heap = map_region_lookup_tag(vmc, VRT_HEAP))) panic("couldn't lookup heap"); assert(heap->phys); if(!(stack = map_region_lookup_tag(vmc, VRT_STACK))) panic("couldn't lookup stack"); assert(stack->phys); /* Now copy the memory regions. */ if(vmc->vm_arch.vm_seg[T].mem_len > 0) { struct vir_region *text; if(!(text = map_region_lookup_tag(vmc, VRT_TEXT))) panic("couldn't lookup text"); assert(text->phys); if(copy_abs2region(CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys), text, 0, text_bytes) != OK) panic("couldn't copy text"); } if(copy_abs2region(CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys), heap, 0, data_bytes) != OK) panic("couldn't copy heap"); if(copy_abs2region(CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys + vmc->vm_arch.vm_seg[D].mem_len) + parent_gap_bytes, stack, child_gap_bytes, stack_bytes) != OK) panic("couldn't copy stack"); } /* Only inherit these flags. */ vmc->vm_flags &= (VMF_INUSE|VMF_SEPARATE|VMF_HASPT); /* inherit the priv call bitmaps */ memcpy(&vmc->vm_call_mask, &vmp->vm_call_mask, sizeof(vmc->vm_call_mask)); /* Tell kernel about the (now successful) FORK. */ if((r=sys_fork(vmp->vm_endpoint, childproc, &vmc->vm_endpoint, vmc->vm_arch.vm_seg, PFF_VMINHIBIT, &msgaddr)) != OK) { panic("do_fork can't sys_fork: %d", r); } if(fullvm) { vir_bytes vir; /* making these messages writable is an optimisation * and its return value needn't be checked. */ vir = arch_vir2map(vmc, msgaddr); handle_memory(vmc, vir, sizeof(message), 1); vir = arch_vir2map(vmp, msgaddr); handle_memory(vmp, vir, sizeof(message), 1); } if((r=pt_bind(&vmc->vm_pt, vmc)) != OK) panic("fork can't pt_bind: %d", r); /* Inform caller of new child endpoint. */ msg->VMF_CHILD_ENDPOINT = vmc->vm_endpoint; SANITYCHECK(SCL_FUNCTIONS); return OK; }
/*===========================================================================* * main * *===========================================================================*/ PUBLIC int main(void) { message msg; int result, who_e; /* SEF local startup. */ sef_local_startup(); /* This is VM's main loop. */ while (TRUE) { int r, c; SANITYCHECK(SCL_TOP); if(missing_spares > 0) { pt_cycle(); /* pagetable code wants to be called */ } SANITYCHECK(SCL_DETAIL); if ((r=sef_receive(ANY, &msg)) != OK) vm_panic("sef_receive() error", r); SANITYCHECK(SCL_DETAIL); if(msg.m_type & NOTIFY_MESSAGE) { switch(msg.m_source) { case SYSTEM: /* Kernel wants to have memory ranges * verified, and/or pagefaults handled. */ do_memory(); break; case HARDWARE: do_pagefaults(); break; case PM_PROC_NR: /* PM sends a notify() on shutdown, which * is OK and we ignore. */ break; default: /* No-one else should send us notifies. */ printf("VM: ignoring notify() from %d\n", msg.m_source); break; } continue; } who_e = msg.m_source; c = CALLNUMBER(msg.m_type); result = ENOSYS; /* Out of range or restricted calls return this. */ if(c < 0 || !vm_calls[c].vmc_func) { printf("VM: out of range or missing callnr %d from %d\n", msg.m_type, who_e); } else if (vm_acl_ok(who_e, c) != OK) { printf("VM: unauthorized %s by %d\n", vm_calls[c].vmc_name, who_e); } else { SANITYCHECK(SCL_FUNCTIONS); result = vm_calls[c].vmc_func(&msg); SANITYCHECK(SCL_FUNCTIONS); } /* Send reply message, unless the return code is SUSPEND, * which is a pseudo-result suppressing the reply message. */ if(result != SUSPEND) { SANITYCHECK(SCL_DETAIL); msg.m_type = result; if((r=send(who_e, &msg)) != OK) { printf("VM: couldn't send %d to %d (err %d)\n", msg.m_type, who_e, r); vm_panic("send() error", NO_NUM); } SANITYCHECK(SCL_DETAIL); } SANITYCHECK(SCL_DETAIL); } return(OK); }
/*===========================================================================* * main * *===========================================================================*/ int main(void) { message msg; int result, who_e, rcv_sts; int caller_slot; /* Initialize system so that all processes are runnable */ init_vm(); /* Register init callbacks. */ sef_setcb_init_restart(sef_cb_init_fail); sef_setcb_signal_handler(sef_cb_signal_handler); /* Let SEF perform startup. */ sef_startup(); SANITYCHECK(SCL_TOP); /* This is VM's main loop. */ while (TRUE) { int r, c; u32_t type, param; SANITYCHECK(SCL_TOP); if(missing_spares > 0) { alloc_cycle(); /* mem alloc code wants to be called */ } if ((r=sef_receive_status(ANY, &msg, &rcv_sts)) != OK) panic("sef_receive_status() error: %d", r); if (is_ipc_notify(rcv_sts)) { /* Unexpected notify(). */ printf("VM: ignoring notify() from %d\n", msg.m_source); continue; } who_e = msg.m_source; if(vm_isokendpt(who_e, &caller_slot) != OK) panic("invalid caller %d", who_e); type = param = msg.m_type; type &= 0x0000FFFF; param >>= 16; c = CALLNUMBER(type); result = ENOSYS; /* Out of range or restricted calls return this. */ if(msg.m_type == RS_INIT && msg.m_source == RS_PROC_NR) { result = do_rs_init(&msg); } else if (msg.m_type == VM_PAGEFAULT) { if (!IPC_STATUS_FLAGS_TEST(rcv_sts, IPC_FLG_MSG_FROM_KERNEL)) { printf("VM: process %d faked VM_PAGEFAULT " "message!\n", msg.m_source); } do_pagefaults(&msg); /* * do not reply to this call, the caller is unblocked by * a sys_vmctl() call in do_pagefaults if success. VM panics * otherwise */ continue; } else if(c < 0 || !vm_calls[c].vmc_func) { /* out of range or missing callnr */ } else { if (acl_check(&vmproc[caller_slot], c) != OK) { printf("VM: unauthorized %s by %d\n", vm_calls[c].vmc_name, who_e); } else { SANITYCHECK(SCL_FUNCTIONS); result = vm_calls[c].vmc_func(&msg); SANITYCHECK(SCL_FUNCTIONS); } } /* Send reply message, unless the return code is SUSPEND, * which is a pseudo-result suppressing the reply message. */ if(result != SUSPEND) { msg.m_type = result; if((r=send(who_e, &msg)) != OK) { printf("VM: couldn't send %d to %d (err %d)\n", msg.m_type, who_e, r); panic("send() error"); } } } return(OK); }
/*===========================================================================* * main * *===========================================================================*/ int main(void) { kipc_msg_t msg; int result, who_e; #if SANITYCHECKS incheck = nocheck = 0; FIXME("VM SANITYCHECKS are on"); #endif vm_paged = 1; env_parse("vm_paged", "d", 0, &vm_paged, 0, 1); #if SANITYCHECKS env_parse("vm_sanitychecklevel", "d", 0, &vm_sanitychecklevel, 0, SCL_MAX); #endif vm_init(); /* This is VM's main loop. */ while (TRUE) { int r, c; SANITYCHECK(SCL_TOP); if(missing_spares > 0) { pt_cycle(); /* pagetable code wants to be called */ } SANITYCHECK(SCL_DETAIL); if ((r=kipc_module_call(KIPC_RECEIVE, 0, ENDPT_ANY, &msg)) != 0) vm_panic("receive() error", r); SANITYCHECK(SCL_DETAIL); if(msg.m_type & NOTIFY_MESSAGE) { switch(msg.m_source) { case SYSTEM: /* Kernel wants to have memory ranges * verified, and/or pagefaults handled. */ do_memory(); break; case HARDWARE: do_pagefaults(); break; case PM_PROC_NR: /* PM sends a notify() on shutdown, which * is OK and we ignore. */ break; default: /* No-one else should send us notifies. */ printk("VM: ignoring notify() from %d\n", msg.m_source); break; } continue; } who_e = msg.m_source; c = CALLNUMBER(msg.m_type); result = -ENOSYS; /* Out of range or restricted calls return this. */ if(c < 0 || !vm_calls[c].vmc_func) { printk("VM: out of range or missing callnr %d from %d\n", msg.m_type, who_e); } else if (vm_acl_ok(who_e, c) != 0) { printk("VM: unauthorized %s by %d\n", vm_calls[c].vmc_name, who_e); } else { SANITYCHECK(SCL_FUNCTIONS); result = vm_calls[c].vmc_func(&msg); SANITYCHECK(SCL_FUNCTIONS); } /* Send reply message, unless the return code is SUSPEND, * which is a pseudo-result suppressing the reply message. */ if(result != SUSPEND) { SANITYCHECK(SCL_DETAIL); msg.m_type = result; if((r=kipc_module_call(KIPC_SEND, 0, who_e, &msg)) != 0) { printk("VM: couldn't send %d to %d (err %d)\n", msg.m_type, who_e, r); vm_panic("send() error", NO_NUM); } SANITYCHECK(SCL_DETAIL); } SANITYCHECK(SCL_DETAIL); } return 0; }
/*===========================================================================* * main * *===========================================================================*/ PUBLIC int main(void) { message msg; int result, who_e, rcv_sts; int caller_slot; struct vmproc *vmp_caller; /* SEF local startup. */ sef_local_startup(); SANITYCHECK(SCL_TOP); /* This is VM's main loop. */ while (TRUE) { int r, c; SANITYCHECK(SCL_TOP); if(missing_spares > 0) { pt_cycle(); /* pagetable code wants to be called */ } if ((r=sef_receive_status(ANY, &msg, &rcv_sts)) != OK) panic("sef_receive_status() error: %d", r); if (is_ipc_notify(rcv_sts)) { /* Unexpected notify(). */ printf("VM: ignoring notify() from %d\n", msg.m_source); continue; } who_e = msg.m_source; if(vm_isokendpt(who_e, &caller_slot) != OK) panic("invalid caller", who_e); vmp_caller = &vmproc[caller_slot]; c = CALLNUMBER(msg.m_type); result = ENOSYS; /* Out of range or restricted calls return this. */ if (msg.m_type == VM_PAGEFAULT) { if (!IPC_STATUS_FLAGS_TEST(rcv_sts, IPC_FLG_MSG_FROM_KERNEL)) { printf("VM: process %d faked VM_PAGEFAULT " "message!\n", msg.m_source); } do_pagefaults(&msg); /* * do not reply to this call, the caller is unblocked by * a sys_vmctl() call in do_pagefaults if success. VM panics * otherwise */ continue; } else if(c < 0 || !vm_calls[c].vmc_func) { /* out of range or missing callnr */ } else { if (vm_acl_ok(who_e, c) != OK) { printf("VM: unauthorized %s by %d\n", vm_calls[c].vmc_name, who_e); } else { SANITYCHECK(SCL_FUNCTIONS); result = vm_calls[c].vmc_func(&msg); SANITYCHECK(SCL_FUNCTIONS); } } /* Send reply message, unless the return code is SUSPEND, * which is a pseudo-result suppressing the reply message. */ if(result != SUSPEND) { msg.m_type = result; if((r=send(who_e, &msg)) != OK) { printf("VM: couldn't send %d to %d (err %d)\n", msg.m_type, who_e, r); panic("send() error"); } } } return(OK); }