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