xref: /inferno-os/emu/FreeBSD/os.c (revision e57c7e16a3789cd4de1a3c2560d49b1ee39cd10a)
1 #include	"dat.h"
2 #include	"fns.h"
3 #include	"error.h"
4 #undef getwd
5 #include	<signal.h>
6 #include 	<sys/socket.h>
7 #include	<time.h>
8 #include	<sys/time.h>
9 #include	<termios.h>
10 #include	<sched.h>
11 #include	<pwd.h>
12 #include	<errno.h>
13 #include	<unistd.h>
14 #include	<sys/resource.h>
15 #include	<fpuctl.h>
16 
17 enum
18 {
19 	DELETE  = 0x7F,
20 	NSTACKSPERALLOC = 16,
21 	X11STACK=	256*1024
22 };
23 char *hosttype = "FreeBSD";
24 
25 extern void unlockandexit(int*);
26 extern void executeonnewstack(void*, void (*f)(void*), void*);
27 static void *stackalloc(Proc *p, void **tos);
28 static void stackfreeandexit(void *stack);
29 
30 extern int dflag;
31 
32 void
33 pexit(char *msg, int t)
34 {
35 	Osenv *e;
36 	Proc *p;
37 	void *kstack;
38 
39 	lock(&procs.l);
40 	p = up;
41 	if(p->prev)
42 		p->prev->next = p->next;
43 	else
44 		procs.head = p->next;
45 
46 	if(up->next)
47 		p->next->prev = p->prev;
48 	else
49 		procs.tail = p->prev;
50 	unlock(&procs.l);
51 
52 	if(0)
53 		print("pexit: %s: %s\n", up->text, msg);
54 
55 	e = up->env;
56 	if(e != nil) {
57 		closefgrp(e->fgrp);
58 		closepgrp(e->pgrp);
59 		closeegrp(e->egrp);
60 		closesigs(e->sigs);
61 	}
62 	kstack = p->kstack;
63 	free(p->prog);
64 	free(p);
65 	if(kstack != nil)
66 		stackfreeandexit(kstack);
67 }
68 
69 void
70 trapBUS(int signo, siginfo_t *info, void *context)
71 {
72 	if(info)
73 		print("trapBUS: signo: %d code: %d addr: %lx\n",
74 		info->si_signo, info->si_code, info->si_addr);
75 	else
76 		print("trapBUS: no info\n");
77 	disfault(nil, "Bus error");
78 }
79 
80 static void
81 trapUSR1(int signo)
82 {
83 	int intwait;
84 
85 	USED(signo);
86 
87 	intwait = up->intwait;
88 	up->intwait = 0;	/* clear it to let proc continue in osleave */
89 
90 	if(up->type != Interp)		/* Used to unblock pending I/O */
91 		return;
92 	if(intwait == 0)		/* Not posted so its a sync error */
93 		disfault(nil, Eintr);	/* Should never happen */
94 }
95 
96 static void
97 trapUSR2(int signo)
98 {
99 	USED(signo);
100 	/* we've done our work of interrupting sigsuspend */
101 }
102 
103 static void
104 trapILL(int signo)
105 {
106 	disfault(nil, "Illegal instruction");
107 }
108 
109 static void
110 trapSEGV(int signo)
111 {
112 	disfault(nil, "Segmentation violation");
113 }
114 
115 static void
116 trapFPE(int signo)
117 {
118 
119 	char buf[64];
120 	USED(signo);
121 	snprint(buf, sizeof(buf), "sys: fp: exception status=%.4lux", getfsr());
122 	disfault(nil, buf);
123 }
124 
125 static sigset_t initmask;
126 
127 static void
128 setsigs(void)
129 {
130 	struct sigaction act;
131 	sigset_t mask;
132 
133 	memset(&act, 0 , sizeof(act));
134 	sigemptyset(&initmask);
135 
136 	signal(SIGPIPE, SIG_IGN);	/* prevent signal when devcmd child exits */
137 	if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
138 		signal(SIGTERM, cleanexit);
139 
140 	act.sa_handler = trapUSR1;
141 	act.sa_mask = initmask;
142 	sigaction(SIGUSR1, &act, nil);
143 
144 	act.sa_handler = trapUSR2;
145 	sigaction(SIGUSR2, &act, nil);
146 	sigemptyset(&mask);
147 	sigaddset(&mask, SIGUSR2);
148 	sigaddset(&initmask, SIGUSR2);
149 	sigprocmask(SIG_BLOCK, &mask, NULL);
150 
151 	/*
152  	 * prevent Zombies forming when any process terminates
153 	 */
154 	act.sa_sigaction = 0;
155 	act.sa_flags |= SA_NOCLDWAIT;
156 	if(sigaction(SIGCHLD, &act, nil))
157 		panic("sigaction SIGCHLD");
158 
159 	if(sflag == 0) {
160 		act.sa_sigaction = trapBUS;
161 		act.sa_flags |= SA_SIGINFO;
162 		if(sigaction(SIGBUS, &act, nil))
163 			panic("sigaction SIGBUS");
164 		act.sa_handler = trapILL;
165 		if(sigaction(SIGILL, &act, nil))
166 			panic("sigaction SIGBUS");
167 		act.sa_handler = trapSEGV;
168 		if(sigaction(SIGSEGV, &act, nil))
169 			panic("sigaction SIGSEGV");
170 		act.sa_handler = trapFPE;
171 		if(sigaction(SIGFPE, &act, nil))
172 			panic("sigaction SIGFPE");
173 		if(sigaddset(&initmask, SIGINT) == -1)
174 			panic("sigaddset");
175 	}
176 	if(sigprocmask(SIG_BLOCK, &initmask, nil)!= 0)
177 		panic("sigprocmask");
178 }
179 
180 static int
181 tramp(void *arg)
182 {
183 	Proc *p;
184 
185 	p = arg;
186 	p->pid = p->sigid = getpid();
187 	sigprocmask(SIG_BLOCK, &initmask, nil);	/* in 5.3, rfork_thread doesn't copy from parent, contrary to docs? */
188 	(*p->func)(p->arg);
189 	pexit("{Tramp}", 0);
190 	_exit(0);
191 }
192 
193 void
194 kproc(char *name, void (*func)(void*), void *arg, int flags)
195 {
196 	Proc *p;
197 	Pgrp *pg;
198 	Fgrp *fg;
199 	Egrp *eg;
200 	int pid;
201 	void *tos;
202 
203 	p = newproc();
204 
205 	if(flags & KPDUPPG) {
206 		pg = up->env->pgrp;
207 		incref(&pg->r);
208 		p->env->pgrp = pg;
209 	}
210 	if(flags & KPDUPFDG) {
211 		fg = up->env->fgrp;
212 		incref(&fg->r);
213 		p->env->fgrp = fg;
214 	}
215 	if(flags & KPDUPENVG) {
216 		eg = up->env->egrp;
217 		incref(&eg->r);
218 		p->env->egrp = eg;
219 	}
220 
221 	p->env->uid = up->env->uid;
222 	p->env->gid = up->env->gid;
223 	kstrdup(&p->env->user, up->env->user);
224 
225 	strcpy(p->text, name);
226 
227 	p->func = func;
228 	p->arg = arg;
229 
230 	lock(&procs.l);
231 	if(procs.tail != nil) {
232 		p->prev = procs.tail;
233 		procs.tail->next = p;
234 	}
235 	else {
236 		procs.head = p;
237 		p->prev = nil;
238 	}
239 	procs.tail = p;
240 	unlock(&procs.l);
241 
242 	if(flags & KPX11){
243 		p->kstack = nil;	/* never freed; also up not defined */
244 		tos = (char*)mallocz(X11STACK, 0) + X11STACK - sizeof(void*);
245 	}else
246 		p->kstack = stackalloc(p, &tos);
247 	pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, tos, tramp, p);
248 	if(pid < 0)
249 		panic("rfork");
250 }
251 
252 void
253 oshostintr(Proc *p)
254 {
255 	kill(p->sigid, SIGUSR1);
256 }
257 
258 void
259 osblock(void)
260 {
261 	sigset_t mask;
262 
263 	sigprocmask(SIG_SETMASK, NULL, &mask);
264 	sigdelset(&mask, SIGUSR2);
265 	sigsuspend(&mask);
266 }
267 
268 void
269 osready(Proc *p)
270 {
271 	if(kill(p->sigid, SIGUSR2) < 0)
272 		fprint(2, "emu: osready failed: pid %d: %s\n", p->sigid, strerror(errno));
273 }
274 
275 void
276 oslongjmp(void *regs, osjmpbuf env, int val)
277 {
278 	USED(regs);
279 	siglongjmp(env, val);
280 }
281 
282 struct termios tinit;
283 
284 static void
285 termset(void)
286 {
287 	struct termios t;
288 
289 	tcgetattr(0, &t);
290 	tinit = t;
291 	t.c_lflag &= ~(ICANON|ECHO|ISIG);
292 	t.c_cc[VMIN] = 1;
293 	t.c_cc[VTIME] = 0;
294 	tcsetattr(0, TCSANOW, &t);
295 }
296 
297 static void
298 termrestore(void)
299 {
300 	tcsetattr(0, TCSANOW, &tinit);
301 }
302 
303 void
304 cleanexit(int x)
305 {
306 	USED(x);
307 
308 	if(up->intwait) {
309 		up->intwait = 0;
310 		return;
311 	}
312 
313 	if(dflag == 0)
314 		termrestore();
315 
316 	kill(0, SIGKILL);
317 	exit(0);
318 }
319 
320 void
321 osreboot(char *file, char **argv)
322 {
323 	if(dflag == 0)
324 		termrestore();
325 	execvp(file, argv);
326 	panic("reboot failure");
327 }
328 
329 int gidnobody= -1, uidnobody= -1;
330 
331 void
332 getnobody()
333 {
334 	struct passwd *pwd;
335 
336 	if(pwd = getpwnam("nobody")) {
337 		uidnobody = pwd->pw_uid;
338 		gidnobody = pwd->pw_gid;
339 	}
340 }
341 
342 void
343 libinit(char *imod)
344 {
345 	struct passwd *pw;
346 	Proc *p;
347 	void *tos;
348 	char sys[64];
349 
350 	setsid();
351 
352 	gethostname(sys, sizeof(sys));
353 	kstrdup(&ossysname, sys);
354 	getnobody();
355 
356 	if(dflag == 0)
357 		termset();
358 
359 	setsigs();
360 
361 	p = newproc();
362 	p->kstack = stackalloc(p, &tos);
363 
364 	pw = getpwuid(getuid());
365 	if(pw != nil)
366 		kstrdup(&eve, pw->pw_name);
367 	else
368 		print("cannot getpwuid\n");
369 
370 	p->env->uid = getuid();
371 	p->env->gid = getgid();
372 
373 	executeonnewstack(tos, emuinit, imod);
374 }
375 
376 int
377 readkbd(void)
378 {
379 	int n;
380 	char buf[1];
381 
382 	n = read(0, buf, sizeof(buf));
383 	if(n < 0)
384 		print("keyboard close (n=%d, %s)\n", n, strerror(errno));
385 	if(n <= 0)
386 		pexit("keyboard thread", 0);
387 
388 	switch(buf[0]) {
389 	case '\r':
390 		buf[0] = '\n';
391 		break;
392 	case DELETE:
393 		cleanexit(0);
394 		break;
395 	}
396 	return buf[0];
397 }
398 
399 /*
400  * Return an abitrary millisecond clock time
401  */
402 long
403 osmillisec(void)
404 {
405 	static long sec0 = 0, usec0;
406 	struct timeval t;
407 
408 	if(gettimeofday(&t,(struct timezone*)0)<0)
409 		return 0;
410 	if(sec0==0) {
411 		sec0 = t.tv_sec;
412 		usec0 = t.tv_usec;
413 	}
414 	return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000;
415 }
416 
417 int
418 limbosleep(ulong milsec)
419 {
420 	return osmillisleep(milsec);
421 }
422 
423 /*
424  * Return the time since the epoch in nanoseconds and microseconds
425  * The epoch is defined at 1 Jan 1970
426  */
427 vlong
428 osnsec(void)
429 {
430 	struct timeval t;
431 
432 	gettimeofday(&t, nil);
433 	return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
434 }
435 
436 vlong
437 osusectime(void)
438 {
439 	struct timeval t;
440 
441 	gettimeofday(&t, nil);
442 	return (vlong)t.tv_sec * 1000000 + t.tv_usec;
443 }
444 
445 int
446 osmillisleep(ulong milsec)
447 {
448 	struct timespec time;
449 
450 	time.tv_sec = milsec / 1000;
451 	time.tv_nsec = (milsec % 1000) * 1000000;
452 	nanosleep(&time, 0);
453 	return 0;
454 }
455 
456 void
457 osyield(void)
458 {
459 	sched_yield();
460 }
461 
462 void
463 ospause(void)
464 {
465 	for(;;)
466 		pause();
467 }
468 
469 void
470 oslopri(void)
471 {
472 	setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4);
473 }
474 
475 static struct {
476 	Lock l;
477 	void *free;
478 } stacklist;
479 
480 static void
481 _stackfree(void *stack)
482 {
483 	*((void **)stack) = stacklist.free;
484 	stacklist.free = stack;
485 }
486 
487 static void
488 stackfreeandexit(void *stack)
489 {
490 	lock(&stacklist.l);
491 	_stackfree(stack);
492 	unlockandexit(&stacklist.l.val);
493 }
494 
495 static void *
496 stackalloc(Proc *p, void **tos)
497 {
498 	void *rv;
499 	lock(&stacklist.l);
500 	if (stacklist.free == 0) {
501 		int x;
502 		/*
503 		 * obtain some more by using sbrk()
504 		 */
505 		void *more = sbrk(KSTACK * (NSTACKSPERALLOC + 1));
506 		if (more == 0)
507 			panic("stackalloc: no more stacks");
508 		/*
509 		 * align to KSTACK
510 		 */
511 		more = (void *)((((unsigned long)more) + (KSTACK - 1)) & ~(KSTACK - 1));
512 		/*
513 		 * free all the new stacks onto the freelist
514 		 */
515 		for (x = 0; x < NSTACKSPERALLOC; x++)
516 			_stackfree((char *)more + KSTACK * x);
517 	}
518 	rv = stacklist.free;
519 	stacklist.free = *(void **)rv;
520 	unlock(&stacklist.l);
521 	*tos = rv + KSTACK - sizeof(void*);
522 	*(Proc **)rv = p;
523 	return rv;
524 }
525 
526 int
527 segflush(void *a, ulong n)
528 {
529 	USED(a);
530 	USED(n);
531 	return 0;
532 }
533