1433d6423SLionel Sambuc 2433d6423SLionel Sambuc #define _SYSTEM 1 3433d6423SLionel Sambuc 4433d6423SLionel Sambuc #include <minix/callnr.h> 5433d6423SLionel Sambuc #include <minix/com.h> 6433d6423SLionel Sambuc #include <minix/config.h> 7433d6423SLionel Sambuc #include <minix/const.h> 8433d6423SLionel Sambuc #include <minix/ds.h> 9433d6423SLionel Sambuc #include <minix/endpoint.h> 10433d6423SLionel Sambuc #include <minix/minlib.h> 11433d6423SLionel Sambuc #include <minix/type.h> 12433d6423SLionel Sambuc #include <minix/ipc.h> 13433d6423SLionel Sambuc #include <minix/sysutil.h> 14433d6423SLionel Sambuc #include <minix/syslib.h> 15433d6423SLionel Sambuc #include <minix/safecopies.h> 16433d6423SLionel Sambuc #include <minix/bitmap.h> 17a1760b57SCristiano Giuffrida #include <minix/rs.h> 18433d6423SLionel Sambuc 1963483e02SCristiano Giuffrida #include <sys/mman.h> 2063483e02SCristiano Giuffrida 21433d6423SLionel Sambuc #include <errno.h> 22433d6423SLionel Sambuc #include <string.h> 23433d6423SLionel Sambuc #include <env.h> 24433d6423SLionel Sambuc #include <stdio.h> 25433d6423SLionel Sambuc #include <assert.h> 26433d6423SLionel Sambuc 27433d6423SLionel Sambuc #include "glo.h" 28433d6423SLionel Sambuc #include "proto.h" 29433d6423SLionel Sambuc #include "util.h" 30433d6423SLionel Sambuc #include "region.h" 31433d6423SLionel Sambuc 32433d6423SLionel Sambuc /*===========================================================================* 33433d6423SLionel Sambuc * do_rs_set_priv * 34433d6423SLionel Sambuc *===========================================================================*/ 35433d6423SLionel Sambuc int do_rs_set_priv(message *m) 36433d6423SLionel Sambuc { 37433d6423SLionel Sambuc int r, n, nr; 38433d6423SLionel Sambuc struct vmproc *vmp; 39433d6423SLionel Sambuc bitchunk_t call_mask[VM_CALL_MASK_SIZE], *call_mask_p; 40433d6423SLionel Sambuc 41433d6423SLionel Sambuc nr = m->VM_RS_NR; 42433d6423SLionel Sambuc 43433d6423SLionel Sambuc if ((r = vm_isokendpt(nr, &n)) != OK) { 44433d6423SLionel Sambuc printf("do_rs_set_priv: bad endpoint %d\n", nr); 45433d6423SLionel Sambuc return EINVAL; 46433d6423SLionel Sambuc } 47433d6423SLionel Sambuc 48433d6423SLionel Sambuc vmp = &vmproc[n]; 49433d6423SLionel Sambuc 50433d6423SLionel Sambuc if (m->VM_RS_BUF) { 51433d6423SLionel Sambuc r = sys_datacopy(m->m_source, (vir_bytes) m->VM_RS_BUF, SELF, 52433d6423SLionel Sambuc (vir_bytes) call_mask, sizeof(call_mask)); 53433d6423SLionel Sambuc if (r != OK) 54433d6423SLionel Sambuc return r; 55433d6423SLionel Sambuc call_mask_p = call_mask; 56433d6423SLionel Sambuc } else { 57433d6423SLionel Sambuc if (m->VM_RS_SYS) { 58433d6423SLionel Sambuc printf("VM: do_rs_set_priv: sys procs don't share!\n"); 59433d6423SLionel Sambuc return EINVAL; 60433d6423SLionel Sambuc } 61433d6423SLionel Sambuc call_mask_p = NULL; 62433d6423SLionel Sambuc } 63433d6423SLionel Sambuc 64433d6423SLionel Sambuc acl_set(vmp, call_mask_p, m->VM_RS_SYS); 65433d6423SLionel Sambuc 66433d6423SLionel Sambuc return OK; 67433d6423SLionel Sambuc } 68433d6423SLionel Sambuc 69433d6423SLionel Sambuc /*===========================================================================* 70433d6423SLionel Sambuc * do_rs_update * 71433d6423SLionel Sambuc *===========================================================================*/ 72433d6423SLionel Sambuc int do_rs_update(message *m_ptr) 73433d6423SLionel Sambuc { 74433d6423SLionel Sambuc endpoint_t src_e, dst_e, reply_e; 75433d6423SLionel Sambuc int src_p, dst_p; 76433d6423SLionel Sambuc struct vmproc *src_vmp, *dst_vmp; 77a1760b57SCristiano Giuffrida int r, sys_upd_flags; 78433d6423SLionel Sambuc 79433d6423SLionel Sambuc src_e = m_ptr->m_lsys_vm_update.src; 80433d6423SLionel Sambuc dst_e = m_ptr->m_lsys_vm_update.dst; 81a1760b57SCristiano Giuffrida sys_upd_flags = m_ptr->m_lsys_vm_update.flags; 8263483e02SCristiano Giuffrida reply_e = m_ptr->m_source; 83433d6423SLionel Sambuc 84433d6423SLionel Sambuc /* Lookup slots for source and destination process. */ 85433d6423SLionel Sambuc if(vm_isokendpt(src_e, &src_p) != OK) { 86433d6423SLionel Sambuc printf("do_rs_update: bad src endpoint %d\n", src_e); 87433d6423SLionel Sambuc return EINVAL; 88433d6423SLionel Sambuc } 89433d6423SLionel Sambuc src_vmp = &vmproc[src_p]; 90433d6423SLionel Sambuc if(vm_isokendpt(dst_e, &dst_p) != OK) { 91433d6423SLionel Sambuc printf("do_rs_update: bad dst endpoint %d\n", dst_e); 92433d6423SLionel Sambuc return EINVAL; 93433d6423SLionel Sambuc } 94433d6423SLionel Sambuc dst_vmp = &vmproc[dst_p]; 95433d6423SLionel Sambuc 9663483e02SCristiano Giuffrida /* Check flags. */ 9763483e02SCristiano Giuffrida if((sys_upd_flags & (SF_VM_ROLLBACK|SF_VM_NOMMAP)) == 0) { 9863483e02SCristiano Giuffrida /* Can't preallocate when transfering mmapped regions. */ 9963483e02SCristiano Giuffrida if(map_region_lookup_type(dst_vmp, VR_PREALLOC_MAP)) { 10063483e02SCristiano Giuffrida return ENOSYS; 10163483e02SCristiano Giuffrida } 10263483e02SCristiano Giuffrida } 10363483e02SCristiano Giuffrida 104433d6423SLionel Sambuc /* Let the kernel do the update first. */ 105a1760b57SCristiano Giuffrida r = sys_update(src_e, dst_e, 106a1760b57SCristiano Giuffrida sys_upd_flags & SF_VM_ROLLBACK ? SYS_UPD_ROLLBACK : 0); 107433d6423SLionel Sambuc if(r != OK) { 108433d6423SLionel Sambuc return r; 109433d6423SLionel Sambuc } 110433d6423SLionel Sambuc 111433d6423SLionel Sambuc /* Do the update in VM now. */ 112433d6423SLionel Sambuc r = swap_proc_slot(src_vmp, dst_vmp); 113433d6423SLionel Sambuc if(r != OK) { 114433d6423SLionel Sambuc return r; 115433d6423SLionel Sambuc } 11663483e02SCristiano Giuffrida r = swap_proc_dyn_data(src_vmp, dst_vmp, sys_upd_flags); 117433d6423SLionel Sambuc if(r != OK) { 118433d6423SLionel Sambuc return r; 119433d6423SLionel Sambuc } 120433d6423SLionel Sambuc pt_bind(&src_vmp->vm_pt, src_vmp); 121433d6423SLionel Sambuc pt_bind(&dst_vmp->vm_pt, dst_vmp); 122433d6423SLionel Sambuc 12363483e02SCristiano Giuffrida /* Reply in case of external request, update-aware. */ 12463483e02SCristiano Giuffrida if(reply_e != VM_PROC_NR) { 125433d6423SLionel Sambuc if(reply_e == src_e) reply_e = dst_e; 126433d6423SLionel Sambuc else if(reply_e == dst_e) reply_e = src_e; 127433d6423SLionel Sambuc m_ptr->m_type = OK; 128433d6423SLionel Sambuc r = ipc_send(reply_e, m_ptr); 129433d6423SLionel Sambuc if(r != OK) { 130433d6423SLionel Sambuc panic("ipc_send() error"); 131433d6423SLionel Sambuc } 13263483e02SCristiano Giuffrida } 133433d6423SLionel Sambuc 134433d6423SLionel Sambuc return SUSPEND; 135433d6423SLionel Sambuc } 136433d6423SLionel Sambuc 137433d6423SLionel Sambuc /*===========================================================================* 138433d6423SLionel Sambuc * rs_memctl_make_vm_instance * 139433d6423SLionel Sambuc *===========================================================================*/ 140433d6423SLionel Sambuc static int rs_memctl_make_vm_instance(struct vmproc *new_vm_vmp) 141433d6423SLionel Sambuc { 142433d6423SLionel Sambuc int r; 143433d6423SLionel Sambuc u32_t flags; 144433d6423SLionel Sambuc int verify; 145433d6423SLionel Sambuc struct vmproc *this_vm_vmp; 146433d6423SLionel Sambuc 147433d6423SLionel Sambuc this_vm_vmp = &vmproc[VM_PROC_NR]; 148433d6423SLionel Sambuc 14963483e02SCristiano Giuffrida /* Check if the operation is allowed. */ 15063483e02SCristiano Giuffrida assert(num_vm_instances == 1 || num_vm_instances == 2); 15163483e02SCristiano Giuffrida if(num_vm_instances == 2) { 15263483e02SCristiano Giuffrida printf("VM can currently support no more than 2 VM instances at the time."); 15363483e02SCristiano Giuffrida return EPERM; 15463483e02SCristiano Giuffrida } 15563483e02SCristiano Giuffrida 15663483e02SCristiano Giuffrida /* Copy settings from current VM. */ 15763483e02SCristiano Giuffrida new_vm_vmp->vm_flags |= VMF_VM_INSTANCE; 15863483e02SCristiano Giuffrida num_vm_instances++; 15963483e02SCristiano Giuffrida 160433d6423SLionel Sambuc /* Pin memory for the new VM instance. */ 161433d6423SLionel Sambuc r = map_pin_memory(new_vm_vmp); 162433d6423SLionel Sambuc if(r != OK) { 163433d6423SLionel Sambuc return r; 164433d6423SLionel Sambuc } 165433d6423SLionel Sambuc 166433d6423SLionel Sambuc /* Preallocate page tables for the entire address space for both 167433d6423SLionel Sambuc * VM and the new VM instance. 168433d6423SLionel Sambuc */ 169433d6423SLionel Sambuc flags = 0; 170433d6423SLionel Sambuc verify = FALSE; 171433d6423SLionel Sambuc r = pt_ptalloc_in_range(&this_vm_vmp->vm_pt, 0, 0, flags, verify); 172433d6423SLionel Sambuc if(r != OK) { 173433d6423SLionel Sambuc return r; 174433d6423SLionel Sambuc } 175433d6423SLionel Sambuc r = pt_ptalloc_in_range(&new_vm_vmp->vm_pt, 0, 0, flags, verify); 176433d6423SLionel Sambuc if(r != OK) { 177433d6423SLionel Sambuc return r; 178433d6423SLionel Sambuc } 179433d6423SLionel Sambuc 180433d6423SLionel Sambuc /* Let the new VM instance map VM's page tables and its own. */ 181433d6423SLionel Sambuc r = pt_ptmap(this_vm_vmp, new_vm_vmp); 182433d6423SLionel Sambuc if(r != OK) { 183433d6423SLionel Sambuc return r; 184433d6423SLionel Sambuc } 185433d6423SLionel Sambuc r = pt_ptmap(new_vm_vmp, new_vm_vmp); 186433d6423SLionel Sambuc if(r != OK) { 187433d6423SLionel Sambuc return r; 188433d6423SLionel Sambuc } 189433d6423SLionel Sambuc 190433d6423SLionel Sambuc return OK; 191433d6423SLionel Sambuc } 192433d6423SLionel Sambuc 193433d6423SLionel Sambuc /*===========================================================================* 19448f446ecSCristiano Giuffrida * rs_memctl_heap_prealloc * 19548f446ecSCristiano Giuffrida *===========================================================================*/ 19648f446ecSCristiano Giuffrida static int rs_memctl_heap_prealloc(struct vmproc *vmp, 19748f446ecSCristiano Giuffrida vir_bytes *addr, size_t *len) 19848f446ecSCristiano Giuffrida { 19948f446ecSCristiano Giuffrida 20048f446ecSCristiano Giuffrida /* 20148f446ecSCristiano Giuffrida * XXX: Is this still needed? 20248f446ecSCristiano Giuffrida */ 20348f446ecSCristiano Giuffrida 20448f446ecSCristiano Giuffrida return OK; 20548f446ecSCristiano Giuffrida } 20648f446ecSCristiano Giuffrida 20748f446ecSCristiano Giuffrida /*===========================================================================* 20848f446ecSCristiano Giuffrida * rs_memctl_map_prealloc * 20948f446ecSCristiano Giuffrida *===========================================================================*/ 21048f446ecSCristiano Giuffrida static int rs_memctl_map_prealloc(struct vmproc *vmp, 21148f446ecSCristiano Giuffrida vir_bytes *addr, size_t *len) 21248f446ecSCristiano Giuffrida { 21348f446ecSCristiano Giuffrida struct vir_region *vr; 21463483e02SCristiano Giuffrida vir_bytes base, top; 21563483e02SCristiano Giuffrida int is_vm; 21663483e02SCristiano Giuffrida 21748f446ecSCristiano Giuffrida if(*len <= 0) { 21848f446ecSCristiano Giuffrida return EINVAL; 21948f446ecSCristiano Giuffrida } 22048f446ecSCristiano Giuffrida *len = CLICK_CEIL(*len); 22148f446ecSCristiano Giuffrida 22263483e02SCristiano Giuffrida is_vm = (vmp->vm_endpoint == VM_PROC_NR); 22363483e02SCristiano Giuffrida base = is_vm ? VM_OWN_MMAPBASE : VM_MMAPBASE; 22463483e02SCristiano Giuffrida top = is_vm ? VM_OWN_MMAPTOP : VM_MMAPTOP; 22563483e02SCristiano Giuffrida 22663483e02SCristiano Giuffrida if (!(vr = map_page_region(vmp, base, top, *len, 22763483e02SCristiano Giuffrida VR_ANON|VR_WRITABLE|VR_UNINITIALIZED, MF_PREALLOC, 22863483e02SCristiano Giuffrida &mem_type_anon))) { 22948f446ecSCristiano Giuffrida return ENOMEM; 23048f446ecSCristiano Giuffrida } 23163483e02SCristiano Giuffrida vr->flags |= VR_PREALLOC_MAP; 23263483e02SCristiano Giuffrida *addr = vr->vaddr; 23348f446ecSCristiano Giuffrida return OK; 23448f446ecSCristiano Giuffrida } 23548f446ecSCristiano Giuffrida 23648f446ecSCristiano Giuffrida /*===========================================================================* 23748f446ecSCristiano Giuffrida * rs_memctl_get_prealloc_map * 23848f446ecSCristiano Giuffrida *===========================================================================*/ 23948f446ecSCristiano Giuffrida static int rs_memctl_get_prealloc_map(struct vmproc *vmp, 24048f446ecSCristiano Giuffrida vir_bytes *addr, size_t *len) 24148f446ecSCristiano Giuffrida { 24248f446ecSCristiano Giuffrida struct vir_region *vr; 24348f446ecSCristiano Giuffrida 24463483e02SCristiano Giuffrida vr = map_region_lookup_type(vmp, VR_PREALLOC_MAP); 24548f446ecSCristiano Giuffrida if(!vr) { 24648f446ecSCristiano Giuffrida *addr = 0; 24748f446ecSCristiano Giuffrida *len = 0; 24848f446ecSCristiano Giuffrida } 24948f446ecSCristiano Giuffrida else { 25063483e02SCristiano Giuffrida *addr = vr->vaddr; 25148f446ecSCristiano Giuffrida *len = vr->length; 25248f446ecSCristiano Giuffrida } 25348f446ecSCristiano Giuffrida return OK; 25448f446ecSCristiano Giuffrida } 25548f446ecSCristiano Giuffrida 25648f446ecSCristiano Giuffrida /*===========================================================================* 257433d6423SLionel Sambuc * do_rs_memctl * 258433d6423SLionel Sambuc *===========================================================================*/ 259433d6423SLionel Sambuc int do_rs_memctl(message *m_ptr) 260433d6423SLionel Sambuc { 261433d6423SLionel Sambuc endpoint_t ep; 262433d6423SLionel Sambuc int req, r, proc_nr; 263433d6423SLionel Sambuc struct vmproc *vmp; 264433d6423SLionel Sambuc 265433d6423SLionel Sambuc ep = m_ptr->VM_RS_CTL_ENDPT; 266433d6423SLionel Sambuc req = m_ptr->VM_RS_CTL_REQ; 267433d6423SLionel Sambuc 268433d6423SLionel Sambuc /* Lookup endpoint. */ 269433d6423SLionel Sambuc if ((r = vm_isokendpt(ep, &proc_nr)) != OK) { 270433d6423SLionel Sambuc printf("do_rs_memctl: bad endpoint %d\n", ep); 271433d6423SLionel Sambuc return EINVAL; 272433d6423SLionel Sambuc } 273433d6423SLionel Sambuc vmp = &vmproc[proc_nr]; 274433d6423SLionel Sambuc 275433d6423SLionel Sambuc /* Process request. */ 276433d6423SLionel Sambuc switch(req) 277433d6423SLionel Sambuc { 278433d6423SLionel Sambuc case VM_RS_MEM_PIN: 279*fb6bd596SCristiano Giuffrida /* Only actually pin RS memory if VM can recover from crashes (saves memory). */ 280*fb6bd596SCristiano Giuffrida if (num_vm_instances <= 1) 281*fb6bd596SCristiano Giuffrida return OK; 282433d6423SLionel Sambuc r = map_pin_memory(vmp); 283433d6423SLionel Sambuc return r; 284433d6423SLionel Sambuc case VM_RS_MEM_MAKE_VM: 285433d6423SLionel Sambuc r = rs_memctl_make_vm_instance(vmp); 286433d6423SLionel Sambuc return r; 28748f446ecSCristiano Giuffrida case VM_RS_MEM_HEAP_PREALLOC: 28848f446ecSCristiano Giuffrida r = rs_memctl_heap_prealloc(vmp, (vir_bytes*) &m_ptr->VM_RS_CTL_ADDR, (size_t*) &m_ptr->VM_RS_CTL_LEN); 28948f446ecSCristiano Giuffrida return r; 29048f446ecSCristiano Giuffrida case VM_RS_MEM_MAP_PREALLOC: 29148f446ecSCristiano Giuffrida r = rs_memctl_map_prealloc(vmp, (vir_bytes*) &m_ptr->VM_RS_CTL_ADDR, (size_t*) &m_ptr->VM_RS_CTL_LEN); 29248f446ecSCristiano Giuffrida return r; 29348f446ecSCristiano Giuffrida case VM_RS_MEM_GET_PREALLOC_MAP: 29448f446ecSCristiano Giuffrida r = rs_memctl_get_prealloc_map(vmp, (vir_bytes*) &m_ptr->VM_RS_CTL_ADDR, (size_t*) &m_ptr->VM_RS_CTL_LEN); 29548f446ecSCristiano Giuffrida return r; 296433d6423SLionel Sambuc default: 297433d6423SLionel Sambuc printf("do_rs_memctl: bad request %d\n", req); 298433d6423SLionel Sambuc return EINVAL; 299433d6423SLionel Sambuc } 300433d6423SLionel Sambuc } 301433d6423SLionel Sambuc 302