1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 8 #include <a.out.h> 9 10 int shargs(char*, int, char**); 11 12 long 13 sysr1(ulong *arg) 14 { 15 xsummary(); 16 print("[%s %s %d] r1 = %d\n", u->p->user, u->p->text, u->p->pid, arg[0]); 17 return 0; 18 } 19 20 long 21 sysrfork(ulong *arg) 22 { 23 KMap *k; 24 Pgrp *opg; 25 Egrp *oeg; 26 Fgrp *ofg; 27 int n, i; 28 Proc *p, *parent; 29 ulong upa, pid, flag; 30 /* 31 * used to compute last valid system stack address for copy 32 */ 33 int lastvar; 34 35 flag = arg[0]; 36 p = u->p; 37 if((flag&RFPROC) == 0) { 38 if(flag & (RFNAMEG|RFCNAMEG)) { 39 if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG)) 40 error(Ebadarg); 41 opg = p->pgrp; 42 p->pgrp = newpgrp(); 43 if(flag & RFNAMEG) 44 pgrpcpy(p->pgrp, opg); 45 closepgrp(opg); 46 } 47 if(flag & (RFENVG|RFCENVG)) { 48 if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG)) 49 error(Ebadarg); 50 oeg = p->egrp; 51 p->egrp = smalloc(sizeof(Egrp)); 52 p->egrp->ref = 1; 53 if(flag & RFENVG) 54 envcpy(p->egrp, oeg); 55 closeegrp(oeg); 56 } 57 if(flag & RFFDG) { 58 ofg = p->fgrp; 59 p->fgrp = dupfgrp(ofg); 60 closefgrp(ofg); 61 } 62 else 63 if(flag & RFCFDG) { 64 ofg = p->fgrp; 65 p->fgrp = smalloc(sizeof(Fgrp)); 66 p->fgrp->ref = 1; 67 closefgrp(ofg); 68 } 69 if(flag & RFNOTEG) 70 p->noteid = incref(¬eidalloc); 71 if(flag & (RFMEM|RFNOWAIT)) 72 error(Ebadarg); 73 return 0; 74 } 75 /* Check flags before we commit */ 76 if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) 77 error(Ebadarg); 78 if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG)) 79 error(Ebadarg); 80 if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG)) 81 error(Ebadarg); 82 83 p = newproc(); 84 parent = u->p; 85 86 /* Page va of upage used as check in mapstack */ 87 p->upage = newpage(0, 0, USERADDR|(p->pid&0xFFFF)); 88 k = kmap(p->upage); 89 upa = VA(k); 90 91 /* Save time: only copy u-> data and useful stack */ 92 memmove((void*)upa, u, sizeof(User)); 93 n = USERADDR+BY2PG - (ulong)&lastvar; 94 n = (n+32) & ~(BY2WD-1); 95 memmove((void*)(upa+BY2PG-n), (void*)(USERADDR+BY2PG-n), n); 96 ((User *)upa)->p = p; 97 kunmap(k); 98 99 /* Make a new set of memory segments */ 100 n = flag & RFMEM; 101 for(i = 0; i < NSEG; i++) 102 if(parent->seg[i]) 103 p->seg[i] = dupseg(parent->seg, i, n); 104 105 /* Refs */ 106 incref(u->dot); 107 108 /* File descriptors */ 109 if(flag & (RFFDG|RFCFDG)) { 110 if(flag & RFFDG) 111 p->fgrp = dupfgrp(parent->fgrp); 112 else { 113 p->fgrp = smalloc(sizeof(Fgrp)); 114 p->fgrp->ref = 1; 115 } 116 } 117 else { 118 p->fgrp = parent->fgrp; 119 incref(p->fgrp); 120 } 121 122 /* Process groups */ 123 if(flag & (RFNAMEG|RFCNAMEG)) { 124 p->pgrp = newpgrp(); 125 if(flag & RFNAMEG) 126 pgrpcpy(p->pgrp, parent->pgrp); 127 } 128 else { 129 p->pgrp = parent->pgrp; 130 incref(p->pgrp); 131 } 132 133 /* Environment group */ 134 if(flag & (RFENVG|RFCENVG)) { 135 p->egrp = smalloc(sizeof(Egrp)); 136 p->egrp->ref = 1; 137 if(flag & RFENVG) 138 envcpy(p->egrp, parent->egrp); 139 } 140 else { 141 p->egrp = parent->egrp; 142 incref(p->egrp); 143 } 144 145 p->hang = parent->hang; 146 p->procmode = parent->procmode; 147 148 if(setlabel(&p->sched)){ 149 /* 150 * use u->p instead of p, because we don't trust the compiler, after a 151 * gotolabel, to find the correct contents of a local variable. 152 */ 153 p = u->p; 154 p->state = Running; 155 p->mach = m; 156 m->proc = p; 157 spllo(); 158 return 0; 159 } 160 161 p->parent = parent; 162 p->parentpid = parent->pid; 163 if(flag&RFNOWAIT) 164 p->parentpid = 1; 165 else { 166 lock(&parent->exl); 167 parent->nchild++; 168 unlock(&parent->exl); 169 } 170 if((flag&RFNOTEG) == 0) 171 p->noteid = parent->noteid; 172 173 p->fpstate = parent->fpstate; 174 pid = p->pid; 175 memset(p->time, 0, sizeof(p->time)); 176 p->time[TReal] = MACHP(0)->ticks; 177 memmove(p->text, parent->text, NAMELEN); 178 memmove(p->user, parent->user, NAMELEN); 179 /* 180 * since the bss/data segments are now shareable, 181 * any mmu info about this process is now stale 182 * (i.e. has bad properties) and has to be discarded. 183 */ 184 flushmmu(); 185 p->priority = u->p->priority; 186 p->basepri = u->p->basepri; 187 p->mp = u->p->mp; 188 ready(p); 189 sched(); 190 return pid; 191 } 192 193 static ulong 194 l2be(long l) 195 { 196 uchar *cp; 197 198 cp = (uchar*)&l; 199 return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3]; 200 } 201 202 long 203 sysexec(ulong *arg) 204 { 205 Proc *p; 206 Segment *s, *ts; 207 ulong t, d, b; 208 int i; 209 Chan *tc; 210 char **argv, **argp; 211 char *a, *charp, *file; 212 char *progarg[sizeof(Exec)/2+1], elem[NAMELEN]; 213 ulong ssize, spage, nargs, nbytes, n, bssend; 214 int indir; 215 Exec exec; 216 char line[sizeof(Exec)]; 217 Fgrp *f; 218 Image *img; 219 ulong magic, text, entry, data, bss; 220 221 p = u->p; 222 validaddr(arg[0], 1, 0); 223 file = (char*)arg[0]; 224 indir = 0; 225 Header: 226 tc = namec(file, Aopen, OEXEC, 0); 227 if(waserror()){ 228 close(tc); 229 nexterror(); 230 } 231 if(!indir) 232 strcpy(elem, u->elem); 233 234 n = (*devtab[tc->type].read)(tc, &exec, sizeof(Exec), 0); 235 if(n < 2) 236 Err: 237 error(Ebadexec); 238 magic = l2be(exec.magic); 239 text = l2be(exec.text); 240 entry = l2be(exec.entry); 241 if(n==sizeof(Exec) && magic==AOUT_MAGIC){ 242 if((text&KZERO) 243 || entry < UTZERO+sizeof(Exec) 244 || entry >= UTZERO+sizeof(Exec)+text) 245 goto Err; 246 goto Binary; 247 } 248 249 /* 250 * Process #! /bin/sh args ... 251 */ 252 memmove(line, &exec, sizeof(Exec)); 253 if(indir || line[0]!='#' || line[1]!='!') 254 goto Err; 255 n = shargs(line, n, progarg); 256 if(n == 0) 257 goto Err; 258 indir = 1; 259 /* 260 * First arg becomes complete file name 261 */ 262 progarg[n++] = file; 263 progarg[n] = 0; 264 validaddr(arg[1], BY2WD, 1); 265 arg[1] += BY2WD; 266 file = progarg[0]; 267 progarg[0] = elem; 268 poperror(); 269 close(tc); 270 goto Header; 271 272 Binary: 273 poperror(); 274 data = l2be(exec.data); 275 bss = l2be(exec.bss); 276 t = (UTZERO+sizeof(Exec)+text+(BY2PG-1)) & ~(BY2PG-1); 277 d = (t + data + (BY2PG-1)) & ~(BY2PG-1); 278 bssend = t + data + bss; 279 b = (bssend + (BY2PG-1)) & ~(BY2PG-1); 280 if((t|d|b) & KZERO) 281 error(Ebadexec); 282 283 /* 284 * Args: pass 1: count 285 */ 286 nbytes = BY2WD; /* hole for profiling clock at top of stack */ 287 nargs = 0; 288 if(indir){ 289 argp = progarg; 290 while(*argp){ 291 a = *argp++; 292 nbytes += strlen(a) + 1; 293 nargs++; 294 } 295 } 296 evenaddr(arg[1]); 297 argp = (char**)arg[1]; 298 validaddr((ulong)argp, BY2WD, 0); 299 while(*argp){ 300 a = *argp++; 301 if(((ulong)argp&(BY2PG-1)) < BY2WD) 302 validaddr((ulong)argp, BY2WD, 0); 303 validaddr((ulong)a, 1, 0); 304 nbytes += (vmemchr(a, 0, 0x7FFFFFFF) - a) + 1; 305 nargs++; 306 } 307 ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1)); 308 309 /* 310 * 8-byte align SP for those (e.g. sparc) that need it. 311 * execregs() will subtract another 4 bytes for argc. 312 */ 313 if((ssize+4) & 7) 314 ssize += 4; 315 spage = (ssize+(BY2PG-1)) >> PGSHIFT; 316 /* 317 * Build the stack segment, putting it in kernel virtual for the moment 318 */ 319 if(spage > TSTKSIZ) 320 error(Enovmem); 321 322 p->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG); 323 324 /* 325 * Args: pass 2: assemble; the pages will be faulted in 326 */ 327 argv = (char**)(TSTKTOP - ssize); 328 charp = (char*)(TSTKTOP - nbytes); 329 if(indir) 330 argp = progarg; 331 else 332 argp = (char**)arg[1]; 333 334 for(i=0; i<nargs; i++){ 335 if(indir && *argp==0) { 336 indir = 0; 337 argp = (char**)arg[1]; 338 } 339 *argv++ = charp + (USTKTOP-TSTKTOP); 340 n = strlen(*argp) + 1; 341 memmove(charp, *argp++, n); 342 charp += n; 343 } 344 345 memmove(p->text, elem, NAMELEN); 346 347 /* 348 * Committed. 349 * Free old memory. 350 * Special segments are maintained accross exec 351 */ 352 for(i = SSEG; i <= BSEG; i++) { 353 putseg(p->seg[i]); 354 /* prevent a second free if we have an error */ 355 p->seg[i] = 0; 356 } 357 for(i = BSEG+1; i < NSEG; i++) { 358 s = p->seg[i]; 359 if(s != 0 && (s->type&SG_CEXEC)) { 360 putseg(s); 361 p->seg[i] = 0; 362 } 363 } 364 365 /* 366 * Close on exec 367 */ 368 f = u->p->fgrp; 369 for(i=0; i<=f->maxfd; i++) 370 fdclose(i, CCEXEC); 371 372 /* Text. Shared. Attaches to cache image if possible */ 373 /* attachimage returns a locked cache image */ 374 img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT); 375 ts = img->s; 376 p->seg[TSEG] = ts; 377 ts->flushme = 1; 378 ts->fstart = 0; 379 ts->flen = sizeof(Exec)+text; 380 unlock(img); 381 382 /* Data. Shared. */ 383 s = newseg(SG_DATA, t, (d-t)>>PGSHIFT); 384 p->seg[DSEG] = s; 385 386 /* Attached by hand */ 387 incref(img); 388 s->image = img; 389 s->fstart = ts->fstart+ts->flen; 390 s->flen = data; 391 392 /* BSS. Zero fill on demand */ 393 p->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT); 394 395 /* 396 * Move the stack 397 */ 398 s = p->seg[ESEG]; 399 p->seg[ESEG] = 0; 400 p->seg[SSEG] = s; 401 s->base = USTKTOP-USTKSIZE; 402 s->top = USTKTOP; 403 relocateseg(s, TSTKTOP-USTKTOP); 404 405 /* 406 * '/' processes are higher priority (hack to make /ip more responsive). 407 */ 408 if(devchar[tc->type] == L'/') 409 u->p->basepri = PriRoot; 410 u->p->priority = u->p->basepri; 411 close(tc); 412 413 /* 414 * At this point, the mmu contains info about the old address 415 * space and needs to be flushed 416 */ 417 flushmmu(); 418 qlock(&p->debug); 419 u->nnote = 0; 420 u->notify = 0; 421 u->notified = 0; 422 procsetup(p); 423 qunlock(&p->debug); 424 if(p->hang) 425 p->procctl = Proc_stopme; 426 427 return execregs(entry, ssize, nargs); 428 } 429 430 int 431 shargs(char *s, int n, char **ap) 432 { 433 int i; 434 435 s += 2; 436 n -= 2; /* skip #! */ 437 for(i=0; s[i]!='\n'; i++) 438 if(i == n-1) 439 return 0; 440 s[i] = 0; 441 *ap = 0; 442 i = 0; 443 for(;;){ 444 while(*s==' ' || *s=='\t') 445 s++; 446 if(*s == 0) 447 break; 448 i++; 449 *ap++ = s; 450 *ap = 0; 451 while(*s && *s!=' ' && *s!='\t') 452 s++; 453 if(*s == 0) 454 break; 455 else 456 *s++ = 0; 457 } 458 return i; 459 } 460 461 int 462 return0(void *a) 463 { 464 USED(a); 465 return 0; 466 } 467 468 long 469 syssleep(ulong *arg) 470 { 471 int n; 472 473 n = arg[0]; 474 if(n == 0){ 475 sched(); /* yield */ 476 return 0; 477 } 478 if(MS2TK(n) == 0) /* sleep for at least one tick */ 479 n = TK2MS(1); 480 tsleep(&u->p->sleep, return0, 0, n); 481 482 return 0; 483 } 484 485 long 486 sysalarm(ulong *arg) 487 { 488 return procalarm(arg[0]); 489 } 490 491 long 492 sysexits(ulong *arg) 493 { 494 char *status; 495 char *inval = "invalid exit string"; 496 char buf[ERRLEN]; 497 498 status = (char*)arg[0]; 499 if(status){ 500 if(waserror()) 501 status = inval; 502 else{ 503 validaddr((ulong)status, 1, 0); 504 if(vmemchr(status, 0, ERRLEN) == 0){ 505 memmove(buf, status, ERRLEN); 506 buf[ERRLEN-1] = 0; 507 status = buf; 508 } 509 } 510 poperror(); 511 512 } 513 pexit(status, 1); 514 return 0; /* not reached */ 515 } 516 517 long 518 syswait(ulong *arg) 519 { 520 if(arg[0]){ 521 validaddr(arg[0], sizeof(Waitmsg), 1); 522 evenaddr(arg[0]); 523 } 524 return pwait((Waitmsg*)arg[0]); 525 } 526 527 long 528 sysdeath(ulong *arg) 529 { 530 USED(arg); 531 pprint("deprecated system call\n"); 532 pexit("Suicide", 0); 533 return 0; /* not reached */ 534 } 535 536 long 537 syserrstr(ulong *arg) 538 { 539 char tmp[ERRLEN]; 540 541 validaddr(arg[0], ERRLEN, 1); 542 memmove(tmp, (char*)arg[0], ERRLEN); 543 memmove((char*)arg[0], u->error, ERRLEN); 544 memmove(u->error, tmp, ERRLEN); 545 return 0; 546 } 547 548 long 549 sysnotify(ulong *arg) 550 { 551 USED(arg); 552 if(arg[0] != 0) 553 validaddr(arg[0], sizeof(ulong), 0); 554 u->notify = (int(*)(void*, char*))(arg[0]); 555 return 0; 556 } 557 558 long 559 sysnoted(ulong *arg) 560 { 561 if(arg[0]!=NRSTR && !u->notified) 562 error(Egreg); 563 return 0; 564 } 565 566 long 567 syssegbrk(ulong *arg) 568 { 569 Segment *s; 570 int i; 571 572 for(i = 0; i < NSEG; i++) { 573 if(s = u->p->seg[i]) { 574 if(arg[0] >= s->base && arg[0] < s->top) { 575 switch(s->type&SG_TYPE) { 576 case SG_TEXT: 577 case SG_DATA: 578 case SG_STACK: 579 error(Ebadarg); 580 default: 581 return ibrk(arg[1], i); 582 } 583 } 584 } 585 } 586 587 error(Ebadarg); 588 return 0; /* not reached */ 589 } 590 591 long 592 syssegattach(ulong *arg) 593 { 594 return segattach(u->p, arg[0], (char*)arg[1], arg[2], arg[3]); 595 } 596 597 long 598 syssegdetach(ulong *arg) 599 { 600 int i; 601 Segment *s; 602 603 s = 0; 604 for(i = 0; i < NSEG; i++) 605 if(s = u->p->seg[i]) { 606 qlock(&s->lk); 607 if((arg[0] >= s->base && arg[0] < s->top) || 608 (s->top == s->base && arg[0] == s->base)) 609 goto found; 610 qunlock(&s->lk); 611 } 612 613 error(Ebadarg); 614 615 found: 616 if((ulong)arg >= s->base && (ulong)arg < s->top) { 617 qunlock(&s->lk); 618 error(Ebadarg); 619 } 620 u->p->seg[i] = 0; 621 qunlock(&s->lk); 622 putseg(s); 623 624 /* Ensure we flush any entries from the lost segment */ 625 flushmmu(); 626 return 0; 627 } 628 629 long 630 syssegfree(ulong *arg) 631 { 632 Segment *s; 633 ulong from, pages; 634 635 from = PGROUND(arg[0]); 636 s = seg(u->p, from, 1); 637 if(s == 0) 638 error(Ebadarg); 639 640 pages = (arg[1]+BY2PG-1)/BY2PG; 641 642 if(from+pages*BY2PG > s->top) { 643 qunlock(&s->lk); 644 error(Ebadarg); 645 } 646 647 mfreeseg(s, from, pages); 648 qunlock(&s->lk); 649 flushmmu(); 650 651 return 0; 652 } 653 654 /* For binary compatability */ 655 long 656 sysbrk_(ulong *arg) 657 { 658 return ibrk(arg[0], BSEG); 659 } 660 661 long 662 sysrendezvous(ulong *arg) 663 { 664 Proc *p, **l; 665 int tag; 666 ulong val; 667 668 tag = arg[0]; 669 l = &REND(u->p->pgrp, tag); 670 671 lock(u->p->pgrp); 672 for(p = *l; p; p = p->rendhash) { 673 if(p->rendtag == tag) { 674 *l = p->rendhash; 675 val = p->rendval; 676 p->rendval = arg[1]; 677 /* Hard race avoidance */ 678 while(p->mach != 0) 679 ; 680 ready(p); 681 unlock(u->p->pgrp); 682 return val; 683 } 684 l = &p->rendhash; 685 } 686 687 /* Going to sleep here */ 688 p = u->p; 689 p->rendtag = tag; 690 p->rendval = arg[1]; 691 p->rendhash = *l; 692 *l = p; 693 u->p->state = Rendezvous; 694 unlock(p->pgrp); 695 696 sched(); 697 698 return u->p->rendval; 699 } 700