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 *===========================================================================*/
process_init(int type,sef_init_info_t * info)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 *===========================================================================*/
do_sef_rs_init(endpoint_t old_endpoint)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 *===========================================================================*/
do_sef_init_request(message * m_ptr)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 *===========================================================================*/
sef_setcb_init_fresh(sef_cb_init_t cb)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 *===========================================================================*/
sef_setcb_init_lu(sef_cb_init_t cb)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 *===========================================================================*/
sef_setcb_init_restart(sef_cb_init_t cb)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 *===========================================================================*/
sef_setcb_init_response(sef_cb_init_response_t cb)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 *===========================================================================*/
sef_cb_init_null(int UNUSED (type),sef_init_info_t * UNUSED (info))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 *===========================================================================*/
sef_cb_init_response_null(message * UNUSED (m_ptr))267 int sef_cb_init_response_null(message * UNUSED(m_ptr))
268 {
269 return ENOSYS;
270 }
271
272 /*===========================================================================*
273 * sef_cb_init_fail *
274 *===========================================================================*/
sef_cb_init_fail(int UNUSED (type),sef_init_info_t * UNUSED (info))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 *===========================================================================*/
sef_cb_init_reset(int UNUSED (type),sef_init_info_t * UNUSED (info))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 *===========================================================================*/
sef_cb_init_crash(int UNUSED (type),sef_init_info_t * UNUSED (info))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 *===========================================================================*/
sef_cb_init_timeout(int UNUSED (type),sef_init_info_t * UNUSED (info))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 *===========================================================================*/
sef_cb_init_restart_generic(int type,sef_init_info_t * info)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 *===========================================================================*/
sef_cb_init_identity_state_transfer(int type,sef_init_info_t * info)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 *===========================================================================*/
sef_cb_init_lu_identity_as_restart(int type,sef_init_info_t * info)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 *===========================================================================*/
sef_cb_init_lu_generic(int type,sef_init_info_t * info)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 *===========================================================================*/
sef_cb_init_response_rs_reply(message * m_ptr)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 *===========================================================================*/
sef_cb_init_response_rs_asyn_once(message * m_ptr)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