xref: /minix3/minix/lib/libsys/sef.c (revision 7c48de6cc4c6d56f2277d378dba01dbac8a8c3b9)
1 #include "syslib.h"
2 #include <assert.h>
3 #include <minix/sysutil.h>
4 #include <minix/rs.h>
5 #include <minix/timers.h>
6 #include <minix/endpoint.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 
12 /* Self variables. */
13 #define SEF_SELF_NAME_MAXLEN 20
14 char sef_self_name[SEF_SELF_NAME_MAXLEN];
15 endpoint_t sef_self_endpoint = NONE;
16 endpoint_t sef_self_proc_nr;
17 int sef_self_priv_flags;
18 int sef_self_init_flags;
19 int sef_self_receiving;
20 
21 /* Extern variables. */
22 EXTERN int sef_lu_state;
23 EXTERN int __sef_st_before_receive_enabled;
24 EXTERN __attribute__((weak)) int __vm_init_fresh;
25 
26 /* Debug. */
27 #if SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG
28 #define SEF_DEBUG_HEADER_MAXLEN 50
29 static int sef_debug_init = 0;
30 static time_t sef_debug_boottime = 0;
31 static u32_t sef_debug_system_hz = 0;
32 static time_t sef_debug_time_sec = 0;
33 static time_t sef_debug_time_us = 0;
34 static char sef_debug_header_buff[SEF_DEBUG_HEADER_MAXLEN];
35 static void sef_debug_refresh_params(void);
36 char* sef_debug_header(void);
37 #endif
38 
39 /* SEF Init prototypes. */
40 EXTERN int do_sef_rs_init(endpoint_t old_endpoint);
41 EXTERN int do_sef_init_request(message *m_ptr);
42 
43 /* SEF Ping prototypes. */
44 EXTERN int do_sef_ping_request(message *m_ptr);
45 
46 /* SEF Live update prototypes. */
47 EXTERN void do_sef_lu_before_receive(void);
48 EXTERN int do_sef_lu_request(message *m_ptr);
49 
50 /* SEF Signal prototypes. */
51 EXTERN int do_sef_signal_request(message *m_ptr);
52 
53 /* State transfer prototypes. */
54 EXTERN void do_sef_st_before_receive(void);
55 
56 /* SEF GCOV prototypes. */
57 #ifdef USE_COVERAGE
58 EXTERN int do_sef_gcov_request(message *m_ptr);
59 #endif
60 
61 /* SEF Fault Injection prototypes. */
62 EXTERN int do_sef_fi_request(message *m_ptr);
63 
64 /*===========================================================================*
65  *				sef_startup				     *
66  *===========================================================================*/
67 void sef_startup()
68 {
69 /* SEF startup interface for system services. */
70   int r, status;
71   endpoint_t old_endpoint;
72   int priv_flags;
73   int init_flags;
74   int sys_upd_flags = 0;
75 
76   /* Get information about self. */
77   r = sys_whoami(&sef_self_endpoint, sef_self_name, SEF_SELF_NAME_MAXLEN,
78       &priv_flags, &init_flags);
79   if ( r != OK) {
80       panic("sef_startup: sys_whoami failed: %d\n", r);
81   }
82 
83   sef_self_proc_nr = _ENDPOINT_P(sef_self_endpoint);
84   sef_self_priv_flags = priv_flags;
85   sef_self_init_flags = init_flags;
86   sef_lu_state = SEF_LU_STATE_NULL;
87   old_endpoint = NONE;
88   if(init_flags & SEF_LU_NOMMAP) {
89       sys_upd_flags |= SF_VM_NOMMAP;
90   }
91 
92 #if USE_LIVEUPDATE
93   /* RS may wake up with the wrong endpoint, perfom the update in that case. */
94   if((sef_self_priv_flags & ROOT_SYS_PROC) && sef_self_endpoint != RS_PROC_NR) {
95       r = vm_update(RS_PROC_NR, sef_self_endpoint, sys_upd_flags);
96       if(r != OK) {
97           panic("unable to update RS from instance %d to %d: %d",
98               RS_PROC_NR, sef_self_endpoint, r);
99       }
100       old_endpoint = sef_self_endpoint;
101       sef_self_endpoint = RS_PROC_NR;
102   }
103 #endif /* USE_LIVEUPDATE */
104 
105 #if INTERCEPT_SEF_INIT_REQUESTS
106   /* Intercept SEF Init requests. */
107   if(sef_self_priv_flags & ROOT_SYS_PROC) {
108       /* RS initialization is special. */
109       if((r = do_sef_rs_init(old_endpoint)) != OK) {
110           panic("RS unable to complete init: %d", r);
111       }
112   }
113   else if(sef_self_endpoint == VM_PROC_NR && __vm_init_fresh) {
114       /* VM handles fresh initialization by RS later */
115   } else {
116       message m;
117 
118       /* Wait for an initialization message from RS. We need this to learn the
119        * initialization type and parameters. When restarting after a crash, we
120        * may get some spurious IPC messages from RS (e.g. update request) that
121        * were originally meant to be delivered to the old instance. We discard
122        * these messages and block till a proper initialization request arrives.
123        */
124       do {
125           r = ipc_receive(RS_PROC_NR, &m, &status);
126           if(r != OK) {
127               panic("unable to ipc_receive from RS: %d", r);
128           }
129       } while(!IS_SEF_INIT_REQUEST(&m, status));
130 
131       /* Process initialization request for this system service. */
132       if((r = do_sef_init_request(&m)) != OK) {
133           panic("unable to process init request: %d", r);
134       }
135   }
136 #endif
137 
138   /* (Re)initialize SEF variables. */
139   sef_self_priv_flags = priv_flags;
140   sef_self_init_flags = init_flags;
141   sef_lu_state = SEF_LU_STATE_NULL;
142 }
143 
144 /*===========================================================================*
145  *				sef_receive_status			     *
146  *===========================================================================*/
147 int sef_receive_status(endpoint_t src, message *m_ptr, int *status_ptr)
148 {
149 /* SEF receive() interface for system services. */
150   int r, status, m_type;
151 
152   sef_self_receiving = TRUE;
153 
154   while(TRUE) {
155       /* If the caller indicated that it no longer wants to receive a message,
156        * return now.
157        */
158       if (!sef_self_receiving)
159           return EINTR;
160 
161 #if INTERCEPT_SEF_LU_REQUESTS
162       /* Handle SEF Live update before receive events. */
163       if(sef_lu_state != SEF_LU_STATE_NULL) {
164           do_sef_lu_before_receive();
165       }
166 
167       /* Handle State transfer before receive events. */
168       if(__sef_st_before_receive_enabled) {
169           do_sef_st_before_receive();
170       }
171 #endif
172 
173       /* Receive and return in case of error. */
174       r = ipc_receive(src, m_ptr, &status);
175       if(status_ptr) *status_ptr = status;
176       if(r != OK) {
177           return r;
178       }
179 
180       m_type = m_ptr->m_type;
181       if (is_ipc_notify(status)) {
182           switch (m_ptr->m_source) {
183               case SYSTEM:
184                   m_type = SEF_SIGNAL_REQUEST_TYPE;
185               break;
186               case RS_PROC_NR:
187                   m_type = SEF_PING_REQUEST_TYPE;
188               break;
189           }
190       }
191       switch(m_type) {
192 
193 #if INTERCEPT_SEF_INIT_REQUESTS
194       case SEF_INIT_REQUEST_TYPE:
195           /* Intercept SEF Init requests. */
196           if(IS_SEF_INIT_REQUEST(m_ptr, status)) {
197               /* Ignore spurious init requests. */
198               if (m_ptr->m_rs_init.type != SEF_INIT_FRESH
199                   || sef_self_endpoint != VM_PROC_NR)
200               continue;
201           }
202       break;
203 #endif
204 
205 #if INTERCEPT_SEF_PING_REQUESTS
206       case SEF_PING_REQUEST_TYPE:
207           /* Intercept SEF Ping requests. */
208           if(IS_SEF_PING_REQUEST(m_ptr, status)) {
209               if(do_sef_ping_request(m_ptr) == OK) {
210                   continue;
211               }
212           }
213       break;
214 #endif
215 
216 #if INTERCEPT_SEF_LU_REQUESTS
217       case SEF_LU_REQUEST_TYPE:
218           /* Intercept SEF Live update requests. */
219           if(IS_SEF_LU_REQUEST(m_ptr, status)) {
220               if(do_sef_lu_request(m_ptr) == OK) {
221                   continue;
222               }
223           }
224       break;
225 #endif
226 
227 #if INTERCEPT_SEF_SIGNAL_REQUESTS
228       case SEF_SIGNAL_REQUEST_TYPE:
229           /* Intercept SEF Signal requests. */
230           if(IS_SEF_SIGNAL_REQUEST(m_ptr, status)) {
231               if(do_sef_signal_request(m_ptr) == OK) {
232                   continue;
233               }
234           }
235       break;
236 #endif
237 
238 #if INTERCEPT_SEF_GCOV_REQUESTS && USE_COVERAGE
239       case SEF_GCOV_REQUEST_TYPE:
240           /* Intercept GCOV data requests (sent by VFS in vfs/gcov.c). */
241           if(IS_SEF_GCOV_REQUEST(m_ptr, status)) {
242               if(do_sef_gcov_request(m_ptr) == OK) {
243                   continue;
244               }
245           }
246       break;
247 #endif
248 
249 #if INTERCEPT_SEF_FI_REQUESTS
250       case SEF_FI_REQUEST_TYPE:
251           /* Intercept SEF Fault Injection requests. */
252           if(IS_SEF_FI_REQUEST(m_ptr, status)) {
253               if(do_sef_fi_request(m_ptr) == OK) {
254                   continue;
255               }
256           }
257       break;
258 #endif
259 
260       default:
261       break;
262       }
263 
264       /* If we get this far, this is not a valid SEF request, return and
265        * let the caller deal with that.
266        */
267       break;
268   }
269 
270   return r;
271 }
272 
273 /*===========================================================================*
274  *				sef_self				     *
275  *===========================================================================*/
276 endpoint_t sef_self(void)
277 {
278 /* Return the process's own endpoint number. */
279 
280   if (sef_self_endpoint == NONE)
281 	panic("sef_self called before initialization");
282 
283   return sef_self_endpoint;
284 }
285 
286 /*===========================================================================*
287  *				sef_cancel				     *
288  *===========================================================================*/
289 void sef_cancel(void)
290 {
291 /* Cancel receiving a message. This function be called from a callback invoked
292  * from within sef_receive_status(), which will then return an EINTR error
293  * code. In particular, this function can be used to exit from the main receive
294  * loop when a signal handler causes the process to want to shut down.
295  */
296 
297   sef_self_receiving = FALSE;
298 }
299 
300 /*===========================================================================*
301  *                              sef_getrndseed              		     *
302  *===========================================================================*/
303 int sef_getrndseed(void)
304 {
305     return (int)getticks();
306 }
307 
308 /*===========================================================================*
309  *      	                  sef_exit                                   *
310  *===========================================================================*/
311 void sef_exit(int status)
312 {
313 /* System services use a special version of exit() that generates a
314  * self-termination signal.
315  */
316 
317   /* Ask the kernel to exit. */
318   sys_exit();
319 
320   /* If everything else fails, hang. */
321   printf("Warning: system service %d couldn't exit\n", sef_self_endpoint);
322   for(;;) { }
323 }
324 
325 #ifdef __weak_alias
326 __weak_alias(_exit, sef_exit);
327 __weak_alias(__exit, sef_exit);
328 #endif
329 
330 /*===========================================================================*
331  *                                sef_munmap                                 *
332  *===========================================================================*/
333 int sef_munmap(void *addrstart, vir_bytes len, int type)
334 {
335 /* System services use a special version of munmap() to control implicit
336  * munmaps as startup and allow for asynchronous mnmap for VM.
337  */
338   message m;
339   m.m_type = type;
340   m.VMUM_ADDR = addrstart;
341   m.VMUM_LEN = len;
342   if(sef_self_endpoint == VM_PROC_NR) {
343       return asynsend3(SELF, &m, AMF_NOREPLY);
344   }
345   return _syscall(VM_PROC_NR, type, &m);
346 }
347 
348 #if SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG
349 /*===========================================================================*
350  *                         sef_debug_refresh_params              	     *
351  *===========================================================================*/
352 static void sef_debug_refresh_params(void)
353 {
354 /* Refresh SEF debug params. */
355   clock_t uptime;
356 
357   /* Get boottime and system hz the first time. */
358   if(!sef_debug_init) {
359       if (sys_times(NONE, NULL, NULL, NULL, &sef_debug_boottime) != OK)
360 	  sef_debug_init = -1;
361       else if (sys_getinfo(GET_HZ, &sef_debug_system_hz,
362         sizeof(sef_debug_system_hz), 0, 0) != OK)
363 	  sef_debug_init = -1;
364       else
365 	  sef_debug_init = 1;
366   }
367 
368   /* Get uptime. */
369   uptime = -1;
370   if (sef_debug_init < 1 || sys_times(NONE, NULL, NULL, &uptime, NULL) != OK) {
371       sef_debug_time_sec = 0;
372       sef_debug_time_us = 0;
373   }
374   else {
375       /* Compute current time. */
376       sef_debug_time_sec = (time_t) (sef_debug_boottime
377           + (uptime/sef_debug_system_hz));
378       sef_debug_time_us = (uptime%sef_debug_system_hz)
379           * 1000000/sef_debug_system_hz;
380   }
381 }
382 
383 /*===========================================================================*
384  *                              sef_debug_header              		     *
385  *===========================================================================*/
386 char* sef_debug_header(void)
387 {
388 /* Build and return a SEF debug header. */
389   sef_debug_refresh_params();
390   snprintf(sef_debug_header_buff, sizeof(sef_debug_header_buff),
391       "%s: time = %ds %06dus", sef_self_name, (int) sef_debug_time_sec,
392       (int) sef_debug_time_us);
393 
394   return sef_debug_header_buff;
395 }
396 #endif /*SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG*/
397 
398