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