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 info.prepare_state = m_ptr->m_rs_init.prepare_state; 211 212 /* Peform initialization. */ 213 r = process_init(type, &info); 214 215 return r; 216 } 217 218 /*===========================================================================* 219 * sef_setcb_init_fresh * 220 *===========================================================================*/ 221 void sef_setcb_init_fresh(sef_cb_init_t cb) 222 { 223 assert(cb != NULL); 224 sef_init_cbs.sef_cb_init_fresh = cb; 225 } 226 227 /*===========================================================================* 228 * sef_setcb_init_lu * 229 *===========================================================================*/ 230 void sef_setcb_init_lu(sef_cb_init_t cb) 231 { 232 assert(cb != NULL); 233 sef_init_cbs.sef_cb_init_lu = cb; 234 } 235 236 /*===========================================================================* 237 * sef_setcb_init_restart * 238 *===========================================================================*/ 239 void sef_setcb_init_restart(sef_cb_init_t cb) 240 { 241 assert(cb != NULL); 242 sef_init_cbs.sef_cb_init_restart = cb; 243 } 244 245 /*===========================================================================* 246 * sef_setcb_init_response * 247 *===========================================================================*/ 248 void sef_setcb_init_response(sef_cb_init_response_t cb) 249 { 250 assert(cb != NULL); 251 sef_init_cbs.sef_cb_init_response = cb; 252 } 253 254 /*===========================================================================* 255 * sef_cb_init_null * 256 *===========================================================================*/ 257 int sef_cb_init_null(int UNUSED(type), 258 sef_init_info_t *UNUSED(info)) 259 { 260 return OK; 261 } 262 263 /*===========================================================================* 264 * sef_cb_init_response_null * 265 *===========================================================================*/ 266 int sef_cb_init_response_null(message * UNUSED(m_ptr)) 267 { 268 return ENOSYS; 269 } 270 271 /*===========================================================================* 272 * sef_cb_init_fail * 273 *===========================================================================*/ 274 int sef_cb_init_fail(int UNUSED(type), sef_init_info_t *UNUSED(info)) 275 { 276 return ENOSYS; 277 } 278 279 /*===========================================================================* 280 * sef_cb_init_reset * 281 *===========================================================================*/ 282 int sef_cb_init_reset(int UNUSED(type), sef_init_info_t *UNUSED(info)) 283 { 284 /* Tell RS to reincarnate us, with no old resources, and a new endpoint. */ 285 return ERESTART; 286 } 287 288 /*===========================================================================* 289 * sef_cb_init_crash * 290 *===========================================================================*/ 291 int sef_cb_init_crash(int UNUSED(type), sef_init_info_t *UNUSED(info)) 292 { 293 panic("Simulating a crash at initialization time...\n"); 294 295 return OK; 296 } 297 298 /*===========================================================================* 299 * sef_cb_init_timeout * 300 *===========================================================================*/ 301 int sef_cb_init_timeout(int UNUSED(type), sef_init_info_t *UNUSED(info)) 302 { 303 message m; 304 int status; 305 306 printf("Simulating a timeout at initialization time...\n"); 307 308 ipc_receive(IDLE, &m, &status); 309 310 return EBADCALL; 311 } 312 313 /*===========================================================================* 314 * sef_cb_init_restart_generic * 315 *===========================================================================*/ 316 int sef_cb_init_restart_generic(int type, sef_init_info_t *info) 317 { 318 /* Always resort to simple identity transfer for self updates. */ 319 if (type == SEF_INIT_LU && (info->flags & SEF_LU_SELF)) 320 return sef_cb_init_identity_state_transfer(type, info); 321 322 /* Can only handle restart otherwise. */ 323 if(type != SEF_INIT_RESTART) { 324 printf("sef_cb_init_restart_generic: init failed\n"); 325 return ENOSYS; 326 } 327 328 /* Perform instrumentation-supported checkpoint-restart. */ 329 return sef_llvm_ltckpt_restart(type, info); 330 } 331 332 /*===========================================================================* 333 * sef_cb_init_identity_state_transfer * 334 *===========================================================================*/ 335 int sef_cb_init_identity_state_transfer(int type, sef_init_info_t *info) 336 { 337 extern char *_brksize; 338 extern char *_etext; 339 int r; 340 char *old_brksize, *new_brksize; 341 char stack_buff[ST_STACK_REFS_BUFF_SIZE]; 342 vir_bytes data_start; 343 size_t size; 344 345 /* Identity state transfer is for crash recovery and self update only. */ 346 if(type != SEF_INIT_RESTART && (type != SEF_INIT_LU || !(info->flags & SEF_LU_SELF))) { 347 printf("sef_cb_init_identity_state_transfer: state transfer failed\n"); 348 return ENOSYS; 349 } 350 351 /* Save stack refs. */ 352 sef_llvm_stack_refs_save(stack_buff); 353 354 old_brksize = _brksize; 355 data_start = (vir_bytes)&_etext; 356 #if SEF_ST_DEBUG 357 printf("sef_cb_init_identity_state_transfer: _brksize = 0x%08x, _etext = 0x%08x, data_start = 0x%08x\n", 358 _brksize, &_etext, data_start); 359 #endif 360 361 /* Transfer data. */ 362 size = (size_t)(_brksize - data_start); 363 364 r = sef_copy_state_region(info, data_start, size, data_start, 365 TRUE /*may_have_holes*/); 366 if (r != OK) 367 return r; 368 369 new_brksize = _brksize; 370 371 /* Transfer heap if necessary. */ 372 if(sef_self_endpoint != VM_PROC_NR && old_brksize != new_brksize) { 373 374 #if SEF_ST_DEBUG 375 printf("sef_cb_init_identity_state_transfer: brk() for new_brksize = 0x%08x\n", 376 new_brksize); 377 #endif 378 379 /* Extend heap first. */ 380 _brksize = old_brksize; 381 r = sef_llvm_real_brk(new_brksize); 382 if(r != OK) { 383 printf("sef_cb_init_identity_state_transfer: brk failed\n"); 384 return EFAULT; 385 } 386 387 /* Transfer state on the heap. */ 388 assert(_brksize == new_brksize); 389 size = (size_t)(_brksize - old_brksize); 390 r = sef_copy_state_region(info, (vir_bytes) old_brksize, size, 391 (vir_bytes) old_brksize, FALSE /*may_have_holes*/); 392 if(r != OK) { 393 printf("sef_cb_init_identity_state_transfer: extended heap transfer failed\n"); 394 return r; 395 } 396 } 397 398 /* Restore stack refs. */ 399 sef_llvm_stack_refs_restore(stack_buff); 400 401 return OK; 402 } 403 404 /*===========================================================================* 405 * sef_cb_init_lu_identity_as_restart * 406 *===========================================================================*/ 407 int sef_cb_init_lu_identity_as_restart(int type, sef_init_info_t *info) 408 { 409 /* Can only handle live update. */ 410 if(type != SEF_INIT_LU) { 411 printf("sef_cb_init_lu_identity_as_restart: init failed\n"); 412 return ENOSYS; 413 } 414 415 /* Resort to restart callback only for identity updates, ignore other cases. */ 416 if(SEF_LU_IS_IDENTITY_UPDATE(info->flags)) { 417 if((info->flags & (SEF_INIT_DEFCB|SEF_INIT_SCRIPT_RESTART)) 418 || sef_init_cbs.sef_cb_init_restart == sef_cb_init_reset) { 419 /* Use stateful restart callback when necessary. */ 420 return SEF_CB_INIT_RESTART_STATEFUL(type, info); 421 } 422 return sef_init_cbs.sef_cb_init_restart(type, info); 423 } 424 425 return ENOSYS; 426 } 427 428 /*===========================================================================* 429 * sef_cb_init_lu_generic * 430 *===========================================================================*/ 431 int sef_cb_init_lu_generic(int type, sef_init_info_t *info) 432 { 433 /* Can only handle live update. */ 434 if(type != SEF_INIT_LU) { 435 printf("sef_cb_init_lu_generic: init failed\n"); 436 return ENOSYS; 437 } 438 439 /* Resort to restart callback for identity updates. */ 440 if(SEF_LU_IS_IDENTITY_UPDATE(info->flags)) { 441 return sef_cb_init_lu_identity_as_restart(type, info); 442 } 443 444 /* Perform state transfer updates in all the other cases. */ 445 return sef_st_state_transfer(info); 446 } 447 448 /*===========================================================================* 449 * sef_cb_init_response_rs_reply * 450 *===========================================================================*/ 451 int sef_cb_init_response_rs_reply(message *m_ptr) 452 { 453 int r; 454 455 /* Inform RS that we completed initialization with the given result. */ 456 r = ipc_sendrec(RS_PROC_NR, m_ptr); 457 458 return r; 459 } 460 461 /*===========================================================================* 462 * sef_cb_init_response_rs_asyn_once * 463 *===========================================================================*/ 464 int sef_cb_init_response_rs_asyn_once(message *m_ptr) 465 { 466 /* This response function is used by VM to avoid a boot-time deadlock. */ 467 int r; 468 469 /* Inform RS that we completed initialization, asynchronously. */ 470 r = asynsend3(RS_PROC_NR, m_ptr, AMF_NOREPLY); 471 472 /* Use a blocking reply call next time. */ 473 sef_setcb_init_response(SEF_CB_INIT_RESPONSE_DEFAULT); 474 475 return r; 476 } 477