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/safecopies.h> 16 #include <minix/bitmap.h> 17 #include <minix/rs.h> 18 19 #include <sys/mman.h> 20 21 #include <errno.h> 22 #include <string.h> 23 #include <env.h> 24 #include <stdio.h> 25 #include <assert.h> 26 27 #include "glo.h" 28 #include "proto.h" 29 #include "util.h" 30 #include "region.h" 31 32 /*===========================================================================* 33 * do_rs_set_priv * 34 *===========================================================================*/ 35 int do_rs_set_priv(message *m) 36 { 37 int r, n, nr; 38 struct vmproc *vmp; 39 bitchunk_t call_mask[VM_CALL_MASK_SIZE], *call_mask_p; 40 41 nr = m->VM_RS_NR; 42 43 if ((r = vm_isokendpt(nr, &n)) != OK) { 44 printf("do_rs_set_priv: bad endpoint %d\n", nr); 45 return EINVAL; 46 } 47 48 vmp = &vmproc[n]; 49 50 if (m->VM_RS_BUF) { 51 r = sys_datacopy(m->m_source, (vir_bytes) m->VM_RS_BUF, SELF, 52 (vir_bytes) call_mask, sizeof(call_mask)); 53 if (r != OK) 54 return r; 55 call_mask_p = call_mask; 56 } else { 57 if (m->VM_RS_SYS) { 58 printf("VM: do_rs_set_priv: sys procs don't share!\n"); 59 return EINVAL; 60 } 61 call_mask_p = NULL; 62 } 63 64 acl_set(vmp, call_mask_p, m->VM_RS_SYS); 65 66 return OK; 67 } 68 69 /*===========================================================================* 70 * do_rs_prepare * 71 *===========================================================================*/ 72 int do_rs_prepare(message *m_ptr) 73 { 74 /* Prepare a new instance of a service for an upcoming live-update 75 * switch, based on the old instance of this service. This call is 76 * used only by RS and only for a multicomponent live update which 77 * includes VM. In this case, all processes need to be prepared such 78 * that they don't require the new VM instance to perform actions 79 * during live update that cannot be undone in the case of a rollback. 80 */ 81 endpoint_t src_e, dst_e; 82 int src_p, dst_p; 83 struct vmproc *src_vmp, *dst_vmp; 84 struct vir_region *src_data_vr, *dst_data_vr; 85 vir_bytes src_addr, dst_addr; 86 int sys_upd_flags; 87 88 src_e = m_ptr->m_lsys_vm_update.src; 89 dst_e = m_ptr->m_lsys_vm_update.dst; 90 sys_upd_flags = m_ptr->m_lsys_vm_update.flags; 91 92 /* Lookup slots for source and destination process. */ 93 if(vm_isokendpt(src_e, &src_p) != OK) { 94 printf("VM: do_rs_prepare: bad src endpoint %d\n", src_e); 95 return EINVAL; 96 } 97 src_vmp = &vmproc[src_p]; 98 if(vm_isokendpt(dst_e, &dst_p) != OK) { 99 printf("VM: do_rs_prepare: bad dst endpoint %d\n", dst_e); 100 return EINVAL; 101 } 102 dst_vmp = &vmproc[dst_p]; 103 104 /* Pin memory for the source process. */ 105 map_pin_memory(src_vmp); 106 107 /* See if the source process has a larger heap than the destination 108 * process. If so, extend the heap of the destination process to 109 * match the source's. While this may end up wasting quite some 110 * memory, it is absolutely essential that the destination process 111 * does not run out of heap memory during the live update window, 112 * and since most processes will be doing an identity transfer, they 113 * are likely to require as much heap as their previous instances. 114 * Better safe than sorry. TODO: prevent wasting memory somehow; 115 * this seems particularly relevant for RS. 116 */ 117 src_data_vr = region_search(&src_vmp->vm_regions_avl, VM_MMAPBASE, 118 AVL_LESS); 119 assert(src_data_vr); 120 dst_data_vr = region_search(&dst_vmp->vm_regions_avl, VM_MMAPBASE, 121 AVL_LESS); 122 assert(dst_data_vr); 123 124 src_addr = src_data_vr->vaddr + src_data_vr->length; 125 dst_addr = dst_data_vr->vaddr + dst_data_vr->length; 126 if (src_addr > dst_addr) 127 real_brk(dst_vmp, src_addr); 128 129 /* Now also pin memory for the destination process. */ 130 map_pin_memory(dst_vmp); 131 132 /* Finally, map the source process's memory-mapped regions into the 133 * destination process. This needs to happen now, because VM may not 134 * allocate any objects during the live update window, since this 135 * would prevent successful rollback of VM afterwards. The 136 * destination may not actually touch these regions during the live 137 * update window either, because they are mapped copy-on-write and a 138 * pagefault would also cause object allocation. Objects are pages, 139 * slab objects, anything in the new VM instance to which changes are 140 * visible in the old VM basically. 141 */ 142 if (!(sys_upd_flags & SF_VM_NOMMAP)) 143 map_proc_dyn_data(src_vmp, dst_vmp); 144 145 return OK; 146 } 147 148 /*===========================================================================* 149 * do_rs_update * 150 *===========================================================================*/ 151 int do_rs_update(message *m_ptr) 152 { 153 endpoint_t src_e, dst_e, reply_e; 154 int src_p, dst_p; 155 struct vmproc *src_vmp, *dst_vmp; 156 int r, sys_upd_flags; 157 158 src_e = m_ptr->m_lsys_vm_update.src; 159 dst_e = m_ptr->m_lsys_vm_update.dst; 160 sys_upd_flags = m_ptr->m_lsys_vm_update.flags; 161 reply_e = m_ptr->m_source; 162 163 /* Lookup slots for source and destination process. */ 164 if(vm_isokendpt(src_e, &src_p) != OK) { 165 printf("do_rs_update: bad src endpoint %d\n", src_e); 166 return EINVAL; 167 } 168 src_vmp = &vmproc[src_p]; 169 if(vm_isokendpt(dst_e, &dst_p) != OK) { 170 printf("do_rs_update: bad dst endpoint %d\n", dst_e); 171 return EINVAL; 172 } 173 dst_vmp = &vmproc[dst_p]; 174 175 /* Check flags. */ 176 if((sys_upd_flags & (SF_VM_ROLLBACK|SF_VM_NOMMAP)) == 0) { 177 /* Can't preallocate when transfering mmapped regions. */ 178 if(map_region_lookup_type(dst_vmp, VR_PREALLOC_MAP)) { 179 return ENOSYS; 180 } 181 } 182 183 /* Let the kernel do the update first. */ 184 r = sys_update(src_e, dst_e, 185 sys_upd_flags & SF_VM_ROLLBACK ? SYS_UPD_ROLLBACK : 0); 186 if(r != OK) { 187 return r; 188 } 189 190 /* Do the update in VM now. */ 191 r = swap_proc_slot(src_vmp, dst_vmp); 192 if(r != OK) { 193 return r; 194 } 195 r = swap_proc_dyn_data(src_vmp, dst_vmp, sys_upd_flags); 196 if(r != OK) { 197 return r; 198 } 199 pt_bind(&src_vmp->vm_pt, src_vmp); 200 pt_bind(&dst_vmp->vm_pt, dst_vmp); 201 202 /* Reply in case of external request, update-aware. */ 203 if(reply_e != VM_PROC_NR) { 204 if(reply_e == src_e) reply_e = dst_e; 205 else if(reply_e == dst_e) reply_e = src_e; 206 m_ptr->m_type = OK; 207 r = ipc_send(reply_e, m_ptr); 208 if(r != OK) { 209 panic("ipc_send() error"); 210 } 211 } 212 213 return SUSPEND; 214 } 215 216 /*===========================================================================* 217 * rs_memctl_make_vm_instance * 218 *===========================================================================*/ 219 static int rs_memctl_make_vm_instance(struct vmproc *new_vm_vmp) 220 { 221 int r; 222 u32_t flags; 223 int verify; 224 struct vmproc *this_vm_vmp; 225 226 this_vm_vmp = &vmproc[VM_PROC_NR]; 227 228 pt_assert(&this_vm_vmp->vm_pt); 229 230 /* Check if the operation is allowed. */ 231 assert(num_vm_instances == 1 || num_vm_instances == 2); 232 if(num_vm_instances == 2) { 233 printf("VM can currently support no more than 2 VM instances at the time."); 234 return EPERM; 235 } 236 237 /* Copy settings from current VM. */ 238 new_vm_vmp->vm_flags |= VMF_VM_INSTANCE; 239 num_vm_instances++; 240 241 /* Pin memory for the new VM instance. */ 242 r = map_pin_memory(new_vm_vmp); 243 if(r != OK) { 244 return r; 245 } 246 247 /* Preallocate page tables for the entire address space for both 248 * VM and the new VM instance. 249 */ 250 flags = 0; 251 verify = FALSE; 252 r = pt_ptalloc_in_range(&this_vm_vmp->vm_pt, 253 VM_OWN_HEAPBASE, VM_DATATOP, flags, verify); 254 if(r != OK) { 255 return r; 256 } 257 r = pt_ptalloc_in_range(&new_vm_vmp->vm_pt, 258 VM_OWN_HEAPBASE, VM_DATATOP, flags, verify); 259 if(r != OK) { 260 return r; 261 } 262 263 /* Let the new VM instance map VM's page tables and its own. */ 264 r = pt_ptmap(this_vm_vmp, new_vm_vmp); 265 if(r != OK) { 266 return r; 267 } 268 r = pt_ptmap(new_vm_vmp, new_vm_vmp); 269 if(r != OK) { 270 return r; 271 } 272 273 pt_assert(&this_vm_vmp->vm_pt); 274 pt_assert(&new_vm_vmp->vm_pt); 275 276 return OK; 277 } 278 279 /*===========================================================================* 280 * rs_memctl_heap_prealloc * 281 *===========================================================================*/ 282 static int rs_memctl_heap_prealloc(struct vmproc *vmp, 283 vir_bytes *addr, size_t *len) 284 { 285 struct vir_region *data_vr; 286 vir_bytes bytes; 287 288 if(*len <= 0) { 289 return EINVAL; 290 } 291 data_vr = region_search(&vmp->vm_regions_avl, VM_MMAPBASE, AVL_LESS); 292 *addr = data_vr->vaddr + data_vr->length; 293 bytes = *addr + *len; 294 295 return real_brk(vmp, bytes); 296 } 297 298 /*===========================================================================* 299 * rs_memctl_map_prealloc * 300 *===========================================================================*/ 301 static int rs_memctl_map_prealloc(struct vmproc *vmp, 302 vir_bytes *addr, size_t *len) 303 { 304 struct vir_region *vr; 305 vir_bytes base, top; 306 int is_vm; 307 308 if(*len <= 0) { 309 return EINVAL; 310 } 311 *len = CLICK_CEIL(*len); 312 313 is_vm = (vmp->vm_endpoint == VM_PROC_NR); 314 base = is_vm ? VM_OWN_MMAPBASE : VM_MMAPBASE; 315 top = is_vm ? VM_OWN_MMAPTOP : VM_MMAPTOP; 316 317 if (!(vr = map_page_region(vmp, base, top, *len, 318 VR_ANON|VR_WRITABLE|VR_UNINITIALIZED, MF_PREALLOC, 319 &mem_type_anon))) { 320 return ENOMEM; 321 } 322 vr->flags |= VR_PREALLOC_MAP; 323 *addr = vr->vaddr; 324 return OK; 325 } 326 327 /*===========================================================================* 328 * rs_memctl_get_prealloc_map * 329 *===========================================================================*/ 330 static int rs_memctl_get_prealloc_map(struct vmproc *vmp, 331 vir_bytes *addr, size_t *len) 332 { 333 struct vir_region *vr; 334 335 vr = map_region_lookup_type(vmp, VR_PREALLOC_MAP); 336 if(!vr) { 337 *addr = 0; 338 *len = 0; 339 } 340 else { 341 *addr = vr->vaddr; 342 *len = vr->length; 343 } 344 return OK; 345 } 346 347 /*===========================================================================* 348 * do_rs_memctl * 349 *===========================================================================*/ 350 int do_rs_memctl(message *m_ptr) 351 { 352 endpoint_t ep; 353 int req, r, proc_nr; 354 struct vmproc *vmp; 355 356 ep = m_ptr->VM_RS_CTL_ENDPT; 357 req = m_ptr->VM_RS_CTL_REQ; 358 359 /* Lookup endpoint. */ 360 if ((r = vm_isokendpt(ep, &proc_nr)) != OK) { 361 printf("do_rs_memctl: bad endpoint %d\n", ep); 362 return EINVAL; 363 } 364 vmp = &vmproc[proc_nr]; 365 366 /* Process request. */ 367 switch(req) 368 { 369 case VM_RS_MEM_PIN: 370 /* Only actually pin RS memory if VM can recover from crashes (saves memory). */ 371 if (num_vm_instances <= 1) 372 return OK; 373 r = map_pin_memory(vmp); 374 return r; 375 case VM_RS_MEM_MAKE_VM: 376 r = rs_memctl_make_vm_instance(vmp); 377 return r; 378 case VM_RS_MEM_HEAP_PREALLOC: 379 r = rs_memctl_heap_prealloc(vmp, (vir_bytes*) &m_ptr->VM_RS_CTL_ADDR, (size_t*) &m_ptr->VM_RS_CTL_LEN); 380 return r; 381 case VM_RS_MEM_MAP_PREALLOC: 382 r = rs_memctl_map_prealloc(vmp, (vir_bytes*) &m_ptr->VM_RS_CTL_ADDR, (size_t*) &m_ptr->VM_RS_CTL_LEN); 383 return r; 384 case VM_RS_MEM_GET_PREALLOC_MAP: 385 r = rs_memctl_get_prealloc_map(vmp, (vir_bytes*) &m_ptr->VM_RS_CTL_ADDR, (size_t*) &m_ptr->VM_RS_CTL_LEN); 386 return r; 387 default: 388 printf("do_rs_memctl: bad request %d\n", req); 389 return EINVAL; 390 } 391 } 392 393