xref: /plan9/sys/src/9/port/sysproc.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
1 #include	"u.h"
2 #include	"tos.h"
3 #include	"../port/lib.h"
4 #include	"mem.h"
5 #include	"dat.h"
6 #include	"fns.h"
7 #include	"../port/error.h"
8 #include	"edf.h"
9 
10 #include	<a.out.h>
11 
12 int	shargs(char*, int, char**);
13 
14 Ref sysr1ref;
15 
16 long
17 sysr1(ulong *arg)
18 {
19 	long a;
20 
21 	a = *arg;
22 	if(a > 0)
23 		return incref(&sysr1ref);
24 	if(a < 0)
25 		return decref(&sysr1ref);
26 	return sysr1ref.ref;
27 
28 /*
29 	extern int chandebug;
30 	extern void dumpmount(void);
31 
32 	print("[%s %s %lud] r1 = %lud\n", up->user, up->text, up->pid, arg[0]);
33 	chandebug=!chandebug;
34 	if(chandebug)
35 		dumpmount();
36 
37 	return 0;
38 */
39 }
40 
41 long
42 sysrfork(ulong *arg)
43 {
44 	Proc *p;
45 	int n, i;
46 	Fgrp *ofg;
47 	Pgrp *opg;
48 	Rgrp *org;
49 	Egrp *oeg;
50 	ulong pid, flag;
51 	Mach *wm;
52 
53 	flag = arg[0];
54 	/* Check flags before we commit */
55 	if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG))
56 		error(Ebadarg);
57 	if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG))
58 		error(Ebadarg);
59 	if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
60 		error(Ebadarg);
61 
62 	if((flag&RFPROC) == 0) {
63 		if(flag & (RFMEM|RFNOWAIT))
64 			error(Ebadarg);
65 		if(flag & (RFFDG|RFCFDG)) {
66 			ofg = up->fgrp;
67 			if(flag & RFFDG)
68 				up->fgrp = dupfgrp(ofg);
69 			else
70 				up->fgrp = dupfgrp(nil);
71 			closefgrp(ofg);
72 		}
73 		if(flag & (RFNAMEG|RFCNAMEG)) {
74 			opg = up->pgrp;
75 			up->pgrp = newpgrp();
76 			if(flag & RFNAMEG)
77 				pgrpcpy(up->pgrp, opg);
78 			/* inherit noattach */
79 			up->pgrp->noattach = opg->noattach;
80 			closepgrp(opg);
81 		}
82 		if(flag & RFNOMNT)
83 			up->pgrp->noattach = 1;
84 		if(flag & RFREND) {
85 			org = up->rgrp;
86 			up->rgrp = newrgrp();
87 			closergrp(org);
88 		}
89 		if(flag & (RFENVG|RFCENVG)) {
90 			oeg = up->egrp;
91 			up->egrp = smalloc(sizeof(Egrp));
92 			up->egrp->ref = 1;
93 			if(flag & RFENVG)
94 				envcpy(up->egrp, oeg);
95 			closeegrp(oeg);
96 		}
97 		if(flag & RFNOTEG)
98 			up->noteid = incref(&noteidalloc);
99 		return 0;
100 	}
101 
102 	p = newproc();
103 
104 	p->fpsave = up->fpsave;
105 	p->scallnr = up->scallnr;
106 	p->s = up->s;
107 	p->nerrlab = 0;
108 	p->slash = up->slash;
109 	p->dot = up->dot;
110 	incref(p->dot);
111 
112 	memmove(p->note, up->note, sizeof(p->note));
113 	p->privatemem = up->privatemem;
114 	p->noswap = up->noswap;
115 	p->nnote = up->nnote;
116 	p->notified = 0;
117 	p->lastnote = up->lastnote;
118 	p->notify = up->notify;
119 	p->ureg = up->ureg;
120 	p->dbgreg = 0;
121 
122 	/* Make a new set of memory segments */
123 	n = flag & RFMEM;
124 	qlock(&p->seglock);
125 	if(waserror()){
126 		qunlock(&p->seglock);
127 		nexterror();
128 	}
129 	for(i = 0; i < NSEG; i++)
130 		if(up->seg[i])
131 			p->seg[i] = dupseg(up->seg, i, n);
132 	qunlock(&p->seglock);
133 	poperror();
134 
135 	/* File descriptors */
136 	if(flag & (RFFDG|RFCFDG)) {
137 		if(flag & RFFDG)
138 			p->fgrp = dupfgrp(up->fgrp);
139 		else
140 			p->fgrp = dupfgrp(nil);
141 	}
142 	else {
143 		p->fgrp = up->fgrp;
144 		incref(p->fgrp);
145 	}
146 
147 	/* Process groups */
148 	if(flag & (RFNAMEG|RFCNAMEG)) {
149 		p->pgrp = newpgrp();
150 		if(flag & RFNAMEG)
151 			pgrpcpy(p->pgrp, up->pgrp);
152 		/* inherit noattach */
153 		p->pgrp->noattach = up->pgrp->noattach;
154 	}
155 	else {
156 		p->pgrp = up->pgrp;
157 		incref(p->pgrp);
158 	}
159 	if(flag & RFNOMNT)
160 		up->pgrp->noattach = 1;
161 
162 	if(flag & RFREND)
163 		p->rgrp = newrgrp();
164 	else {
165 		incref(up->rgrp);
166 		p->rgrp = up->rgrp;
167 	}
168 
169 	/* Environment group */
170 	if(flag & (RFENVG|RFCENVG)) {
171 		p->egrp = smalloc(sizeof(Egrp));
172 		p->egrp->ref = 1;
173 		if(flag & RFENVG)
174 			envcpy(p->egrp, up->egrp);
175 	}
176 	else {
177 		p->egrp = up->egrp;
178 		incref(p->egrp);
179 	}
180 	p->hang = up->hang;
181 	p->procmode = up->procmode;
182 
183 	/* Craft a return frame which will cause the child to pop out of
184 	 * the scheduler in user mode with the return register zero
185 	 */
186 	forkchild(p, up->dbgreg);
187 
188 	p->parent = up;
189 	p->parentpid = up->pid;
190 	if(flag&RFNOWAIT)
191 		p->parentpid = 0;
192 	else {
193 		lock(&up->exl);
194 		up->nchild++;
195 		unlock(&up->exl);
196 	}
197 	if((flag&RFNOTEG) == 0)
198 		p->noteid = up->noteid;
199 
200 	p->fpstate = up->fpstate;
201 	pid = p->pid;
202 	memset(p->time, 0, sizeof(p->time));
203 	p->time[TReal] = MACHP(0)->ticks;
204 
205 	kstrdup(&p->text, up->text);
206 	kstrdup(&p->user, up->user);
207 	/*
208 	 *  since the bss/data segments are now shareable,
209 	 *  any mmu info about this process is now stale
210 	 *  (i.e. has bad properties) and has to be discarded.
211 	 */
212 	flushmmu();
213 	p->basepri = up->basepri;
214 	p->priority = up->basepri;
215 	p->fixedpri = up->fixedpri;
216 	p->mp = up->mp;
217 	wm = up->wired;
218 	if(wm)
219 		procwired(p, wm->machno);
220 	ready(p);
221 	sched();
222 	return pid;
223 }
224 
225 static ulong
226 l2be(long l)
227 {
228 	uchar *cp;
229 
230 	cp = (uchar*)&l;
231 	return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];
232 }
233 
234 long
235 sysexec(ulong *arg)
236 {
237 	Segment *s, *ts;
238 	ulong t, d, b;
239 	int i;
240 	Chan *tc;
241 	char **argv, **argp;
242 	char *a, *charp, *args, *file;
243 	char *progarg[sizeof(Exec)/2+1], *elem, progelem[64];
244 	ulong ssize, spage, nargs, nbytes, n, bssend;
245 	int indir;
246 	Exec exec;
247 	char line[sizeof(Exec)];
248 	Fgrp *f;
249 	Image *img;
250 	ulong magic, text, entry, data, bss;
251 	Tos *tos;
252 
253 	validaddr(arg[0], 1, 0);
254 	file = (char*)arg[0];
255 	indir = 0;
256 	elem = nil;
257 	if(waserror()){
258 		free(elem);
259 		nexterror();
260 	}
261 	for(;;){
262 		tc = namec(file, Aopen, OEXEC, 0);
263 		if(waserror()){
264 			cclose(tc);
265 			nexterror();
266 		}
267 		if(!indir)
268 			kstrdup(&elem, up->genbuf);
269 
270 		n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0);
271 		if(n < 2)
272 			error(Ebadexec);
273 		magic = l2be(exec.magic);
274 		text = l2be(exec.text);
275 		entry = l2be(exec.entry);
276 		if(n==sizeof(Exec) && (magic == AOUT_MAGIC)){
277 			if((text&KZERO) == KZERO
278 			|| entry < UTZERO+sizeof(Exec)
279 			|| entry >= UTZERO+sizeof(Exec)+text)
280 				error(Ebadexec);
281 			break; /* for binary */
282 		}
283 
284 		/*
285 		 * Process #! /bin/sh args ...
286 		 */
287 		memmove(line, &exec, sizeof(Exec));
288 		if(indir || line[0]!='#' || line[1]!='!')
289 			error(Ebadexec);
290 		n = shargs(line, n, progarg);
291 		if(n == 0)
292 			error(Ebadexec);
293 		indir = 1;
294 		/*
295 		 * First arg becomes complete file name
296 		 */
297 		progarg[n++] = file;
298 		progarg[n] = 0;
299 		validaddr(arg[1], BY2WD, 1);
300 		arg[1] += BY2WD;
301 		file = progarg[0];
302 		if(strlen(elem) >= sizeof progelem)
303 			error(Ebadexec);
304 		strcpy(progelem, elem);
305 		progarg[0] = progelem;
306 		poperror();
307 		cclose(tc);
308 	}
309 
310 	data = l2be(exec.data);
311 	bss = l2be(exec.bss);
312 	t = (UTZERO+sizeof(Exec)+text+(BY2PG-1)) & ~(BY2PG-1);
313 	d = (t + data + (BY2PG-1)) & ~(BY2PG-1);
314 	bssend = t + data + bss;
315 	b = (bssend + (BY2PG-1)) & ~(BY2PG-1);
316 	if(((t|d|b) & KZERO) == KZERO)
317 		error(Ebadexec);
318 
319 	/*
320 	 * Args: pass 1: count
321 	 */
322 	nbytes = sizeof(Tos);		/* hole for profiling clock at top of stack (and more) */
323 	nargs = 0;
324 	if(indir){
325 		argp = progarg;
326 		while(*argp){
327 			a = *argp++;
328 			nbytes += strlen(a) + 1;
329 			nargs++;
330 		}
331 	}
332 	evenaddr(arg[1]);
333 	argp = (char**)arg[1];
334 	validaddr((ulong)argp, BY2WD, 0);
335 	while(*argp){
336 		a = *argp++;
337 		if(((ulong)argp&(BY2PG-1)) < BY2WD)
338 			validaddr((ulong)argp, BY2WD, 0);
339 		validaddr((ulong)a, 1, 0);
340 		nbytes += (vmemchr(a, 0, 0x7FFFFFFF) - a) + 1;
341 		nargs++;
342 	}
343 	ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1));
344 
345 	/*
346 	 * 8-byte align SP for those (e.g. sparc) that need it.
347 	 * execregs() will subtract another 4 bytes for argc.
348 	 */
349 	if((ssize+4) & 7)
350 		ssize += 4;
351 	spage = (ssize+(BY2PG-1)) >> PGSHIFT;
352 
353 	/*
354 	 * Build the stack segment, putting it in kernel virtual for the moment
355 	 */
356 	if(spage > TSTKSIZ)
357 		error(Enovmem);
358 
359 	qlock(&up->seglock);
360 	if(waserror()){
361 		qunlock(&up->seglock);
362 		nexterror();
363 	}
364 	up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG);
365 
366 	/*
367 	 * Args: pass 2: assemble; the pages will be faulted in
368 	 */
369 	tos = (Tos*)(TSTKTOP - sizeof(Tos));
370 	tos->cyclefreq = m->cyclefreq;
371 	cycles((uvlong*)&tos->pcycles);
372 	tos->pcycles = -tos->pcycles;
373 	tos->kcycles = tos->pcycles;
374 	tos->clock = 0;
375 	argv = (char**)(TSTKTOP - ssize);
376 	charp = (char*)(TSTKTOP - nbytes);
377 	args = charp;
378 	if(indir)
379 		argp = progarg;
380 	else
381 		argp = (char**)arg[1];
382 
383 	for(i=0; i<nargs; i++){
384 		if(indir && *argp==0) {
385 			indir = 0;
386 			argp = (char**)arg[1];
387 		}
388 		*argv++ = charp + (USTKTOP-TSTKTOP);
389 		n = strlen(*argp) + 1;
390 		memmove(charp, *argp++, n);
391 		charp += n;
392 	}
393 
394 	free(up->text);
395 	up->text = elem;
396 	elem = nil;	/* so waserror() won't free elem */
397 	USED(elem);
398 
399 	/* copy args; easiest from new process's stack */
400 	n = charp - args;
401 	if(n > 128)	/* don't waste too much space on huge arg lists */
402 		n = 128;
403 	a = up->args;
404 	up->args = nil;
405 	free(a);
406 	up->args = smalloc(n);
407 	memmove(up->args, args, n);
408 	if(n>0 && up->args[n-1]!='\0'){
409 		/* make sure last arg is NUL-terminated */
410 		/* put NUL at UTF-8 character boundary */
411 		for(i=n-1; i>0; --i)
412 			if(fullrune(up->args+i, n-i))
413 				break;
414 		up->args[i] = 0;
415 		n = i+1;
416 	}
417 	up->nargs = n;
418 
419 	/*
420 	 * Committed.
421 	 * Free old memory.
422 	 * Special segments are maintained across exec
423 	 */
424 	for(i = SSEG; i <= BSEG; i++) {
425 		putseg(up->seg[i]);
426 		/* prevent a second free if we have an error */
427 		up->seg[i] = 0;
428 	}
429 	for(i = BSEG+1; i < NSEG; i++) {
430 		s = up->seg[i];
431 		if(s != 0 && (s->type&SG_CEXEC)) {
432 			putseg(s);
433 			up->seg[i] = 0;
434 		}
435 	}
436 
437 	/*
438 	 * Close on exec
439 	 */
440 	f = up->fgrp;
441 	for(i=0; i<=f->maxfd; i++)
442 		fdclose(i, CCEXEC);
443 
444 	/* Text.  Shared. Attaches to cache image if possible */
445 	/* attachimage returns a locked cache image */
446 	img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT);
447 	ts = img->s;
448 	up->seg[TSEG] = ts;
449 	ts->flushme = 1;
450 	ts->fstart = 0;
451 	ts->flen = sizeof(Exec)+text;
452 	unlock(img);
453 
454 	/* Data. Shared. */
455 	s = newseg(SG_DATA, t, (d-t)>>PGSHIFT);
456 	up->seg[DSEG] = s;
457 
458 	/* Attached by hand */
459 	incref(img);
460 	s->image = img;
461 	s->fstart = ts->fstart+ts->flen;
462 	s->flen = data;
463 
464 	/* BSS. Zero fill on demand */
465 	up->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT);
466 
467 	/*
468 	 * Move the stack
469 	 */
470 	s = up->seg[ESEG];
471 	up->seg[ESEG] = 0;
472 	up->seg[SSEG] = s;
473 	qunlock(&up->seglock);
474 	poperror();	/* seglock */
475 	poperror();	/* elem */
476 	s->base = USTKTOP-USTKSIZE;
477 	s->top = USTKTOP;
478 	relocateseg(s, USTKTOP-TSTKTOP);
479 
480 	/*
481 	 *  '/' processes are higher priority (hack to make /ip more responsive).
482 	 */
483 	if(devtab[tc->type]->dc == L'/')
484 		up->basepri = PriRoot;
485 	up->priority = up->basepri;
486 	poperror();
487 	cclose(tc);
488 
489 	/*
490 	 *  At this point, the mmu contains info about the old address
491 	 *  space and needs to be flushed
492 	 */
493 	flushmmu();
494 	qlock(&up->debug);
495 	up->nnote = 0;
496 	up->notify = 0;
497 	up->notified = 0;
498 	up->privatemem = 0;
499 	procsetup(up);
500 	qunlock(&up->debug);
501 	if(up->hang)
502 		up->procctl = Proc_stopme;
503 
504 	return execregs(entry, ssize, nargs);
505 }
506 
507 int
508 shargs(char *s, int n, char **ap)
509 {
510 	int i;
511 
512 	s += 2;
513 	n -= 2;		/* skip #! */
514 	for(i=0; s[i]!='\n'; i++)
515 		if(i == n-1)
516 			return 0;
517 	s[i] = 0;
518 	*ap = 0;
519 	i = 0;
520 	for(;;) {
521 		while(*s==' ' || *s=='\t')
522 			s++;
523 		if(*s == 0)
524 			break;
525 		i++;
526 		*ap++ = s;
527 		*ap = 0;
528 		while(*s && *s!=' ' && *s!='\t')
529 			s++;
530 		if(*s == 0)
531 			break;
532 		else
533 			*s++ = 0;
534 	}
535 	return i;
536 }
537 
538 int
539 return0(void*)
540 {
541 	return 0;
542 }
543 
544 long
545 syssleep(ulong *arg)
546 {
547 
548 	int n;
549 
550 	n = arg[0];
551 	if(n <= 0) {
552 		if (up->edf && (up->edf->flags & Admitted))
553 			edfyield();
554 		else
555 			yield();
556 		return 0;
557 	}
558 	if(n < TK2MS(1))
559 		n = TK2MS(1);
560 	tsleep(&up->sleep, return0, 0, n);
561 	return 0;
562 }
563 
564 long
565 sysalarm(ulong *arg)
566 {
567 	return procalarm(arg[0]);
568 }
569 
570 long
571 sysexits(ulong *arg)
572 {
573 	char *status;
574 	char *inval = "invalid exit string";
575 	char buf[ERRMAX];
576 
577 	status = (char*)arg[0];
578 	if(status){
579 		if(waserror())
580 			status = inval;
581 		else{
582 			validaddr((ulong)status, 1, 0);
583 			if(vmemchr(status, 0, ERRMAX) == 0){
584 				memmove(buf, status, ERRMAX);
585 				buf[ERRMAX-1] = 0;
586 				status = buf;
587 			}
588 		}
589 		poperror();
590 
591 	}
592 	pexit(status, 1);
593 	return 0;		/* not reached */
594 }
595 
596 long
597 sys_wait(ulong *arg)
598 {
599 	int pid;
600 	Waitmsg w;
601 	OWaitmsg *ow;
602 
603 	if(arg[0] == 0)
604 		return pwait(nil);
605 
606 	validaddr(arg[0], sizeof(OWaitmsg), 1);
607 	evenaddr(arg[0]);
608 	pid = pwait(&w);
609 	if(pid >= 0){
610 		ow = (OWaitmsg*)arg[0];
611 		readnum(0, ow->pid, NUMSIZE, w.pid, NUMSIZE);
612 		readnum(0, ow->time+TUser*NUMSIZE, NUMSIZE, w.time[TUser], NUMSIZE);
613 		readnum(0, ow->time+TSys*NUMSIZE, NUMSIZE, w.time[TSys], NUMSIZE);
614 		readnum(0, ow->time+TReal*NUMSIZE, NUMSIZE, w.time[TReal], NUMSIZE);
615 		strncpy(ow->msg, w.msg, sizeof(ow->msg));
616 		ow->msg[sizeof(ow->msg)-1] = '\0';
617 	}
618 	return pid;
619 }
620 
621 long
622 sysawait(ulong *arg)
623 {
624 	int i;
625 	int pid;
626 	Waitmsg w;
627 	ulong n;
628 
629 	n = arg[1];
630 	validaddr(arg[0], n, 1);
631 	pid = pwait(&w);
632 	if(pid < 0)
633 		return -1;
634 	i = snprint((char*)arg[0], n, "%d %lud %lud %lud %q",
635 		w.pid,
636 		w.time[TUser], w.time[TSys], w.time[TReal],
637 		w.msg);
638 
639 	return i;
640 }
641 
642 long
643 sysdeath(ulong*)
644 {
645 	pprint("deprecated system call\n");
646 	pexit("Suicide", 0);
647 	return 0;	/* not reached */
648 }
649 
650 void
651 werrstr(char *fmt, ...)
652 {
653 	va_list va;
654 
655 	if(up == nil)
656 		return;
657 
658 	va_start(va, fmt);
659 	vseprint(up->syserrstr, up->syserrstr+ERRMAX, fmt, va);
660 	va_end(va);
661 }
662 
663 static long
664 generrstr(char *buf, uint nbuf)
665 {
666 	char tmp[ERRMAX];
667 
668 	if(nbuf == 0)
669 		error(Ebadarg);
670 	validaddr((ulong)buf, nbuf, 1);
671 	if(nbuf > sizeof tmp)
672 		nbuf = sizeof tmp;
673 	memmove(tmp, buf, nbuf);
674 
675 	/* make sure it's NUL-terminated */
676 	tmp[nbuf-1] = '\0';
677 	memmove(buf, up->syserrstr, nbuf);
678 	buf[nbuf-1] = '\0';
679 	memmove(up->syserrstr, tmp, nbuf);
680 	return 0;
681 }
682 
683 long
684 syserrstr(ulong *arg)
685 {
686 	return generrstr((char*)arg[0], arg[1]);
687 }
688 
689 /* compatibility for old binaries */
690 long
691 sys_errstr(ulong *arg)
692 {
693 	return generrstr((char*)arg[0], 64);
694 }
695 
696 long
697 sysnotify(ulong *arg)
698 {
699 	if(arg[0] != 0)
700 		validaddr(arg[0], sizeof(ulong), 0);
701 	up->notify = (int(*)(void*, char*))(arg[0]);
702 	return 0;
703 }
704 
705 long
706 sysnoted(ulong *arg)
707 {
708 	if(arg[0]!=NRSTR && !up->notified)
709 		error(Egreg);
710 	return 0;
711 }
712 
713 long
714 syssegbrk(ulong *arg)
715 {
716 	int i;
717 	ulong addr;
718 	Segment *s;
719 
720 	addr = arg[0];
721 	for(i = 0; i < NSEG; i++) {
722 		s = up->seg[i];
723 		if(s == 0 || addr < s->base || addr >= s->top)
724 			continue;
725 		switch(s->type&SG_TYPE) {
726 		case SG_TEXT:
727 		case SG_DATA:
728 		case SG_STACK:
729 			error(Ebadarg);
730 		default:
731 			return ibrk(arg[1], i);
732 		}
733 	}
734 
735 	error(Ebadarg);
736 	return 0;		/* not reached */
737 }
738 
739 long
740 syssegattach(ulong *arg)
741 {
742 	return segattach(up, arg[0], (char*)arg[1], arg[2], arg[3]);
743 }
744 
745 long
746 syssegdetach(ulong *arg)
747 {
748 	int i;
749 	ulong addr;
750 	Segment *s;
751 
752 	qlock(&up->seglock);
753 	if(waserror()){
754 		qunlock(&up->seglock);
755 		nexterror();
756 	}
757 
758 	s = 0;
759 	addr = arg[0];
760 	for(i = 0; i < NSEG; i++)
761 		if(s = up->seg[i]) {
762 			qlock(&s->lk);
763 			if((addr >= s->base && addr < s->top) ||
764 			   (s->top == s->base && addr == s->base))
765 				goto found;
766 			qunlock(&s->lk);
767 		}
768 
769 	error(Ebadarg);
770 
771 found:
772 	/* Check we are not detaching the current stack segment */
773 	if((ulong)arg >= s->base && (ulong)arg < s->top) {
774 		qunlock(&s->lk);
775 		error(Ebadarg);
776 	}
777 	up->seg[i] = 0;
778 	qunlock(&s->lk);
779 	putseg(s);
780 	qunlock(&up->seglock);
781 	poperror();
782 
783 	/* Ensure we flush any entries from the lost segment */
784 	flushmmu();
785 	return 0;
786 }
787 
788 long
789 syssegfree(ulong *arg)
790 {
791 	Segment *s;
792 	ulong from, to;
793 
794 	from = arg[0];
795 	s = seg(up, from, 1);
796 	if(s == nil)
797 		error(Ebadarg);
798 	to = (from + arg[1]) & ~(BY2PG-1);
799 	from = PGROUND(from);
800 
801 	if(to > s->top) {
802 		qunlock(&s->lk);
803 		error(Ebadarg);
804 	}
805 
806 	mfreeseg(s, from, (to - from) / BY2PG);
807 	qunlock(&s->lk);
808 	flushmmu();
809 
810 	return 0;
811 }
812 
813 /* For binary compatibility */
814 long
815 sysbrk_(ulong *arg)
816 {
817 	return ibrk(arg[0], BSEG);
818 }
819 
820 long
821 sysrendezvous(ulong *arg)
822 {
823 	ulong tag;
824 	ulong val;
825 	Proc *p, **l;
826 
827 	tag = arg[0];
828 	l = &REND(up->rgrp, tag);
829 	up->rendval = ~0UL;
830 
831 	lock(up->rgrp);
832 	for(p = *l; p; p = p->rendhash) {
833 		if(p->rendtag == tag) {
834 			*l = p->rendhash;
835 			val = p->rendval;
836 			p->rendval = arg[1];
837 
838 			while(p->mach != 0)
839 				;
840 			ready(p);
841 			unlock(up->rgrp);
842 			return val;
843 		}
844 		l = &p->rendhash;
845 	}
846 
847 	/* Going to sleep here */
848 	up->rendtag = tag;
849 	up->rendval = arg[1];
850 	up->rendhash = *l;
851 	*l = up;
852 	up->state = Rendezvous;
853 	unlock(up->rgrp);
854 
855 	sched();
856 
857 	return up->rendval;
858 }
859