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