xref: /minix/minix/lib/libsys/sef_init.c (revision 08cbf5a0)
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