1 /* 2 * Loosely based on FreeBSD/os.c and Solaris/os.c 3 * Copyright © 1998, 1999 Lucent Technologies Inc. All rights reserved. 4 * Revisions Copyright © 1999, 2000 Vita Nuova Limited. All rights reserved. 5 * Revisions Copyright © 2002, 2003 Corpus Callosum Corporation. All rights reserved. 6 */ 7 8 #include "dat.h" 9 #include "fns.h" 10 #include "error.h" 11 12 #include <raise.h> 13 #include <fpuctl.h> 14 15 #undef _POSIX_C_SOURCE 16 #undef getwd 17 18 #include <unistd.h> 19 #include <pthread.h> 20 #include <time.h> 21 #include <termios.h> 22 #include <signal.h> 23 #include <pwd.h> 24 #include <sys/resource.h> 25 #include <sys/time.h> 26 27 #include <sys/socket.h> 28 #include <sched.h> 29 #include <errno.h> 30 #include <sys/ucontext.h> 31 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 35 #include <mach/mach_init.h> 36 #include <mach/task.h> 37 #include <mach/vm_map.h> 38 39 #if defined(__ppc__) 40 #include <architecture/ppc/cframe.h> 41 #endif 42 43 enum 44 { 45 DELETE = 0x7F 46 }; 47 char *hosttype = "MacOSX"; 48 char *cputype = OBJTYPE; 49 50 typedef struct Sem Sem; 51 struct Sem { 52 pthread_cond_t c; 53 pthread_mutex_t m; 54 int v; 55 }; 56 57 static pthread_key_t prdakey; 58 59 extern int dflag; 60 61 Proc* 62 getup(void) 63 { 64 return pthread_getspecific(prdakey); 65 } 66 67 void 68 pexit(char *msg, int t) 69 { 70 Osenv *e; 71 Proc *p; 72 Sem *sem; 73 74 USED(t); 75 USED(msg); 76 77 lock(&procs.l); 78 p = up; 79 if(p->prev) 80 p->prev->next = p->next; 81 else 82 procs.head = p->next; 83 84 if(p->next) 85 p->next->prev = p->prev; 86 else 87 procs.tail = p->prev; 88 unlock(&procs.l); 89 90 if(0) 91 print("pexit: %s: %s\n", p->text, msg); 92 93 e = p->env; 94 if(e != nil) { 95 closefgrp(e->fgrp); 96 closepgrp(e->pgrp); 97 closeegrp(e->egrp); 98 closesigs(e->sigs); 99 free(e->user); 100 } 101 free(p->prog); 102 sem = p->os; 103 if(sem != nil){ 104 pthread_cond_destroy(&sem->c); 105 pthread_mutex_destroy(&sem->m); 106 } 107 free(p->os); 108 free(p); 109 pthread_exit(0); 110 } 111 112 113 114 static void 115 sysfault(char *what, void *addr) 116 { 117 char buf[64]; 118 119 snprint(buf, sizeof(buf), "sys: %s%#p", what, addr); 120 disfault(nil, buf); 121 } 122 123 static void 124 trapILL(int signo, siginfo_t *si, void *a) 125 { 126 USED(signo); 127 USED(a); 128 sysfault("illegal instruction pc=", si->si_addr); 129 } 130 131 static int 132 isnilref(siginfo_t *si) 133 { 134 return si != 0 && (si->si_addr == (void*)~(uintptr_t)0 || (uintptr_t)si->si_addr < 512); 135 } 136 137 static void 138 trapmemref(int signo, siginfo_t *si, void *a) 139 { 140 USED(a); /* ucontext_t*, could fetch pc in machine-dependent way */ 141 if(isnilref(si)) 142 disfault(nil, exNilref); 143 else if(signo == SIGBUS) 144 sysfault("bad address addr=", si->si_addr); /* eg, misaligned */ 145 else 146 sysfault("segmentation violation addr=", si->si_addr); 147 } 148 149 static void 150 trapFPE(int signo, siginfo_t *si, void *a) 151 { 152 char buf[64]; 153 154 USED(signo); 155 USED(a); 156 snprint(buf, sizeof(buf), "sys: fp: exception status=%.4lux pc=%#p", getfsr(), si->si_addr); 157 disfault(nil, buf); 158 } 159 160 void 161 trapUSR1(int signo) 162 { 163 USED(signo); 164 165 if(up->type != Interp) /* Used to unblock pending I/O */ 166 return; 167 if(up->intwait == 0) /* Not posted so its a sync error */ 168 disfault(nil, Eintr); /* Should never happen */ 169 170 up->intwait = 0; /* Clear it so the proc can continue */ 171 } 172 173 /* from geoff collyer's port */ 174 void 175 printILL(int sig, siginfo_t *si, void *v) 176 { 177 USED(sig); 178 USED(v); 179 panic("illegal instruction with code=%d at address=%p, opcode=%#x\n", 180 si->si_code, si->si_addr, *(uchar*)si->si_addr); 181 } 182 183 static void 184 setsigs(void) 185 { 186 struct sigaction act; 187 188 memset(&act, 0 , sizeof(act)); 189 190 /* 191 * For the correct functioning of devcmd in the 192 * face of exiting slaves 193 */ 194 signal(SIGPIPE, SIG_IGN); 195 if(signal(SIGTERM, SIG_IGN) != SIG_IGN) 196 signal(SIGTERM, cleanexit); 197 198 act.sa_handler = trapUSR1; 199 sigaction(SIGUSR1, &act, nil); 200 201 if(sflag == 0) { 202 act.sa_flags = SA_SIGINFO; 203 act.sa_sigaction = trapILL; 204 sigaction(SIGILL, &act, nil); 205 act.sa_sigaction = trapFPE; 206 sigaction(SIGFPE, &act, nil); 207 act.sa_sigaction = trapmemref; 208 sigaction(SIGBUS, &act, nil); 209 sigaction(SIGSEGV, &act, nil); 210 if(signal(SIGINT, SIG_IGN) != SIG_IGN) 211 signal(SIGINT, cleanexit); 212 } else { 213 act.sa_sigaction = printILL; 214 act.sa_flags = SA_SIGINFO; 215 sigaction(SIGILL, &act, nil); 216 } 217 } 218 219 220 221 222 void * 223 tramp(void *arg) 224 { 225 Proc *p = arg; 226 p->sigid = (int)pthread_self(); 227 if(pthread_setspecific(prdakey, arg)) { 228 print("set specific data failed in tramp\n"); 229 pthread_exit(0); 230 } 231 p->func(p->arg); 232 pexit("{Tramp}", 0); 233 return NULL; 234 } 235 236 int 237 kproc(char *name, void (*func)(void*), void *arg, int flags) 238 { 239 pthread_t thread; 240 Proc *p; 241 Pgrp *pg; 242 Fgrp *fg; 243 Egrp *eg; 244 pthread_attr_t attr; 245 Sem *sem; 246 247 p = newproc(); 248 if(p == nil) 249 panic("kproc: no memory"); 250 sem = malloc(sizeof(*sem)); 251 if(sem == nil) 252 panic("can't allocate semaphore"); 253 pthread_cond_init(&sem->c, NULL); 254 pthread_mutex_init(&sem->m, NULL); 255 sem->v = 0; 256 p->os = sem; 257 258 if(flags & KPDUPPG) { 259 pg = up->env->pgrp; 260 incref(&pg->r); 261 p->env->pgrp = pg; 262 } 263 if(flags & KPDUPFDG) { 264 fg = up->env->fgrp; 265 incref(&fg->r); 266 p->env->fgrp = fg; 267 } 268 if(flags & KPDUPENVG) { 269 eg = up->env->egrp; 270 incref(&eg->r); 271 p->env->egrp = eg; 272 } 273 274 p->env->uid = up->env->uid; 275 p->env->gid = up->env->gid; 276 kstrdup(&p->env->user, up->env->user); 277 278 strcpy(p->text, name); 279 280 p->func = func; 281 p->arg = arg; 282 283 lock(&procs.l); 284 if(procs.tail != nil) { 285 p->prev = procs.tail; 286 procs.tail->next = p; 287 } else { 288 procs.head = p; 289 p->prev = nil; 290 } 291 procs.tail = p; 292 unlock(&procs.l); 293 294 up->kid = p; 295 296 if(pthread_attr_init(&attr) == -1) 297 panic("pthread_attr_init failed"); 298 299 errno = 0; 300 pthread_attr_setschedpolicy(&attr, SCHED_OTHER); 301 if(errno) 302 panic("pthread_attr_setschedpolicy failed"); 303 304 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); 305 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 306 307 if(pthread_create(&thread, &attr, tramp, p)) 308 panic("thr_create failed\n"); 309 pthread_attr_destroy(&attr); 310 311 return (int)thread; 312 } 313 314 int 315 segflush(void *va, ulong len) 316 { 317 kern_return_t err; 318 vm_machine_attribute_val_t value = MATTR_VAL_ICACHE_FLUSH; 319 320 err = vm_machine_attribute( (vm_map_t)mach_task_self(), 321 (vm_address_t)va, 322 (vm_size_t)len, 323 MATTR_CACHE, 324 &value); 325 if(err != KERN_SUCCESS) 326 print("segflush: failure (%d) address %lud\n", err, va); 327 return (int)err; 328 } 329 330 void 331 oshostintr(Proc *p) 332 { 333 fprint(2, "oshostintr %p\n", p); 334 pthread_kill((pthread_t)p->sigid, SIGUSR1); 335 } 336 337 void 338 osblock(void) 339 { 340 Sem *sem; 341 342 sem = up->os; 343 pthread_mutex_lock(&sem->m); 344 while(sem->v == 0) 345 pthread_cond_wait(&sem->c, &sem->m); 346 sem->v--; 347 pthread_mutex_unlock(&sem->m); 348 } 349 350 void 351 osready(Proc *p) 352 { 353 Sem *sem; 354 355 sem = p->os; 356 pthread_mutex_lock(&sem->m); 357 sem->v++; 358 pthread_cond_signal(&sem->c); 359 pthread_mutex_unlock(&sem->m); 360 } 361 362 void 363 oslongjmp(void *regs, osjmpbuf env, int val) 364 { 365 USED(regs); 366 siglongjmp(env, val); 367 } 368 369 struct termios tinit; 370 371 static void 372 termset(void) 373 { 374 struct termios t; 375 376 tcgetattr(0, &t); 377 tinit = t; 378 t.c_lflag &= ~(ICANON | ECHO | ISIG); 379 t.c_cc[VMIN] = 1; 380 t.c_cc[VTIME] = 0; 381 tcsetattr(0, TCSANOW, &t); 382 } 383 384 static void 385 termrestore(void) 386 { 387 tcsetattr(0, TCSANOW, &tinit); 388 } 389 390 391 void 392 cleanexit(int x) 393 { 394 USED(x); 395 396 if(up->intwait) { 397 up->intwait = 0; 398 return; 399 } 400 401 if(dflag == 0) 402 termrestore(); 403 404 exit(0); 405 } 406 407 408 409 void 410 osreboot(char *file, char **argv) 411 { 412 if(dflag == 0) 413 termrestore(); 414 execvp(file, argv); 415 panic("reboot failure"); 416 } 417 418 419 420 int gidnobody= -1, uidnobody= -1; 421 422 void 423 getnobody() 424 { 425 struct passwd *pwd; 426 427 if((pwd = getpwnam("nobody"))) { 428 uidnobody = pwd->pw_uid; 429 gidnobody = pwd->pw_gid; 430 } 431 } 432 433 void 434 libinit(char *imod) 435 { 436 struct passwd *pw; 437 Proc *p; 438 char sys[64]; 439 440 setsid(); 441 442 // setup personality 443 gethostname(sys, sizeof(sys)); 444 kstrdup(&ossysname, sys); 445 getnobody(); 446 447 if(dflag == 0) 448 termset(); 449 450 setsigs(); 451 452 if(pthread_key_create(&prdakey, NULL)) 453 print("key_create failed\n"); 454 455 p = newproc(); 456 if(pthread_setspecific(prdakey, p)) 457 panic("set specific thread data failed\n"); 458 459 pw = getpwuid(getuid()); 460 if(pw != nil) 461 kstrdup(&eve, pw->pw_name); 462 else 463 print("cannot getpwuid\n"); 464 465 up->env->uid = getuid(); 466 up->env->gid = getgid(); 467 468 emuinit(imod); 469 } 470 471 472 473 int 474 readkbd(void) 475 { 476 int n; 477 char buf[1]; 478 479 n = read(0, buf, sizeof(buf)); 480 if(n < 0) 481 print("keyboard close (n=%d, %s)\n", n, strerror(errno)); 482 if(n <= 0) 483 pexit("keyboard thread", 0); 484 485 switch(buf[0]) { 486 case '\r': 487 buf[0] = '\n'; 488 break; 489 case DELETE: 490 cleanexit(0); 491 break; 492 } 493 return buf[0]; 494 } 495 496 /* 497 * Return an abitrary millisecond clock time 498 */ 499 long 500 osmillisec(void) 501 { 502 static long sec0 = 0, usec0; 503 struct timeval t; 504 505 if(gettimeofday(&t, NULL) < 0) 506 return(0); 507 if(sec0 == 0) { 508 sec0 = t.tv_sec; 509 usec0 = t.tv_usec; 510 } 511 return((t.tv_sec - sec0) * 1000 + (t.tv_usec - usec0 + 500) / 1000); 512 } 513 514 /* 515 * Return the time since the epoch in nanoseconds and microseconds 516 * The epoch is defined at 1 Jan 1970 517 */ 518 vlong 519 osnsec(void) 520 { 521 struct timeval t; 522 523 gettimeofday(&t, nil); 524 return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000; 525 } 526 527 vlong 528 osusectime(void) 529 { 530 struct timeval t; 531 532 gettimeofday(&t, nil); 533 return (vlong)t.tv_sec * 1000000 + t.tv_usec; 534 } 535 int 536 osmillisleep(ulong milsec) 537 { 538 struct timespec time; 539 time.tv_sec = milsec / 1000; 540 time.tv_nsec = (milsec % 1000) * 1000000; 541 nanosleep(&time, nil); 542 return 0; 543 } 544 545 int 546 limbosleep(ulong milsec) 547 { 548 return osmillisleep(milsec); 549 } 550 551 void 552 osyield(void) 553 { 554 pthread_yield_np(); 555 } 556 557 void 558 ospause(void) 559 { 560 for(;;) 561 pause(); 562 } 563 564 void 565 oslopri(void) 566 { 567 // pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param); 568 setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4); 569 } 570 571 __typeof__(sbrk(0)) 572 sbrk(int size) 573 { 574 void *brk; 575 kern_return_t err; 576 577 err = vm_allocate( (vm_map_t) mach_task_self(), 578 (vm_address_t *)&brk, 579 size, 580 VM_FLAGS_ANYWHERE); 581 if(err != KERN_SUCCESS) 582 brk = (void*)-1; 583 return brk; 584 } 585