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