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