xref: /inferno-os/emu/Linux/os.c (revision a60fa48ce2f27a689f276bea9538b5db2b74ff86)
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(void*);
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 }
295 
296 void
297 libinit(char *imod)
298 {
299 	struct termios t;
300 	struct sigaction act;
301 	sigset_t mask;
302 	struct passwd *pw;
303 	Proc *p;
304 	void *tos;
305 	char sys[64];
306 
307 	setsid();
308 
309 	gethostname(sys, sizeof(sys));
310 	kstrdup(&ossysname, sys);
311 	pw = getpwnam("nobody");
312 	if(pw != nil) {
313 		uidnobody = pw->pw_uid;
314 		gidnobody = pw->pw_gid;
315 	}
316 
317 	if(dflag == 0)
318 		termset();
319 
320 	memset(&act, 0 , sizeof(act));
321 	act.sa_handler = trapUSR1;
322 	sigaction(SIGUSR1, &act, nil);
323 
324 	sigemptyset(&mask);
325 	sigaddset(&mask, SIGUSR2);
326 	sigprocmask(SIG_BLOCK, &mask, NULL);
327 
328 	memset(&act, 0 , sizeof(act));
329 	act.sa_handler = trapUSR2;
330 	sigaction(SIGUSR2, &act, nil);
331 
332 	act.sa_handler = SIG_IGN;
333 	sigaction(SIGCHLD, &act, nil);
334 
335 	/*
336 	 * For the correct functioning of devcmd in the
337 	 * face of exiting slaves
338 	 */
339 	signal(SIGPIPE, SIG_IGN);
340 	if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
341 		signal(SIGTERM, cleanexit);
342 	if(signal(SIGINT, SIG_IGN) != SIG_IGN)
343 		signal(SIGINT, cleanexit);
344 
345 	if(sflag == 0) {
346 		act.sa_handler = trapBUS;
347 		sigaction(SIGBUS, &act, nil);
348 		act.sa_handler = trapILL;
349 		sigaction(SIGILL, &act, nil);
350 		act.sa_handler = trapSEGV;
351 		sigaction(SIGSEGV, &act, nil);
352 		act.sa_handler = trapFPE;
353 		sigaction(SIGFPE, &act, nil);
354 	}
355 
356 	p = newproc();
357 	p->kstack = stackalloc(p, &tos);
358 
359 	pw = getpwuid(getuid());
360 	if(pw != nil)
361 		kstrdup(&eve, pw->pw_name);
362 	else
363 		print("cannot getpwuid\n");
364 
365 	p->env->uid = getuid();
366 	p->env->gid = getgid();
367 
368 	executeonnewstack(tos, emuinit, imod);
369 }
370 
371 int
372 readkbd(void)
373 {
374 	int n;
375 	char buf[1];
376 
377 	n = read(0, buf, sizeof(buf));
378 	if(n < 0)
379 		print("keyboard close (n=%d, %s)\n", n, strerror(errno));
380 	if(n <= 0)
381 		pexit("keyboard thread", 0);
382 
383 	switch(buf[0]) {
384 	case '\r':
385 		buf[0] = '\n';
386 		break;
387 	case DELETE:
388 		buf[0] = 'H' - '@';
389 		break;
390 	case CTRLC:
391 		cleanexit(0);
392 		break;
393 	}
394 	return buf[0];
395 }
396 
397 /*
398  * Return an abitrary millisecond clock time
399  */
400 long
401 osmillisec(void)
402 {
403 	static long sec0 = 0, usec0;
404 	struct timeval t;
405 
406 	if(gettimeofday(&t,(struct timezone*)0)<0)
407 		return 0;
408 
409 	if(sec0 == 0) {
410 		sec0 = t.tv_sec;
411 		usec0 = t.tv_usec;
412 	}
413 	return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000;
414 }
415 
416 /*
417  * Return the time since the epoch in nanoseconds and microseconds
418  * The epoch is defined at 1 Jan 1970
419  */
420 vlong
421 osnsec(void)
422 {
423 	struct timeval t;
424 
425 	gettimeofday(&t, nil);
426 	return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
427 }
428 
429 vlong
430 osusectime(void)
431 {
432 	struct timeval t;
433 
434 	gettimeofday(&t, nil);
435 	return (vlong)t.tv_sec * 1000000 + t.tv_usec;
436 }
437 
438 int
439 osmillisleep(ulong milsec)
440 {
441 	struct  timespec time;
442 
443 	time.tv_sec = milsec/1000;
444 	time.tv_nsec= (milsec%1000)*1000000;
445 	nanosleep(&time, NULL);
446 	return 0;
447 }
448 
449 int
450 limbosleep(ulong milsec)
451 {
452 	return osmillisleep(milsec);
453 }
454 
455 void
456 osyield(void)
457 {
458 	sched_yield();
459 }
460 
461 void
462 ospause(void)
463 {
464 	for(;;)
465 		pause();
466 }
467 
468 void
469 oslopri(void)
470 {
471 	setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4);
472 }
473 
474 static struct {
475 	Lock l;
476 	void *free;
477 } stacklist;
478 
479 static void
480 _stackfree(void *stack)
481 {
482 	*((void **)stack) = stacklist.free;
483 	stacklist.free = stack;
484 }
485 
486 static void
487 stackfreeandexit(void *stack)
488 {
489 	lock(&stacklist.l);
490 	_stackfree(stack);
491 	unlockandexit(&stacklist.l.val);
492 }
493 
494 static void *
495 stackalloc(Proc *p, void **tos)
496 {
497 	void *rv;
498 	lock(&stacklist.l);
499 	if (stacklist.free == 0) {
500 		int x;
501 		/*
502 		 * obtain some more by using sbrk()
503 		 */
504 		void *more = sbrk(KSTACK * (NSTACKSPERALLOC + 1));
505 		if (more == 0)
506 			panic("stackalloc: no more stacks");
507 		/*
508 		 * align to KSTACK
509 		 */
510 		more = (void *)((((unsigned long)more) + (KSTACK - 1)) & ~(KSTACK - 1));
511 		/*
512 		 * free all the new stacks onto the freelist
513 		 */
514 		for (x = 0; x < NSTACKSPERALLOC; x++)
515 			_stackfree((char *)more + KSTACK * x);
516 	}
517 	rv = stacklist.free;
518 	stacklist.free = *(void **)rv;
519 	unlock(&stacklist.l);
520 	*tos = rv + KSTACK - sizeof(void *);
521 	*(Proc **)rv = p;
522 	return rv;
523 }
524 
525 #ifdef LINUX_ARM
526 #define	SYS_cacheflush	__ARM_NR_cacheflush
527 
528 int
529 segflush(void *a, ulong n)
530 {
531 	if(n)
532 		syscall(SYS_cacheflush, a, (char*)a+n-1, 1);
533 	return 0;
534 }
535 #endif
536