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