1 #include <sys/types.h> 2 #include <time.h> 3 #include <termios.h> 4 #include <signal.h> 5 #include <pwd.h> 6 #include <sched.h> 7 #include <sys/resource.h> 8 #include <sys/wait.h> 9 #include <sys/time.h> 10 11 #include "dat.h" 12 #include "fns.h" 13 #include "error.h" 14 15 /* glibc 2.3.3-NTPL messes up getpid() by trying to cache the result, so we'll do it ourselves */ 16 #include <sys/syscall.h> 17 #define getpid() syscall(SYS_getpid) 18 19 /* temporarily suppress CLONE_PTRACE so it works on broken Linux kernels */ 20 #undef CLONE_PTRACE 21 #define CLONE_PTRACE 0 22 23 enum 24 { 25 DELETE = 0x7f, 26 CTRLC = 'C'-'@', 27 NSTACKSPERALLOC = 16, 28 X11STACK= 256*1024 29 }; 30 char *hosttype = "Linux"; 31 32 static void *stackalloc(Proc *p, void **tos); 33 static void stackfreeandexit(void *stack); 34 35 extern int dflag; 36 37 int gidnobody = -1; 38 int uidnobody = -1; 39 static struct termios tinit; 40 41 void 42 pexit(char *msg, int t) 43 { 44 Osenv *e; 45 void *kstack; 46 47 lock(&procs.l); 48 if(up->prev) 49 up->prev->next = up->next; 50 else 51 procs.head = up->next; 52 53 if(up->next) 54 up->next->prev = up->prev; 55 else 56 procs.tail = up->prev; 57 unlock(&procs.l); 58 59 if(0) 60 print("pexit: %s: %s\n", up->text, msg); 61 62 e = up->env; 63 if(e != nil) { 64 closefgrp(e->fgrp); 65 closepgrp(e->pgrp); 66 closeegrp(e->egrp); 67 closesigs(e->sigs); 68 } 69 kstack = up->kstack; 70 free(up->prog); 71 free(up); 72 if(kstack != nil) 73 stackfreeandexit(kstack); 74 } 75 76 void 77 tramp(void *arg) 78 { 79 Proc *p; 80 p = arg; 81 p->pid = p->sigid = getpid(); 82 (*p->func)(p->arg); 83 pexit("{Tramp}", 0); 84 } 85 86 int 87 kproc(char *name, void (*func)(void*), void *arg, int flags) 88 { 89 int pid; 90 Proc *p; 91 Pgrp *pg; 92 Fgrp *fg; 93 Egrp *eg; 94 void *tos; 95 96 p = newproc(); 97 if(0) 98 print("start %s:%.8lx\n", name, p); 99 if(p == nil) { 100 print("kproc(%s): no memory", name); 101 return; 102 } 103 104 if(flags & KPDUPPG) { 105 pg = up->env->pgrp; 106 incref(&pg->r); 107 p->env->pgrp = pg; 108 } 109 if(flags & KPDUPFDG) { 110 fg = up->env->fgrp; 111 incref(&fg->r); 112 p->env->fgrp = fg; 113 } 114 if(flags & KPDUPENVG) { 115 eg = up->env->egrp; 116 incref(&eg->r); 117 p->env->egrp = eg; 118 } 119 120 p->env->uid = up->env->uid; 121 p->env->gid = up->env->gid; 122 kstrdup(&p->env->user, up->env->user); 123 124 strcpy(p->text, name); 125 126 p->func = func; 127 p->arg = arg; 128 129 if(flags & KPX11){ 130 p->kstack = nil; /* never freed; also up not defined */ 131 tos = (char*)mallocz(X11STACK, 0) + X11STACK - sizeof(void*); 132 }else 133 p->kstack = stackalloc(p, &tos); 134 135 lock(&procs.l); 136 if(procs.tail != nil) { 137 p->prev = procs.tail; 138 procs.tail->next = p; 139 } 140 else { 141 procs.head = p; 142 p->prev = nil; 143 } 144 procs.tail = p; 145 unlock(&procs.l); 146 147 if (__clone(tramp, tos, CLONE_PTRACE|CLONE_VM|CLONE_FS|CLONE_FILES|SIGCHLD, p) <= 0) 148 panic("kproc: clone failed"); 149 150 return 0; 151 } 152 153 /* 154 * TO DO: 155 * To get pc on trap, use sigaction instead of signal and 156 * examine its siginfo structure 157 */ 158 159 /* 160 static void 161 diserr(char *s, int pc) 162 { 163 char buf[ERRMAX]; 164 165 snprint(buf, sizeof(buf), "%s: pc=0x%lux", s, pc); 166 disfault(nil, buf); 167 } 168 */ 169 170 static void 171 trapILL(int signo) 172 { 173 USED(signo); 174 disfault(nil, "Illegal instruction"); 175 } 176 177 static void 178 trapBUS(int signo) 179 { 180 USED(signo); 181 disfault(nil, "Bus error"); 182 } 183 184 static void 185 trapSEGV(int signo) 186 { 187 USED(signo); 188 disfault(nil, "Segmentation violation"); 189 } 190 191 #include <fpuctl.h> 192 static void 193 trapFPE(int signo) 194 { 195 USED(signo); 196 print("FPU status=0x%.4lux", getfsr()); 197 disfault(nil, "Floating exception"); 198 } 199 200 static void 201 trapUSR1(int signo) 202 { 203 int intwait; 204 205 USED(signo); 206 207 intwait = up->intwait; 208 up->intwait = 0; /* clear it to let proc continue in osleave */ 209 210 if(up->type != Interp) /* Used to unblock pending I/O */ 211 return; 212 213 if(intwait == 0) /* Not posted so it's a sync error */ 214 disfault(nil, Eintr); /* Should never happen */ 215 } 216 217 /* called to wake up kproc blocked on a syscall */ 218 void 219 oshostintr(Proc *p) 220 { 221 kill(p->sigid, SIGUSR1); 222 } 223 224 static void 225 trapUSR2(int signo) 226 { 227 USED(signo); 228 /* we've done our work of interrupting sigsuspend */ 229 } 230 231 void 232 osblock(void) 233 { 234 sigset_t mask; 235 236 sigprocmask(SIG_SETMASK, NULL, &mask); 237 sigdelset(&mask, SIGUSR2); 238 sigsuspend(&mask); 239 } 240 241 void 242 osready(Proc *p) 243 { 244 if(kill(p->sigid, SIGUSR2) < 0) 245 fprint(2, "emu: osready failed: pid %d: %s\n", p->sigid, strerror(errno)); 246 } 247 248 void 249 oslongjmp(void *regs, osjmpbuf env, int val) 250 { 251 USED(regs); 252 siglongjmp(env, val); 253 } 254 255 static void 256 termset(void) 257 { 258 struct termios t; 259 260 tcgetattr(0, &t); 261 tinit = t; 262 t.c_lflag &= ~(ICANON|ECHO|ISIG); 263 t.c_cc[VMIN] = 1; 264 t.c_cc[VTIME] = 0; 265 tcsetattr(0, TCSANOW, &t); 266 } 267 268 static void 269 termrestore(void) 270 { 271 tcsetattr(0, TCSANOW, &tinit); 272 } 273 274 void 275 cleanexit(int x) 276 { 277 USED(x); 278 279 if(up->intwait) { 280 up->intwait = 0; 281 return; 282 } 283 284 if(dflag == 0) 285 termrestore(); 286 287 kill(0, SIGKILL); 288 exit(0); 289 } 290 291 void 292 osreboot(char *file, char **argv) 293 { 294 } 295 296 void 297 libinit(char *imod) 298 { 299 struct termios t; 300 struct sigaction act; 301 sigset_t mask; 302 struct passwd *pw; 303 Proc *p; 304 void *tos; 305 char sys[64]; 306 307 setsid(); 308 309 gethostname(sys, sizeof(sys)); 310 kstrdup(&ossysname, sys); 311 pw = getpwnam("nobody"); 312 if(pw != nil) { 313 uidnobody = pw->pw_uid; 314 gidnobody = pw->pw_gid; 315 } 316 317 if(dflag == 0) 318 termset(); 319 320 memset(&act, 0 , sizeof(act)); 321 act.sa_handler = trapUSR1; 322 sigaction(SIGUSR1, &act, nil); 323 324 sigemptyset(&mask); 325 sigaddset(&mask, SIGUSR2); 326 sigprocmask(SIG_BLOCK, &mask, NULL); 327 328 memset(&act, 0 , sizeof(act)); 329 act.sa_handler = trapUSR2; 330 sigaction(SIGUSR2, &act, nil); 331 332 act.sa_handler = SIG_IGN; 333 sigaction(SIGCHLD, &act, nil); 334 335 /* 336 * For the correct functioning of devcmd in the 337 * face of exiting slaves 338 */ 339 signal(SIGPIPE, SIG_IGN); 340 if(signal(SIGTERM, SIG_IGN) != SIG_IGN) 341 signal(SIGTERM, cleanexit); 342 if(signal(SIGINT, SIG_IGN) != SIG_IGN) 343 signal(SIGINT, cleanexit); 344 345 if(sflag == 0) { 346 act.sa_handler = trapBUS; 347 sigaction(SIGBUS, &act, nil); 348 act.sa_handler = trapILL; 349 sigaction(SIGILL, &act, nil); 350 act.sa_handler = trapSEGV; 351 sigaction(SIGSEGV, &act, nil); 352 act.sa_handler = trapFPE; 353 sigaction(SIGFPE, &act, nil); 354 } 355 356 p = newproc(); 357 p->kstack = stackalloc(p, &tos); 358 359 pw = getpwuid(getuid()); 360 if(pw != nil) 361 kstrdup(&eve, pw->pw_name); 362 else 363 print("cannot getpwuid\n"); 364 365 p->env->uid = getuid(); 366 p->env->gid = getgid(); 367 368 executeonnewstack(tos, emuinit, imod); 369 } 370 371 int 372 readkbd(void) 373 { 374 int n; 375 char buf[1]; 376 377 n = read(0, buf, sizeof(buf)); 378 if(n < 0) 379 print("keyboard close (n=%d, %s)\n", n, strerror(errno)); 380 if(n <= 0) 381 pexit("keyboard thread", 0); 382 383 switch(buf[0]) { 384 case '\r': 385 buf[0] = '\n'; 386 break; 387 case DELETE: 388 buf[0] = 'H' - '@'; 389 break; 390 case CTRLC: 391 cleanexit(0); 392 break; 393 } 394 return buf[0]; 395 } 396 397 /* 398 * Return an abitrary millisecond clock time 399 */ 400 long 401 osmillisec(void) 402 { 403 static long sec0 = 0, usec0; 404 struct timeval t; 405 406 if(gettimeofday(&t,(struct timezone*)0)<0) 407 return 0; 408 409 if(sec0 == 0) { 410 sec0 = t.tv_sec; 411 usec0 = t.tv_usec; 412 } 413 return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000; 414 } 415 416 /* 417 * Return the time since the epoch in nanoseconds and microseconds 418 * The epoch is defined at 1 Jan 1970 419 */ 420 vlong 421 osnsec(void) 422 { 423 struct timeval t; 424 425 gettimeofday(&t, nil); 426 return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000; 427 } 428 429 vlong 430 osusectime(void) 431 { 432 struct timeval t; 433 434 gettimeofday(&t, nil); 435 return (vlong)t.tv_sec * 1000000 + t.tv_usec; 436 } 437 438 int 439 osmillisleep(ulong milsec) 440 { 441 struct timespec time; 442 443 time.tv_sec = milsec/1000; 444 time.tv_nsec= (milsec%1000)*1000000; 445 nanosleep(&time, NULL); 446 return 0; 447 } 448 449 int 450 limbosleep(ulong milsec) 451 { 452 return osmillisleep(milsec); 453 } 454 455 void 456 osyield(void) 457 { 458 sched_yield(); 459 } 460 461 void 462 ospause(void) 463 { 464 for(;;) 465 pause(); 466 } 467 468 void 469 oslopri(void) 470 { 471 setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4); 472 } 473 474 static struct { 475 Lock l; 476 void *free; 477 } stacklist; 478 479 static void 480 _stackfree(void *stack) 481 { 482 *((void **)stack) = stacklist.free; 483 stacklist.free = stack; 484 } 485 486 static void 487 stackfreeandexit(void *stack) 488 { 489 lock(&stacklist.l); 490 _stackfree(stack); 491 unlockandexit(&stacklist.l.val); 492 } 493 494 static void * 495 stackalloc(Proc *p, void **tos) 496 { 497 void *rv; 498 lock(&stacklist.l); 499 if (stacklist.free == 0) { 500 int x; 501 /* 502 * obtain some more by using sbrk() 503 */ 504 void *more = sbrk(KSTACK * (NSTACKSPERALLOC + 1)); 505 if (more == 0) 506 panic("stackalloc: no more stacks"); 507 /* 508 * align to KSTACK 509 */ 510 more = (void *)((((unsigned long)more) + (KSTACK - 1)) & ~(KSTACK - 1)); 511 /* 512 * free all the new stacks onto the freelist 513 */ 514 for (x = 0; x < NSTACKSPERALLOC; x++) 515 _stackfree((char *)more + KSTACK * x); 516 } 517 rv = stacklist.free; 518 stacklist.free = *(void **)rv; 519 unlock(&stacklist.l); 520 *tos = rv + KSTACK - sizeof(void *); 521 *(Proc **)rv = p; 522 return rv; 523 } 524 525 #ifdef LINUX_ARM 526 #define SYS_cacheflush __ARM_NR_cacheflush 527 528 int 529 segflush(void *a, ulong n) 530 { 531 if(n) 532 syscall(SYS_cacheflush, a, (char*)a+n-1, 1); 533 return 0; 534 } 535 #endif 536