1 #include <assert.h> 2 #include <unistd.h> 3 #include <string.h> 4 5 #include <machine/vmparam.h> 6 7 #include <minix/sysutil.h> 8 9 #include "syslib.h" 10 /* SEF Init callbacks. */ 11 static struct sef_init_cbs { 12 sef_cb_init_t sef_cb_init_fresh; 13 sef_cb_init_t sef_cb_init_lu; 14 sef_cb_init_t sef_cb_init_restart; 15 sef_cb_init_response_t sef_cb_init_response; 16 } sef_init_cbs = { 17 SEF_CB_INIT_FRESH_DEFAULT, 18 SEF_CB_INIT_LU_DEFAULT, 19 SEF_CB_INIT_RESTART_DEFAULT, 20 SEF_CB_INIT_RESPONSE_DEFAULT 21 }; 22 23 /* SEF Init prototypes for sef_startup(). */ 24 int do_sef_rs_init(endpoint_t old_endpoint); 25 int do_sef_init_request(message *m_ptr); 26 27 /* Debug. */ 28 EXTERN char* sef_debug_header(void); 29 30 /* Information about SELF. */ 31 EXTERN endpoint_t sef_self_endpoint; 32 EXTERN endpoint_t sef_self_priv_flags; 33 EXTERN endpoint_t sef_self_init_flags; 34 35 #ifndef ST_STACK_REFS_BUFF_SIZE 36 #define ST_STACK_REFS_BUFF_SIZE 1024 37 #endif 38 39 /*===========================================================================* 40 * process_init * 41 *===========================================================================*/ 42 static int process_init(int type, sef_init_info_t *info) 43 { 44 /* Process initialization. */ 45 int r, result, debug_result_found, is_def_cb; 46 cp_grant_id_t gid; 47 message m; 48 49 /* Debug. */ 50 #if SEF_INIT_DEBUG 51 sef_init_debug_begin(); 52 sef_init_dprint("%s. Got a SEF Init request of type %d, flags 0x%08x, rproctab_gid %d, ep %d, old ep %d, restarts %d. About to init.\n", 53 sef_debug_header(), type, info->flags, info->rproctab_gid, info->endpoint, info->old_endpoint, info->restarts); 54 sef_init_debug_end(); 55 #endif 56 57 /* Clear any IPC filter. */ 58 r = sys_statectl(SYS_STATE_CLEAR_IPC_FILTERS, 0, 0); 59 assert(r == OK); 60 61 /* Create grant for state transfer. */ 62 gid = cpf_grant_direct(sef_self_endpoint, 0, ULONG_MAX, CPF_READ); 63 if(!GRANT_VALID(gid)) { 64 panic("unable to create grant for state transfer"); 65 } 66 if(gid != SEF_STATE_TRANSFER_GID) { 67 panic("bad state transfer gid"); 68 } 69 70 /* If debug init flags are allowed, process them first. */ 71 debug_result_found = 0; 72 if(SEF_INIT_ALLOW_DEBUG_INIT_FLAGS) { 73 int flags = info->flags; 74 if(flags & SEF_INIT_CRASH) { 75 result = sef_cb_init_crash(type, info); 76 debug_result_found = 1; 77 } 78 else if(flags & SEF_INIT_FAIL) { 79 result = sef_cb_init_fail(type, info); 80 debug_result_found = 1; 81 } 82 else if(flags & SEF_INIT_TIMEOUT) { 83 result = sef_cb_init_timeout(type, info); 84 debug_result_found = 1; 85 } 86 } 87 88 if(!debug_result_found) { 89 /* Let the callback code handle the specific initialization type. */ 90 is_def_cb = info->flags & SEF_INIT_DEFCB; 91 switch(type) { 92 case SEF_INIT_FRESH: 93 result = is_def_cb ? SEF_CB_INIT_FRESH_DEFAULT(type, info) 94 : sef_init_cbs.sef_cb_init_fresh(type, info); 95 break; 96 case SEF_INIT_LU: 97 result = is_def_cb ? SEF_CB_INIT_LU_DEFAULT(type, info) 98 : sef_init_cbs.sef_cb_init_lu(type, info); 99 break; 100 case SEF_INIT_RESTART: 101 result = is_def_cb ? SEF_CB_INIT_RESTART_DEFAULT(type, info) 102 : sef_init_cbs.sef_cb_init_restart(type, info); 103 break; 104 105 default: 106 /* Not a valid SEF init type. */ 107 result = EINVAL; 108 break; 109 } 110 } 111 112 memset(&m, 0, sizeof(m)); 113 m.m_source = sef_self_endpoint; 114 m.m_type = RS_INIT; 115 m.m_rs_init.result = result; 116 r = sef_init_cbs.sef_cb_init_response(&m); 117 if (r != OK) { 118 return r; 119 } 120 121 /* See if we need to unmap the initialization buffer. */ 122 if(info->init_buff_cleanup_start) { 123 void *addrstart = info->init_buff_cleanup_start; 124 size_t len = info->init_buff_len - (size_t)((char*)info->init_buff_cleanup_start - (char*)info->init_buff_start); 125 r = sef_munmap(addrstart, len, VM_MUNMAP); 126 if(r != OK) { 127 printf("process_init: warning: munmap failed for init buffer\n"); 128 } 129 } 130 131 /* Tell the kernel about the grant table. */ 132 cpf_reload(); 133 134 /* Tell the kernel about the senda table. */ 135 r = senda_reload(); 136 if(r != OK) { 137 printf("process_init: warning: senda_reload failed\n"); 138 } 139 140 /* Tell the kernel about the state table. */ 141 sys_statectl(SYS_STATE_SET_STATE_TABLE, sef_llvm_state_table_addr(), 0); 142 143 return r; 144 } 145 146 /*===========================================================================* 147 * do_sef_rs_init * 148 *===========================================================================*/ 149 int do_sef_rs_init(endpoint_t old_endpoint) 150 { 151 /* Special SEF Init for RS. */ 152 int r; 153 int type; 154 sef_init_info_t info; 155 memset(&info, 0, sizeof(info)); 156 157 /* Get init parameters from SEF. */ 158 type = SEF_INIT_FRESH; 159 if(sef_self_priv_flags & LU_SYS_PROC) { 160 type = SEF_INIT_LU; 161 } 162 else if(sef_self_priv_flags & RST_SYS_PROC) { 163 type = SEF_INIT_RESTART; 164 } 165 info.flags = sef_self_init_flags; 166 info.rproctab_gid = GRANT_INVALID; 167 info.endpoint = sef_self_endpoint; 168 info.old_endpoint = old_endpoint; 169 info.restarts = 0; 170 171 /* Get init buffer details from VM. */ 172 info.init_buff_start = NULL; 173 info.init_buff_len = 0; 174 if(type != SEF_INIT_FRESH) { 175 r = vm_memctl(RS_PROC_NR, VM_RS_MEM_GET_PREALLOC_MAP, 176 &info.init_buff_start, &info.init_buff_len); 177 if(r != OK) { 178 printf("do_sef_rs_init: vm_memctl failed\n"); 179 } 180 } 181 info.init_buff_cleanup_start = info.init_buff_start; 182 183 /* Peform initialization. */ 184 r = process_init(type, &info); 185 186 return r; 187 } 188 189 /*===========================================================================* 190 * do_sef_init_request * 191 *===========================================================================*/ 192 int do_sef_init_request(message *m_ptr) 193 { 194 /* Handle a SEF Init request. */ 195 int r; 196 int type; 197 sef_init_info_t info; 198 memset(&info, 0, sizeof(info)); 199 200 /* Get init parameters from message. */ 201 type = m_ptr->m_rs_init.type; 202 info.flags = m_ptr->m_rs_init.flags; 203 info.rproctab_gid = m_ptr->m_rs_init.rproctab_gid; 204 info.endpoint = sef_self_endpoint; 205 info.old_endpoint = m_ptr->m_rs_init.old_endpoint; 206 info.restarts = m_ptr->m_rs_init.restarts; 207 info.init_buff_start = (void*) m_ptr->m_rs_init.buff_addr; 208 info.init_buff_cleanup_start = info.init_buff_start; 209 info.init_buff_len = m_ptr->m_rs_init.buff_len; 210 211 /* Peform initialization. */ 212 r = process_init(type, &info); 213 214 return r; 215 } 216 217 /*===========================================================================* 218 * sef_setcb_init_fresh * 219 *===========================================================================*/ 220 void sef_setcb_init_fresh(sef_cb_init_t cb) 221 { 222 assert(cb != NULL); 223 sef_init_cbs.sef_cb_init_fresh = cb; 224 } 225 226 /*===========================================================================* 227 * sef_setcb_init_lu * 228 *===========================================================================*/ 229 void sef_setcb_init_lu(sef_cb_init_t cb) 230 { 231 assert(cb != NULL); 232 sef_init_cbs.sef_cb_init_lu = cb; 233 } 234 235 /*===========================================================================* 236 * sef_setcb_init_restart * 237 *===========================================================================*/ 238 void sef_setcb_init_restart(sef_cb_init_t cb) 239 { 240 assert(cb != NULL); 241 sef_init_cbs.sef_cb_init_restart = cb; 242 } 243 244 /*===========================================================================* 245 * sef_setcb_init_response * 246 *===========================================================================*/ 247 void sef_setcb_init_response(sef_cb_init_response_t cb) 248 { 249 assert(cb != NULL); 250 sef_init_cbs.sef_cb_init_response = cb; 251 } 252 253 /*===========================================================================* 254 * sef_cb_init_null * 255 *===========================================================================*/ 256 int sef_cb_init_null(int UNUSED(type), 257 sef_init_info_t *UNUSED(info)) 258 { 259 return OK; 260 } 261 262 /*===========================================================================* 263 * sef_cb_init_response_null * 264 *===========================================================================*/ 265 int sef_cb_init_response_null(message * UNUSED(m_ptr)) 266 { 267 return ENOSYS; 268 } 269 270 /*===========================================================================* 271 * sef_cb_init_fail * 272 *===========================================================================*/ 273 int sef_cb_init_fail(int UNUSED(type), sef_init_info_t *UNUSED(info)) 274 { 275 return ENOSYS; 276 } 277 278 /*===========================================================================* 279 * sef_cb_init_reset * 280 *===========================================================================*/ 281 int sef_cb_init_reset(int UNUSED(type), sef_init_info_t *UNUSED(info)) 282 { 283 /* Tell RS to reincarnate us, with no old resources, and a new endpoint. */ 284 return ERESTART; 285 } 286 287 /*===========================================================================* 288 * sef_cb_init_crash * 289 *===========================================================================*/ 290 int sef_cb_init_crash(int UNUSED(type), sef_init_info_t *UNUSED(info)) 291 { 292 panic("Simulating a crash at initialization time...\n"); 293 294 return OK; 295 } 296 297 /*===========================================================================* 298 * sef_cb_init_timeout * 299 *===========================================================================*/ 300 int sef_cb_init_timeout(int UNUSED(type), sef_init_info_t *UNUSED(info)) 301 { 302 message m; 303 int status; 304 305 printf("Simulating a timeout at initialization time...\n"); 306 307 ipc_receive(IDLE, &m, &status); 308 309 return EBADCALL; 310 } 311 312 /*===========================================================================* 313 * sef_cb_init_restart_generic * 314 *===========================================================================*/ 315 int sef_cb_init_restart_generic(int type, sef_init_info_t *info) 316 { 317 /* Always resort to simple identity transfer for self updates. */ 318 if (type == SEF_INIT_LU && (info->flags & SEF_LU_SELF)) 319 return sef_cb_init_identity_state_transfer(type, info); 320 321 /* Can only handle restart otherwise. */ 322 if(type != SEF_INIT_RESTART) { 323 printf("sef_cb_init_restart_generic: init failed\n"); 324 return ENOSYS; 325 } 326 327 /* Perform instrumentation-supported checkpoint-restart. */ 328 return sef_llvm_ltckpt_restart(type, info); 329 } 330 331 /*===========================================================================* 332 * sef_cb_init_identity_state_transfer * 333 *===========================================================================*/ 334 int sef_cb_init_identity_state_transfer(int type, sef_init_info_t *info) 335 { 336 extern char *_brksize; 337 extern char *_etext; 338 int r; 339 char *old_brksize, *new_brksize; 340 char stack_buff[ST_STACK_REFS_BUFF_SIZE]; 341 vir_bytes data_start; 342 size_t size; 343 344 /* Identity state transfer is for crash recovery and self update only. */ 345 if(type != SEF_INIT_RESTART && (type != SEF_INIT_LU || !(info->flags & SEF_LU_SELF))) { 346 printf("sef_cb_init_identity_state_transfer: state transfer failed\n"); 347 return ENOSYS; 348 } 349 350 /* Save stack refs. */ 351 sef_llvm_stack_refs_save(stack_buff); 352 353 old_brksize = _brksize; 354 data_start = (vir_bytes)&_etext; 355 #if SEF_ST_DEBUG 356 printf("sef_cb_init_identity_state_transfer: _brksize = 0x%08x, _etext = 0x%08x, data_start = 0x%08x\n", 357 _brksize, &_etext, data_start); 358 #endif 359 360 /* Transfer data. */ 361 size = (size_t)(_brksize - data_start); 362 363 r = sef_copy_state_region(info, data_start, size, data_start, 364 TRUE /*may_have_holes*/); 365 if (r != OK) 366 return r; 367 368 new_brksize = _brksize; 369 370 /* Transfer heap if necessary. */ 371 if(sef_self_endpoint != VM_PROC_NR && old_brksize != new_brksize) { 372 373 #if SEF_ST_DEBUG 374 printf("sef_cb_init_identity_state_transfer: brk() for new_brksize = 0x%08x\n", 375 new_brksize); 376 #endif 377 378 /* Extend heap first. */ 379 _brksize = old_brksize; 380 r = sef_llvm_real_brk(new_brksize); 381 if(r != OK) { 382 printf("sef_cb_init_identity_state_transfer: brk failed\n"); 383 return EFAULT; 384 } 385 386 /* Transfer state on the heap. */ 387 assert(_brksize == new_brksize); 388 size = (size_t)(_brksize - old_brksize); 389 r = sef_copy_state_region(info, (vir_bytes) old_brksize, size, 390 (vir_bytes) old_brksize, FALSE /*may_have_holes*/); 391 if(r != OK) { 392 printf("sef_cb_init_identity_state_transfer: extended heap transfer failed\n"); 393 return r; 394 } 395 } 396 397 /* Restore stack refs. */ 398 sef_llvm_stack_refs_restore(stack_buff); 399 400 return OK; 401 } 402 403 /*===========================================================================* 404 * sef_cb_init_lu_identity_as_restart * 405 *===========================================================================*/ 406 int sef_cb_init_lu_identity_as_restart(int type, sef_init_info_t *info) 407 { 408 /* Can only handle live update. */ 409 if(type != SEF_INIT_LU) { 410 printf("sef_cb_init_lu_identity_as_restart: init failed\n"); 411 return ENOSYS; 412 } 413 414 /* Resort to restart callback only for identity updates, ignore other cases. */ 415 if(SEF_LU_IS_IDENTITY_UPDATE(info->flags)) { 416 if((info->flags & (SEF_INIT_DEFCB|SEF_INIT_SCRIPT_RESTART)) 417 || sef_init_cbs.sef_cb_init_restart == sef_cb_init_reset) { 418 /* Use stateful restart callback when necessary. */ 419 return SEF_CB_INIT_RESTART_STATEFUL(type, info); 420 } 421 return sef_init_cbs.sef_cb_init_restart(type, info); 422 } 423 424 return ENOSYS; 425 } 426 427 /*===========================================================================* 428 * sef_cb_init_lu_generic * 429 *===========================================================================*/ 430 int sef_cb_init_lu_generic(int type, sef_init_info_t *info) 431 { 432 /* Can only handle live update. */ 433 if(type != SEF_INIT_LU) { 434 printf("sef_cb_init_lu_generic: init failed\n"); 435 return ENOSYS; 436 } 437 438 /* Resort to restart callback for identity updates. */ 439 if(SEF_LU_IS_IDENTITY_UPDATE(info->flags)) { 440 return sef_cb_init_lu_identity_as_restart(type, info); 441 } 442 443 /* Perform state transfer updates in all the other cases. */ 444 return sef_st_state_transfer(info); 445 } 446 447 /*===========================================================================* 448 * sef_cb_init_response_rs_reply * 449 *===========================================================================*/ 450 int sef_cb_init_response_rs_reply(message *m_ptr) 451 { 452 int r; 453 454 /* Inform RS that we completed initialization with the given result. */ 455 r = ipc_sendrec(RS_PROC_NR, m_ptr); 456 457 return r; 458 } 459 460 /*===========================================================================* 461 * sef_cb_init_response_rs_asyn_once * 462 *===========================================================================*/ 463 int sef_cb_init_response_rs_asyn_once(message *m_ptr) 464 { 465 /* This response function is used by VM to avoid a boot-time deadlock. */ 466 int r; 467 468 /* Inform RS that we completed initialization, asynchronously. */ 469 r = asynsend3(RS_PROC_NR, m_ptr, AMF_NOREPLY); 470 471 /* Use a blocking reply call next time. */ 472 sef_setcb_init_response(SEF_CB_INIT_RESPONSE_DEFAULT); 473 474 return r; 475 } 476