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