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