xref: /minix3/minix/lib/libsys/sef.c (revision 0b98e8aad89f2bd4ba80b523d73cf29e9dd82ce1)
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     clock_t uptime;
306     sys_times(SELF, NULL, NULL, &uptime, NULL);
307     return (int) uptime;
308 }
309 
310 /*===========================================================================*
311  *      	                  sef_exit                                   *
312  *===========================================================================*/
313 void sef_exit(int status)
314 {
315 /* System services use a special version of exit() that generates a
316  * self-termination signal.
317  */
318 
319   /* Ask the kernel to exit. */
320   sys_exit();
321 
322   /* If everything else fails, hang. */
323   printf("Warning: system service %d couldn't exit\n", sef_self_endpoint);
324   for(;;) { }
325 }
326 
327 #ifdef __weak_alias
328 __weak_alias(_exit, sef_exit);
329 __weak_alias(__exit, sef_exit);
330 #endif
331 
332 /*===========================================================================*
333  *                                sef_munmap                                 *
334  *===========================================================================*/
335 int sef_munmap(void *addrstart, vir_bytes len, int type)
336 {
337 /* System services use a special version of munmap() to control implicit
338  * munmaps as startup and allow for asynchronous mnmap for VM.
339  */
340   message m;
341   m.m_type = type;
342   m.VMUM_ADDR = addrstart;
343   m.VMUM_LEN = len;
344   if(sef_self_endpoint == VM_PROC_NR) {
345       return asynsend3(SELF, &m, AMF_NOREPLY);
346   }
347   return _syscall(VM_PROC_NR, type, &m);
348 }
349 
350 #if SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG
351 /*===========================================================================*
352  *                         sef_debug_refresh_params              	     *
353  *===========================================================================*/
354 static void sef_debug_refresh_params(void)
355 {
356 /* Refresh SEF debug params. */
357   clock_t uptime;
358 
359   /* Get boottime and system hz the first time. */
360   if(!sef_debug_init) {
361       if (sys_times(NONE, NULL, NULL, NULL, &sef_debug_boottime) != OK)
362 	  sef_debug_init = -1;
363       else if (sys_getinfo(GET_HZ, &sef_debug_system_hz,
364         sizeof(sef_debug_system_hz), 0, 0) != OK)
365 	  sef_debug_init = -1;
366       else
367 	  sef_debug_init = 1;
368   }
369 
370   /* Get uptime. */
371   uptime = -1;
372   if (sef_debug_init < 1 || sys_times(NONE, NULL, NULL, &uptime, NULL) != OK) {
373       sef_debug_time_sec = 0;
374       sef_debug_time_us = 0;
375   }
376   else {
377       /* Compute current time. */
378       sef_debug_time_sec = (time_t) (sef_debug_boottime
379           + (uptime/sef_debug_system_hz));
380       sef_debug_time_us = (uptime%sef_debug_system_hz)
381           * 1000000/sef_debug_system_hz;
382   }
383 }
384 
385 /*===========================================================================*
386  *                              sef_debug_header              		     *
387  *===========================================================================*/
388 char* sef_debug_header(void)
389 {
390 /* Build and return a SEF debug header. */
391   sef_debug_refresh_params();
392   snprintf(sef_debug_header_buff, sizeof(sef_debug_header_buff),
393       "%s: time = %ds %06dus", sef_self_name, (int) sef_debug_time_sec,
394       (int) sef_debug_time_us);
395 
396   return sef_debug_header_buff;
397 }
398 #endif /*SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG*/
399 
400