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 void 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 if(pthread_attr_init(&attr) == -1) 295 panic("pthread_attr_init failed"); 296 297 pthread_attr_setschedpolicy(&attr, SCHED_OTHER); 298 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); 299 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 300 301 if(pthread_create(&thread, &attr, tramp, p)) 302 panic("thr_create failed\n"); 303 pthread_attr_destroy(&attr); 304 } 305 306 int 307 segflush(void *va, ulong len) 308 { 309 kern_return_t err; 310 vm_machine_attribute_val_t value = MATTR_VAL_ICACHE_FLUSH; 311 312 err = vm_machine_attribute( (vm_map_t)mach_task_self(), 313 (vm_address_t)va, 314 (vm_size_t)len, 315 MATTR_CACHE, 316 &value); 317 if(err != KERN_SUCCESS) 318 print("segflush: failure (%d) address %lud\n", err, va); 319 return (int)err; 320 } 321 322 void 323 oshostintr(Proc *p) 324 { 325 pthread_kill((pthread_t)p->sigid, SIGUSR1); 326 } 327 328 void 329 osblock(void) 330 { 331 Sem *sem; 332 333 sem = up->os; 334 pthread_mutex_lock(&sem->m); 335 while(sem->v == 0) 336 pthread_cond_wait(&sem->c, &sem->m); 337 sem->v--; 338 pthread_mutex_unlock(&sem->m); 339 } 340 341 void 342 osready(Proc *p) 343 { 344 Sem *sem; 345 346 sem = p->os; 347 pthread_mutex_lock(&sem->m); 348 sem->v++; 349 pthread_cond_signal(&sem->c); 350 pthread_mutex_unlock(&sem->m); 351 } 352 353 void 354 oslongjmp(void *regs, osjmpbuf env, int val) 355 { 356 USED(regs); 357 siglongjmp(env, val); 358 } 359 360 struct termios tinit; 361 362 static void 363 termset(void) 364 { 365 struct termios t; 366 367 tcgetattr(0, &t); 368 tinit = t; 369 t.c_lflag &= ~(ICANON | ECHO | ISIG); 370 t.c_cc[VMIN] = 1; 371 t.c_cc[VTIME] = 0; 372 tcsetattr(0, TCSANOW, &t); 373 } 374 375 static void 376 termrestore(void) 377 { 378 tcsetattr(0, TCSANOW, &tinit); 379 } 380 381 382 void 383 cleanexit(int x) 384 { 385 USED(x); 386 387 if(up->intwait) { 388 up->intwait = 0; 389 return; 390 } 391 392 if(dflag == 0) 393 termrestore(); 394 395 exit(0); 396 } 397 398 399 400 void 401 osreboot(char *file, char **argv) 402 { 403 if(dflag == 0) 404 termrestore(); 405 execvp(file, argv); 406 panic("reboot failure"); 407 } 408 409 410 411 int gidnobody= -1, uidnobody= -1; 412 413 void 414 getnobody() 415 { 416 struct passwd *pwd; 417 418 if((pwd = getpwnam("nobody"))) { 419 uidnobody = pwd->pw_uid; 420 gidnobody = pwd->pw_gid; 421 } 422 } 423 424 void 425 libinit(char *imod) 426 { 427 struct passwd *pw; 428 Proc *p; 429 char sys[64]; 430 431 setsid(); 432 433 // setup personality 434 gethostname(sys, sizeof(sys)); 435 kstrdup(&ossysname, sys); 436 getnobody(); 437 438 if(dflag == 0) 439 termset(); 440 441 setsigs(); 442 443 if(pthread_key_create(&prdakey, NULL)) 444 print("key_create failed\n"); 445 446 p = newproc(); 447 if(pthread_setspecific(prdakey, p)) 448 panic("set specific thread data failed\n"); 449 450 pw = getpwuid(getuid()); 451 if(pw != nil) 452 kstrdup(&eve, pw->pw_name); 453 else 454 print("cannot getpwuid\n"); 455 456 up->env->uid = getuid(); 457 up->env->gid = getgid(); 458 459 emuinit(imod); 460 } 461 462 463 464 int 465 readkbd(void) 466 { 467 int n; 468 char buf[1]; 469 470 n = read(0, buf, sizeof(buf)); 471 if(n < 0) 472 print("keyboard close (n=%d, %s)\n", n, strerror(errno)); 473 if(n <= 0) 474 pexit("keyboard thread", 0); 475 476 switch(buf[0]) { 477 case '\r': 478 buf[0] = '\n'; 479 break; 480 case DELETE: 481 cleanexit(0); 482 break; 483 } 484 return buf[0]; 485 } 486 487 /* 488 * Return an abitrary millisecond clock time 489 */ 490 long 491 osmillisec(void) 492 { 493 static long sec0 = 0, usec0; 494 struct timeval t; 495 496 if(gettimeofday(&t, NULL) < 0) 497 return(0); 498 if(sec0 == 0) { 499 sec0 = t.tv_sec; 500 usec0 = t.tv_usec; 501 } 502 return((t.tv_sec - sec0) * 1000 + (t.tv_usec - usec0 + 500) / 1000); 503 } 504 505 /* 506 * Return the time since the epoch in nanoseconds and microseconds 507 * The epoch is defined at 1 Jan 1970 508 */ 509 vlong 510 osnsec(void) 511 { 512 struct timeval t; 513 514 gettimeofday(&t, nil); 515 return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000; 516 } 517 518 vlong 519 osusectime(void) 520 { 521 struct timeval t; 522 523 gettimeofday(&t, nil); 524 return (vlong)t.tv_sec * 1000000 + t.tv_usec; 525 } 526 int 527 osmillisleep(ulong milsec) 528 { 529 struct timespec time; 530 time.tv_sec = milsec / 1000; 531 time.tv_nsec = (milsec % 1000) * 1000000; 532 nanosleep(&time, nil); 533 return 0; 534 } 535 536 int 537 limbosleep(ulong milsec) 538 { 539 return osmillisleep(milsec); 540 } 541 542 void 543 osyield(void) 544 { 545 pthread_yield_np(); 546 } 547 548 void 549 ospause(void) 550 { 551 for(;;) 552 pause(); 553 } 554 555 void 556 oslopri(void) 557 { 558 // pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param); 559 setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4); 560 } 561 562 __typeof__(sbrk(0)) 563 sbrk(int size) 564 { 565 void *brk; 566 kern_return_t err; 567 568 err = vm_allocate( (vm_map_t) mach_task_self(), 569 (vm_address_t *)&brk, 570 size, 571 VM_FLAGS_ANYWHERE); 572 if(err != KERN_SUCCESS) 573 brk = (void*)-1; 574 return brk; 575 } 576