/*===========================================================================* * do_mmap * *===========================================================================*/ int do_mmap(message *m) { int r, n; struct vmproc *vmp; vir_bytes addr = m->VMM_ADDR; struct vir_region *vr = NULL; int execpriv = 0; size_t len = (vir_bytes) m->VMM_LEN; /* RS and VFS can do slightly more special mmap() things */ if(m->m_source == VFS_PROC_NR || m->m_source == RS_PROC_NR) execpriv = 1; if(m->VMM_FLAGS & MAP_THIRDPARTY) { if(!execpriv) return EPERM; if((r=vm_isokendpt(m->VMM_FORWHOM, &n)) != OK) return ESRCH; } else { /* regular mmap, i.e. for caller */ if((r=vm_isokendpt(m->m_source, &n)) != OK) { panic("do_mmap: message from strange source: %d", m->m_source); } } vmp = &vmproc[n]; if(m->VMM_FD == -1 || (m->VMM_FLAGS & MAP_ANON)) { /* actual memory in some form */ mem_type_t *mt = NULL; if(m->VMM_FD != -1 || len <= 0) { printf("VM: mmap: fd %d, len 0x%x\n", m->VMM_FD, len); return EINVAL; } /* Contiguous phys memory has to be preallocated. */ if((m->VMM_FLAGS & (MAP_CONTIG|MAP_PREALLOC)) == MAP_CONTIG) { return EINVAL; } if(m->VMM_FLAGS & MAP_CONTIG) { mt = &mem_type_anon_contig; } else mt = &mem_type_anon; if(!(vr = mmap_region(vmp, addr, m->VMM_FLAGS, len, VR_WRITABLE | VR_ANON, mt, execpriv))) { return ENOMEM; } } else { return ENXIO; } /* Return mapping, as seen from process. */ m->VMM_RETADDR = vr->vaddr; return OK; }
/*===========================================================================* * do_remap * *===========================================================================*/ PUBLIC int do_remap(message *m) { int dn, sn; vir_bytes da, sa, startv; size_t size; struct vir_region *vr, *region; struct vmproc *dvmp, *svmp; int r; da = (vir_bytes) m->VMRE_DA; sa = (vir_bytes) m->VMRE_SA; size = m->VMRE_SIZE; if ((r = vm_isokendpt((endpoint_t) m->VMRE_D, &dn)) != OK) return EINVAL; if ((r = vm_isokendpt((endpoint_t) m->VMRE_S, &sn)) != OK) return EINVAL; dvmp = &vmproc[dn]; svmp = &vmproc[sn]; /* da is not translated by arch_vir2map(), * it's handled a little differently, * since in map_remap(), we have to know * about whether the user needs to bind to * THAT address or be chosen by the system. */ sa = arch_vir2map(svmp, sa); if (!(region = map_lookup(svmp, sa))) return EINVAL; if(region->vaddr != sa) { printf("VM: do_remap: not start of region.\n"); return EFAULT; } if(!(region->flags & VR_SHARED)) { printf("VM: do_remap: not shared.\n"); return EFAULT; } if (size % VM_PAGE_SIZE) size += VM_PAGE_SIZE - size % VM_PAGE_SIZE; if(size != region->length) { printf("VM: do_remap: not size of region.\n"); return EFAULT; } if ((r = map_remap(dvmp, da, size, region, &startv)) != OK) return r; m->VMRE_RETA = (char *) arch_map2vir(dvmp, startv); return OK; }
/*===========================================================================* * do_rs_update * *===========================================================================*/ int do_rs_update(message *m_ptr) { endpoint_t src_e, dst_e, reply_e; int src_p, dst_p; struct vmproc *src_vmp, *dst_vmp; int r; src_e = m_ptr->VM_RS_SRC_ENDPT; dst_e = m_ptr->VM_RS_DST_ENDPT; /* Lookup slots for source and destination process. */ if(vm_isokendpt(src_e, &src_p) != OK) { printf("do_rs_update: bad src endpoint %d\n", src_e); return EINVAL; } src_vmp = &vmproc[src_p]; if(vm_isokendpt(dst_e, &dst_p) != OK) { printf("do_rs_update: bad dst endpoint %d\n", dst_e); return EINVAL; } dst_vmp = &vmproc[dst_p]; /* Let the kernel do the update first. */ r = sys_update(src_e, dst_e); if(r != OK) { return r; } /* Do the update in VM now. */ r = swap_proc_slot(src_vmp, dst_vmp); if(r != OK) { return r; } r = swap_proc_dyn_data(src_vmp, dst_vmp); if(r != OK) { return r; } pt_bind(&src_vmp->vm_pt, src_vmp); pt_bind(&dst_vmp->vm_pt, dst_vmp); /* Reply, update-aware. */ reply_e = m_ptr->m_source; if(reply_e == src_e) reply_e = dst_e; else if(reply_e == dst_e) reply_e = src_e; m_ptr->m_type = OK; r = send(reply_e, m_ptr); if(r != OK) { panic("send() error"); } return SUSPEND; }
/*===========================================================================* * do_rs_set_priv * *===========================================================================*/ int do_rs_set_priv(message *m) { int r, n, nr; struct vmproc *vmp; bitchunk_t call_mask[VM_CALL_MASK_SIZE], *call_mask_p; nr = m->VM_RS_NR; if ((r = vm_isokendpt(nr, &n)) != OK) { printf("do_rs_set_priv: bad endpoint %d\n", nr); return EINVAL; } vmp = &vmproc[n]; if (m->VM_RS_BUF) { r = sys_datacopy(m->m_source, (vir_bytes) m->VM_RS_BUF, SELF, (vir_bytes) call_mask, sizeof(call_mask)); if (r != OK) return r; call_mask_p = call_mask; } else { if (m->VM_RS_SYS) { printf("VM: do_rs_set_priv: sys procs don't share!\n"); return EINVAL; } call_mask_p = NULL; } acl_set(vmp, call_mask_p, m->VM_RS_SYS); return OK; }
/*===========================================================================* * do_push_sig * *===========================================================================*/ PUBLIC int do_push_sig(message *msg) { int r, n; endpoint_t ep; vir_bytes sp; struct vmproc *vmp; ep = msg->VMPS_ENDPOINT; if((r=vm_isokendpt(ep, &n)) != OK) { printf("VM: bogus endpoint %d from %d\n", ep, msg->m_source); return r; } vmp = &vmproc[n]; if ((r=get_stack_ptr(ep, &sp)) != OK) vm_panic("couldn't get new stack pointer (for sig)",r); /* Save old SP for caller */ msg->VMPS_OLD_SP = (char *) sp; /* Make room for the sigcontext and sigframe struct. */ sp -= sizeof(struct sigcontext) + 3 * sizeof(char *) + 2 * sizeof(int); if ((r=adjust(vmp, vmp->vm_arch.vm_seg[D].mem_len, sp)) != OK) { printf("VM: do_push_sig: adjust() failed: %d\n", r); return r; } return OK; }
int do_procctl(message *msg) { endpoint_t proc; struct vmproc *vmp; if(vm_isokendpt(msg->VMPCTL_WHO, &proc) != OK) { printf("VM: bogus endpoint VM_PROCCTL %d\n", msg->VMPCTL_WHO); return EINVAL; } vmp = &vmproc[proc]; switch(msg->VMPCTL_PARAM) { case VMPPARAM_CLEAR: if(msg->m_source != RS_PROC_NR && msg->m_source != VFS_PROC_NR) return EPERM; free_proc(vmp); if(pt_new(&vmp->vm_pt) != OK) panic("VMPPARAM_CLEAR: pt_new failed"); pt_bind(&vmp->vm_pt, vmp); return OK; default: return EINVAL; } return OK; }
/*===========================================================================* * 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_unmap_phys * *===========================================================================*/ PUBLIC int do_unmap_phys(message *m) { int r, n; struct vmproc *vmp; endpoint_t target; struct vir_region *region; target = m->VMUP_EP; if(target == SELF) target = m->m_source; if((r=vm_isokendpt(target, &n)) != OK) return EINVAL; vmp = &vmproc[n]; if(!(region = map_lookup(vmp, arch_vir2map(vmp, (vir_bytes) m->VMUM_ADDR)))) { return EINVAL; } if(!(region->flags & VR_DIRECT)) { return EINVAL; } if(map_unmap_region(vmp, region, region->length) != OK) { return EINVAL; } return OK; }
/*===========================================================================* * do_vfs_reply * *===========================================================================*/ int do_vfs_reply(message *m) { /* VFS has handled a VM request and VFS has replied. It must be the * active request. */ struct vfs_request_node *orignode = active; vfs_callback_t req_callback; void *cbarg; int n; struct vmproc *vmp; assert(active); assert(active->req_id == m->VMV_REQID); /* the endpoint may have exited */ if(vm_isokendpt(m->VMV_ENDPOINT, &n) != OK) vmp = NULL; else vmp = &vmproc[n]; req_callback = active->callback; cbarg = active->opaque; active = NULL; /* Invoke requested reply-callback within VM. */ if(req_callback) req_callback(vmp, m, cbarg, orignode->reqstate); SLABFREE(orignode); /* Send the next request message if any and not re-activated. */ if(first_queued && !active) activate(); return SUSPEND; /* don't reply to the reply */ }
/*===========================================================================* * do_mmap * *===========================================================================*/ PUBLIC int do_mmap(message *m) { int r, n; struct vmproc *vmp; int mfflags = 0; struct vir_region *vr = NULL; if((r=vm_isokendpt(m->m_source, &n)) != OK) { panic("do_mmap: message from strange source: %d", m->m_source); } vmp = &vmproc[n]; if(!(vmp->vm_flags & VMF_HASPT)) return ENXIO; if(m->VMM_FD == -1 || (m->VMM_FLAGS & MAP_ANON)) { int s; vir_bytes v; u32_t vrflags = VR_ANON | VR_WRITABLE; size_t len = (vir_bytes) m->VMM_LEN; if(m->VMM_FD != -1) { return EINVAL; } /* Contiguous phys memory has to be preallocated. */ if((m->VMM_FLAGS & (MAP_CONTIG|MAP_PREALLOC)) == MAP_CONTIG) { return EINVAL; } if(m->VMM_FLAGS & MAP_PREALLOC) mfflags |= MF_PREALLOC; if(m->VMM_FLAGS & MAP_LOWER16M) vrflags |= VR_LOWER16MB; if(m->VMM_FLAGS & MAP_LOWER1M) vrflags |= VR_LOWER1MB; if(m->VMM_FLAGS & MAP_ALIGN64K) vrflags |= VR_PHYS64K; if(m->VMM_FLAGS & MAP_SHARED) vrflags |= VR_SHARED; if(m->VMM_FLAGS & MAP_CONTIG) vrflags |= VR_CONTIG; if(len % VM_PAGE_SIZE) len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE); if(!(vr = map_page_region(vmp, arch_vir2map(vmp, m->VMM_ADDR ? m->VMM_ADDR : vmp->vm_stacktop), VM_DATATOP, len, MAP_NONE, vrflags, mfflags))) { return ENOMEM; } } else { return ENOSYS; } /* Return mapping, as seen from process. */ assert(vr); m->VMM_RETADDR = arch_map2vir(vmp, vr->vaddr); return OK; }
/*===========================================================================* * do_munmap * *===========================================================================*/ int do_munmap(message *m) { int r, n; struct vmproc *vmp; vir_bytes addr, len, offset; struct vir_region *vr; endpoint_t target = SELF; if(m->m_type == VM_UNMAP_PHYS) { target = m->VMUP_EP; } else if(m->m_type == VM_SHM_UNMAP) { target = m->VMUN_ENDPT; } if(target == SELF) target = m->m_source; if((r=vm_isokendpt(target, &n)) != OK) { panic("do_mmap: message from strange source: %d", m->m_source); } vmp = &vmproc[n]; if(m->m_type == VM_UNMAP_PHYS) { addr = (vir_bytes) m->VMUP_VADDR; } else if(m->m_type == VM_SHM_UNMAP) { addr = (vir_bytes) m->VMUN_ADDR; } else addr = (vir_bytes) m->VMUM_ADDR; if(!(vr = map_lookup(vmp, addr, NULL))) { printf("VM: unmap: virtual address 0x%lx not found in %d\n", addr, target); return EFAULT; } if(addr % VM_PAGE_SIZE) return EFAULT; if(m->m_type == VM_UNMAP_PHYS || m->m_type == VM_SHM_UNMAP) { len = vr->length; } else len = roundup(m->VMUM_LEN, VM_PAGE_SIZE); offset = addr - vr->vaddr; if(offset + len > vr->length) { printf("munmap: addr 0x%lx len 0x%lx spills out of region\n", addr, len); return EFAULT; } if(map_unmap_region(vmp, vr, offset, len) != OK) panic("do_munmap: map_unmap_region failed"); return OK; }
/*===========================================================================* * do_watch_exit * *===========================================================================*/ PUBLIC int do_watch_exit(message *m) { endpoint_t e = m->VM_WE_EP; struct vmproc *vmp; int p; if(vm_isokendpt(e, &p) != OK) return ESRCH; vmp = &vmproc[p]; vmp->vm_flags |= VMF_WATCHEXIT; return OK; }
/*===========================================================================* * do_map_phys * *===========================================================================*/ PUBLIC int do_map_phys(message *m) { int r, n; struct vmproc *vmp; endpoint_t target; struct vir_region *vr; vir_bytes len; phys_bytes startaddr; size_t offset; target = m->VMMP_EP; len = m->VMMP_LEN; if (len <= 0) return EINVAL; if(target == SELF) target = m->m_source; if((r=vm_isokendpt(target, &n)) != OK) return EINVAL; startaddr = (vir_bytes)m->VMMP_PHADDR; /* First check permission, then round range down/up. Caller can't * help it if we can't map in lower than page granularity. */ if(map_perm_check(m->m_source, target, startaddr, len) != OK) { printf("VM: unauthorized mapping of 0x%lx by %d\n", startaddr, m->m_source); return EPERM; } vmp = &vmproc[n]; if(!(vmp->vm_flags & VMF_HASPT)) return ENXIO; offset = startaddr % VM_PAGE_SIZE; len += offset; startaddr -= offset; if(len % VM_PAGE_SIZE) len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE); if(!(vr = map_page_region(vmp, arch_vir2map(vmp, vmp->vm_stacktop), VM_DATATOP, len, startaddr, VR_DIRECT | VR_NOPF | VR_WRITABLE, 0))) { return ENOMEM; } m->VMMP_VADDR_REPLY = (void *) (arch_map2vir(vmp, vr->vaddr) + offset); return OK; }
/*===========================================================================* * do_remap * *===========================================================================*/ int do_remap(kipc_msg_t *m) { int d, dn, s, sn; vir_bytes da, sa, startv; size_t size; struct vir_region *vr, *region; struct vmproc *dvmp, *svmp; int r; d = m->VMRE_D; s = m->VMRE_S; da = (vir_bytes) m->VMRE_DA; sa = (vir_bytes) m->VMRE_SA; size = m->VMRE_SIZE; if ((r = vm_isokendpt(d, &dn)) != 0) return -EINVAL; if ((r = vm_isokendpt(s, &sn)) != 0) return -EINVAL; dvmp = &vmproc[dn]; svmp = &vmproc[sn]; /* da is not translated by arch_vir2map(), * it's handled a little differently, * since in map_remap(), we have to know * about whether the user needs to bind to * THAT address or be chosen by the system. */ sa = arch_vir2map(svmp, sa); if (!(region = map_lookup(svmp, sa))) return -EINVAL; if ((r = map_remap(dvmp, da, size, region, &startv)) != 0) return r; m->VMRE_RETA = (char *) arch_map2vir(dvmp, startv); return 0; }
/*===========================================================================* * do_map_phys * *===========================================================================*/ int do_map_phys(message *m) { int r, n; struct vmproc *vmp; endpoint_t target; struct vir_region *vr; vir_bytes len; phys_bytes startaddr; size_t offset; target = m->m_lsys_vm_map_phys.ep; len = m->m_lsys_vm_map_phys.len; if (len <= 0) return EINVAL; if(target == SELF) target = m->m_source; if((r=vm_isokendpt(target, &n)) != OK) return EINVAL; startaddr = (vir_bytes)m->m_lsys_vm_map_phys.phaddr; /* First check permission, then round range down/up. Caller can't * help it if we can't map in lower than page granularity. */ if(map_perm_check(m->m_source, target, startaddr, len) != OK) { printf("VM: unauthorized mapping of 0x%lx by %d\n", startaddr, m->m_source); return EPERM; } vmp = &vmproc[n]; offset = startaddr % VM_PAGE_SIZE; len += offset; startaddr -= offset; if(len % VM_PAGE_SIZE) len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE); if(!(vr = map_page_region(vmp, 0, VM_DATATOP, len, VR_DIRECT | VR_WRITABLE, 0, &mem_type_directphys))) { return ENOMEM; } phys_setphys(vr, startaddr); m->m_lsys_vm_map_phys.reply = (void *) (vr->vaddr + offset); return OK; }
int scall_mmap(kipc_msg_t *m) { int err, n; struct vmproc *vmp; int mfflags = 0; struct vir_region *vr = NULL; if((err = vm_isokendpt(m->m_source, &n)) != 0) { vm_panic("do_mmap: message from strange source", m->m_source); } vmp = &vmproc[n]; if(!(vmp->vm_flags & VMF_HASPT)) return -ENXIO; if(m->VMM_FD == -1 || (m->VMM_FLAGS & MAP_ANONYMOUS)) { int s; vir_bytes v; u32_t vrflags = VR_ANON | VR_WRITABLE; size_t len = (vir_bytes) m->VMM_LEN; if(m->VMM_FD != -1) { return -EINVAL; } if(m->VMM_FLAGS & MAP_CONTIG) mfflags |= MF_CONTIG; if(m->VMM_FLAGS & MAP_PREALLOC) mfflags |= MF_PREALLOC; if(m->VMM_FLAGS & MAP_LOWER16M) vrflags |= VR_LOWER16MB; if(m->VMM_FLAGS & MAP_LOWER1M) vrflags |= VR_LOWER1MB; if(m->VMM_FLAGS & MAP_ALIGN64K) vrflags |= VR_PHYS64K; if(m->VMM_FLAGS & MAP_SHARED) vrflags |= VR_SHARED; if(len % VM_PAGE_SIZE) len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE); if(!(vr = map_page_region(vmp, arch_vir2map(vmp, m->VMM_ADDR ? m->VMM_ADDR : vmp->vm_stacktop), VM_DATATOP, len, MAP_NONE, vrflags, mfflags))) { return -ENOMEM; } } else { return -ENOSYS; } /* Return mapping, as seen from process. */ vm_assert(vr); m->VMM_RETADDR = arch_map2vir(vmp, vr->vaddr); return m->VMM_RETADDR; }
/*===========================================================================* * do_brk * *===========================================================================*/ int do_brk(message *msg) { /* Perform the brk(addr) system call. * The parameter, 'addr' is the new virtual address in D space. */ int proc; if(vm_isokendpt(msg->VMB_ENDPOINT, &proc) != OK) { printf("VM: bogus endpoint VM_BRK %d\n", msg->VMB_ENDPOINT); return EINVAL; } return real_brk(&vmproc[proc], (vir_bytes) msg->VMB_ADDR); }
/*===========================================================================* * do_notify_sig * *===========================================================================*/ PUBLIC int do_notify_sig(message *m) { int i, avails = 0; endpoint_t ep = m->VM_NOTIFY_SIG_ENDPOINT; endpoint_t ipc_ep = m->VM_NOTIFY_SIG_IPC; int r; struct vmproc *vmp; int pslot; if(vm_isokendpt(ep, &pslot) != OK) return ESRCH; vmp = &vmproc[pslot]; /* Only record the event if we've been asked to report it. */ if(!(vmp->vm_flags & VMF_WATCHEXIT)) return OK; for (i = 0; i < NR_PROCS; i++) { /* its signal is already here */ if (!array[i].avail && array[i].ep == ep) goto out; if (array[i].avail) avails++; } if (!avails) { /* no slot for signals, unlikely */ printf("VM: no slot for signals!\n"); return ENOMEM; } for (i = 0; i < NR_PROCS; i++) { if (array[i].avail) { array[i].avail = 0; array[i].ep = ep; break; } } out: /* only care when IPC server starts up, * and bypass the process to be signal is IPC itself. */ if (ipc_ep != 0 && ep != ipc_ep) { r = notify(ipc_ep); if (r != OK) printf("VM: notify IPC error!\n"); } return OK; }
/*===========================================================================* * do_willexit * *===========================================================================*/ int do_willexit(message *msg) { int proc; struct vmproc *vmp; if(vm_isokendpt(msg->VMWE_ENDPOINT, &proc) != OK) { printf("VM: bogus endpoint VM_EXITING %d\n", msg->VMWE_ENDPOINT); return EINVAL; } vmp = &vmproc[proc]; vmp->vm_flags |= VMF_EXITING; return OK; }
/*===========================================================================* * do_getrusage * *===========================================================================*/ int do_getrusage(message *m) { int res, slot; struct vmproc *vmp; struct rusage r_usage; /* If the request is not from PM, it is coming directly from userland. * This is an obsolete construction. In the future, userland programs * should no longer be allowed to call vm_getrusage(2) directly at all. * For backward compatibility, we simply return success for now. */ if (m->m_source != PM_PROC_NR) return OK; /* Get the process for which resource usage is requested. */ if ((res = vm_isokendpt(m->m_lsys_vm_rusage.endpt, &slot)) != OK) return ESRCH; vmp = &vmproc[slot]; /* We are going to change only a few fields, so copy in the rusage * structure first. The structure is still in PM's address space at * this point, so use the message source. */ if ((res = sys_datacopy(m->m_source, m->m_lsys_vm_rusage.addr, SELF, (vir_bytes) &r_usage, (vir_bytes) sizeof(r_usage))) < 0) return res; if (!m->m_lsys_vm_rusage.children) { r_usage.ru_maxrss = vmp->vm_total_max / 1024L; /* unit is KB */ r_usage.ru_minflt = vmp->vm_minor_page_fault; r_usage.ru_majflt = vmp->vm_major_page_fault; } else { /* XXX TODO: return the fields for terminated, waited-for * children of the given process. We currently do not have this * information! In the future, rather than teaching VM about * the process hierarchy, PM should probably tell VM at process * exit time which other process should inherit its resource * usage fields. For now, we assume PM clears the fields before * making this call, so we don't zero the fields explicitly. */ } /* Copy out the resulting structure back to PM. */ return sys_datacopy(SELF, (vir_bytes) &r_usage, m->m_source, m->m_lsys_vm_rusage.addr, (vir_bytes) sizeof(r_usage)); }
/*===========================================================================* * do_vfs_reply * *===========================================================================*/ PUBLIC int do_vfs_reply(message *m) { /* Reply to a request has been received from vfs. Handle it. First verify * and look up which process, identified by endpoint, this is about. * Then call the callback function that was registered when the request * was done. Return result to vfs. */ endpoint_t ep; struct vmproc *vmp; int procno; callback_t cb; ep = m->VMV_ENDPOINT; if(vm_isokendpt(ep, &procno) != OK) { printf("VM:do_vfs_reply: reply %d about invalid endpoint %d\n", m->m_type, ep); vm_panic("do_vfs_reply: invalid endpoint from vfs", NO_NUM); } vmp = &vmproc[procno]; if(!vmp->vm_callback) { printf("VM:do_vfs_reply: reply %d: endpoint %d not waiting\n", m->m_type, ep); vm_panic("do_vfs_reply: invalid endpoint from vfs", NO_NUM); } if(vmp->vm_callback_type != m->m_type) { printf("VM:do_vfs_reply: reply %d unexpected for endpoint %d\n" " (expecting %d)\n", m->m_type, ep, vmp->vm_callback_type); vm_panic("do_vfs_reply: invalid reply from vfs", NO_NUM); } if(vmp->vm_flags & VMF_EXITING) { /* This is not fatal or impossible, but the callback * function has to realize it shouldn't do any PM or * VFS calls for this process. */ printf("VM:do_vfs_reply: reply %d for EXITING endpoint %d\n", m->m_type, ep); } /* All desired callback state has been used, so save and reset * the callback. This allows the callback to register another * one. */ cb = vmp->vm_callback; vmp->vm_callback = NULL; cb(vmp, m); return SUSPEND; }
static int getsrc(struct vir_region *region, struct vmproc **vmp, struct vir_region **r) { int srcproc; if(region->def_memtype != &mem_type_shared) { printf("shared region hasn't shared type but %s.\n", region->def_memtype->name); return EINVAL; } if(!region->param.shared.ep || !region->param.shared.vaddr) { printf("shared region has not defined source region.\n"); util_stacktrace(); return EINVAL; } if(vm_isokendpt((endpoint_t) region->param.shared.ep, &srcproc) != OK) { printf("VM: shared memory with missing source process.\n"); util_stacktrace(); return EINVAL; } *vmp = &vmproc[srcproc]; if(!(*r=map_lookup(*vmp, region->param.shared.vaddr, NULL))) { printf("VM: shared memory with missing vaddr 0x%lx.\n", region->param.shared.vaddr); return EINVAL; } if((*r)->def_memtype != &mem_type_anon) { printf("source region hasn't anon type but %s.\n", (*r)->def_memtype->name); return EINVAL; } if(region->param.shared.id != (*r)->id) { printf("source region has no matching id\n"); return EINVAL; } return OK; }
/*===========================================================================* * do_munmap * *===========================================================================*/ int do_munmap(message *m) { int r, n; struct vmproc *vmp; vir_bytes addr, len; endpoint_t target = SELF; if(m->m_type == VM_UNMAP_PHYS) { target = m->m_lsys_vm_unmap_phys.ep; } else if(m->m_type == VM_SHM_UNMAP) { target = m->m_lc_vm_shm_unmap.forwhom; } if(target == SELF) target = m->m_source; if((r=vm_isokendpt(target, &n)) != OK) { panic("do_mmap: message from strange source: %d", m->m_source); } vmp = &vmproc[n]; if(m->m_type == VM_UNMAP_PHYS) { addr = (vir_bytes) m->m_lsys_vm_unmap_phys.vaddr; } else if(m->m_type == VM_SHM_UNMAP) { addr = (vir_bytes) m->m_lc_vm_shm_unmap.addr; } else addr = (vir_bytes) m->VMUM_ADDR; if(addr % VM_PAGE_SIZE) return EFAULT; if(m->m_type == VM_UNMAP_PHYS || m->m_type == VM_SHM_UNMAP) { struct vir_region *vr; if(!(vr = map_lookup(vmp, addr, NULL))) { printf("VM: unmap: address 0x%lx not found in %d\n", addr, target); sys_diagctl_stacktrace(target); return EFAULT; } len = vr->length; } else len = roundup(m->VMUM_LEN, VM_PAGE_SIZE); return map_unmap_range(vmp, addr, len); }
/*===========================================================================* * do_munmap * *===========================================================================*/ PUBLIC int do_munmap(message *m) { int r, n; struct vmproc *vmp; vir_bytes addr, len; struct vir_region *vr; if((r=vm_isokendpt(m->m_source, &n)) != OK) { panic("do_mmap: message from strange source: %d", m->m_source); } vmp = &vmproc[n]; if(!(vmp->vm_flags & VMF_HASPT)) return ENXIO; if(m->m_type == VM_MUNMAP) { addr = (vir_bytes) arch_vir2map(vmp, (vir_bytes) m->VMUM_ADDR); } else if(m->m_type == VM_MUNMAP_TEXT) { addr = (vir_bytes) arch_vir2map_text(vmp, (vir_bytes) m->VMUM_ADDR); } else { panic("do_munmap: strange type"); } if(!(vr = map_lookup(vmp, addr))) { printf("VM: unmap: virtual address %p not found in %d\n", m->VMUM_ADDR, vmp->vm_endpoint); return EFAULT; } len = m->VMUM_LEN; if (len % VM_PAGE_SIZE) len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE); if(addr != vr->vaddr || len > vr->length || len < VM_PAGE_SIZE) { return EFAULT; } if(map_unmap_region(vmp, vr, len) != OK) panic("do_munmap: map_unmap_region failed"); return OK; }
int scall_munmap(kipc_msg_t *m) { int r, n; struct vmproc *vmp; vir_bytes addr, len; struct vir_region *vr; if((r = vm_isokendpt(m->m_source, &n)) != 0) { vm_panic("do_mmap: message from strange source", m->m_source); } vmp = &vmproc[n]; if (!(vmp->vm_flags & VMF_HASPT)) return -ENXIO; if (m->m_type == NNR_VM_MUNMAP) { addr = (vir_bytes) arch_vir2map(vmp, (vir_bytes) m->VMUM_ADDR); } else if(m->m_type == NNR_VM_MUNMAP_TEXT) { addr = (vir_bytes) arch_vir2map_text(vmp, (vir_bytes) m->VMUM_ADDR); } else { vm_panic("do_munmap: strange type", NO_NUM); } if (!(vr = map_lookup(vmp, addr))) { printk("VM: unmap: virtual address 0x%lx not found in %d\n", m->VMUM_ADDR, vmp->vm_endpoint); return -EFAULT; } len = m->VMUM_LEN; if (len % VM_PAGE_SIZE) len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE); if (addr != vr->vaddr || len > vr->length || len < VM_PAGE_SIZE) { return -EFAULT; } if (map_unmap_region(vmp, vr, len) != 0) vm_panic("do_munmap: map_unmap_region failed", NO_NUM); return 0; }
/*===========================================================================* * do_rs_memctl * *===========================================================================*/ int do_rs_memctl(message *m_ptr) { endpoint_t ep; int req, r, proc_nr; struct vmproc *vmp; ep = m_ptr->VM_RS_CTL_ENDPT; req = m_ptr->VM_RS_CTL_REQ; /* Lookup endpoint. */ if ((r = vm_isokendpt(ep, &proc_nr)) != OK) { printf("do_rs_memctl: bad endpoint %d\n", ep); return EINVAL; } vmp = &vmproc[proc_nr]; /* Process request. */ switch(req) { case VM_RS_MEM_PIN: /* Do not perform VM_RS_MEM_PIN yet - it costs the full * size of the RS stack (64MB by default) in memory, * and it's needed for functionality that isn't complete / * merged in current Minix (surviving VM crashes). */ #if 0 r = map_pin_memory(vmp); return r; #else return OK; #endif case VM_RS_MEM_MAKE_VM: r = rs_memctl_make_vm_instance(vmp); return r; default: printf("do_rs_memctl: bad request %d\n", req); return EINVAL; } }
/*===========================================================================* * do_rs_memctl * *===========================================================================*/ int do_rs_memctl(message *m_ptr) { endpoint_t ep; int req, r, proc_nr; struct vmproc *vmp; ep = m_ptr->VM_RS_CTL_ENDPT; req = m_ptr->VM_RS_CTL_REQ; /* Lookup endpoint. */ if ((r = vm_isokendpt(ep, &proc_nr)) != OK) { printf("do_rs_memctl: bad endpoint %d\n", ep); return EINVAL; } vmp = &vmproc[proc_nr]; /* Process request. */ switch(req) { case VM_RS_MEM_PIN: /* Only actually pin RS memory if VM can recover from crashes (saves memory). */ if (num_vm_instances <= 1) return OK; r = map_pin_memory(vmp); return r; case VM_RS_MEM_MAKE_VM: r = rs_memctl_make_vm_instance(vmp); return r; case VM_RS_MEM_HEAP_PREALLOC: r = rs_memctl_heap_prealloc(vmp, (vir_bytes*) &m_ptr->VM_RS_CTL_ADDR, (size_t*) &m_ptr->VM_RS_CTL_LEN); return r; case VM_RS_MEM_MAP_PREALLOC: r = rs_memctl_map_prealloc(vmp, (vir_bytes*) &m_ptr->VM_RS_CTL_ADDR, (size_t*) &m_ptr->VM_RS_CTL_LEN); return r; case VM_RS_MEM_GET_PREALLOC_MAP: r = rs_memctl_get_prealloc_map(vmp, (vir_bytes*) &m_ptr->VM_RS_CTL_ADDR, (size_t*) &m_ptr->VM_RS_CTL_LEN); return r; default: printf("do_rs_memctl: bad request %d\n", req); return EINVAL; } }
/*===========================================================================* * do_get_refcount * *===========================================================================*/ int do_get_refcount(message *m) { int r, n; struct vmproc *vmp; endpoint_t target; u8_t cnt; vir_bytes addr; target = m->m_lsys_vm_getref.endpt; addr = (vir_bytes) m->m_lsys_vm_getref.addr; if ((r = vm_isokendpt(target, &n)) != OK) return EINVAL; vmp = &vmproc[n]; r = map_get_ref(vmp, addr, &cnt); m->m_lsys_vm_getref.retc = cnt; return r; }
/*===========================================================================* * do_get_phys * *===========================================================================*/ int do_get_phys(message *m) { int r, n; struct vmproc *vmp; endpoint_t target; phys_bytes ret; vir_bytes addr; target = m->m_lc_vm_getphys.endpt; addr = (vir_bytes) m->m_lc_vm_getphys.addr; if ((r = vm_isokendpt(target, &n)) != OK) return EINVAL; vmp = &vmproc[n]; r = map_get_phys(vmp, addr, &ret); m->m_lc_vm_getphys.ret_addr = (void *) ret; return r; }
/*===========================================================================* * do_get_refcount * *===========================================================================*/ int do_get_refcount(message *m) { int r, n; struct vmproc *vmp; endpoint_t target; u8_t cnt; vir_bytes addr; target = m->VMREFCNT_ENDPT; addr = m->VMREFCNT_ADDR; if ((r = vm_isokendpt(target, &n)) != OK) return EINVAL; vmp = &vmproc[n]; r = map_get_ref(vmp, addr, &cnt); m->VMREFCNT_RETC = cnt; return r; }