xref: /inferno-os/emu/MacOSX/os.c (revision 5d0c4cf3fc288434c41cba52dd998ab1d7375a7b)
1 /*
2  * Loosely based on FreeBSD/os.c and Solaris/os.c
3  * Copyright © 1998, 1999 Lucent Technologies Inc.  All rights reserved.
4  * Revisions Copyright © 1999, 2000 Vita Nuova Limited.  All rights reserved.
5  * Revisions Copyright © 2002, 2003 Corpus Callosum Corporation.  All rights reserved.
6  */
7 
8 #include	"dat.h"
9 #include	"fns.h"
10 #include	"error.h"
11 
12 #include <raise.h>
13 
14 #undef _POSIX_C_SOURCE
15 #undef getwd
16 
17 #include	<unistd.h>
18 #include        <pthread.h>
19 #include	<time.h>
20 #include	<termios.h>
21 #include	<signal.h>
22 #include	<pwd.h>
23 #include	<sys/resource.h>
24 #include	<sys/time.h>
25 
26 #include 	<sys/socket.h>
27 #include	<sched.h>
28 #include	<errno.h>
29 #include        <sys/ucontext.h>
30 
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 
34 #include <mach/mach_init.h>
35 #include <mach/task.h>
36 #include <mach/vm_map.h>
37 
38 #if defined(__ppc__)
39 #include <architecture/ppc/cframe.h>
40 #endif
41 
42 enum
43 {
44     DELETE = 0x7F
45 };
46 char *hosttype = "MacOSX";
47 char *cputype = OBJTYPE;
48 
49 typedef struct Sem Sem;
50 struct Sem {
51 	pthread_cond_t	c;
52 	pthread_mutex_t	m;
53 	int	v;
54 };
55 
56 static pthread_key_t  prdakey;
57 
58 extern int dflag;
59 
60 Proc*
61 getup(void)
62 {
63 	return pthread_getspecific(prdakey);
64 }
65 
66 void
67 pexit(char *msg, int t)
68 {
69 	Osenv *e;
70 	Proc *p;
71 	Sem *sem;
72 
73 	USED(t);
74 	USED(msg);
75 
76 	lock(&procs.l);
77 	p = up;
78 	if(p->prev)
79 		p->prev->next = p->next;
80 	else
81 		procs.head = p->next;
82 
83 	if(p->next)
84 		p->next->prev = p->prev;
85 	else
86 		procs.tail = p->prev;
87 	unlock(&procs.l);
88 
89 	if(0)
90 		print("pexit: %s: %s\n", p->text, msg);
91 
92 	e = p->env;
93 	if(e != nil) {
94 		closefgrp(e->fgrp);
95 		closepgrp(e->pgrp);
96 		closeegrp(e->egrp);
97 		closesigs(e->sigs);
98 		free(e->user);
99 	}
100 	free(p->prog);
101 	sem = p->os;
102 	if(sem != nil){
103 		pthread_cond_destroy(&sem->c);
104 		pthread_mutex_destroy(&sem->m);
105 	}
106 	free(p->os);
107 	free(p);
108 	pthread_exit(0);
109 }
110 
111 
112 
113 static void
114 sysfault(char *what, void *addr)
115 {
116 	char buf[64];
117 
118 	snprint(buf, sizeof(buf), "sys: %s%#p", what, addr);
119 	disfault(nil, buf);
120 }
121 
122 static void
123 trapILL(int signo, siginfo_t *si, void *a)
124 {
125 	USED(signo);
126 	USED(a);
127 	sysfault("illegal instruction pc=", si->si_addr);
128 }
129 
130 static int
131 isnilref(siginfo_t *si)
132 {
133 	return si != 0 && (si->si_addr == (void*)~(uintptr_t)0 || (uintptr_t)si->si_addr < 512);
134 }
135 
136 static void
137 trapmemref(int signo, siginfo_t *si, void *a)
138 {
139 	USED(a);	/* ucontext_t*, could fetch pc in machine-dependent way */
140 	if(isnilref(si))
141 		disfault(nil, exNilref);
142 	else if(signo == SIGBUS)
143 		sysfault("bad address addr=", si->si_addr);	/* eg, misaligned */
144 	else
145 		sysfault("segmentation violation addr=", si->si_addr);
146 }
147 
148 static void
149 trapFPE(int signo, siginfo_t *si, void *a)
150 {
151 	char buf[64];
152 
153 	USED(signo);
154 	USED(a);
155 	snprint(buf, sizeof(buf), "sys: fp: exception status=%.4lux pc=%#p", getfsr(), si->si_addr);
156 	disfault(nil, buf);
157 }
158 
159 void
160 trapUSR1(int signo)
161 {
162     USED(signo);
163 
164     if(up->type != Interp)      /* Used to unblock pending I/O */
165         return;
166     if(up->intwait == 0)        /* Not posted so its a sync error */
167         disfault(nil, Eintr);	/* Should never happen */
168 
169     up->intwait = 0;		/* Clear it so the proc can continue */
170 }
171 
172 /* from geoff collyer's port */
173 void
174 printILL(int sig, siginfo_t *si, void *v)
175 {
176 	USED(sig);
177 	USED(v);
178 	panic("illegal instruction with code=%d at address=%p, opcode=%#x\n",
179 		si->si_code, si->si_addr, *(uchar*)si->si_addr);
180 }
181 
182 static void
183 setsigs(void)
184 {
185 	struct sigaction act;
186 
187 	memset(&act, 0 , sizeof(act));
188 
189 	/*
190 	  * For the correct functioning of devcmd in the
191 	 * face of exiting slaves
192 	 */
193 	signal(SIGPIPE, SIG_IGN);
194 	if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
195 		signal(SIGTERM, cleanexit);
196 
197 	act.sa_handler = trapUSR1;
198 	sigaction(SIGUSR1, &act, nil);
199 
200 	if(sflag == 0) {
201 		act.sa_flags = SA_SIGINFO;
202 		act.sa_sigaction = trapILL;
203 		sigaction(SIGILL, &act, nil);
204 		act.sa_sigaction = trapFPE;
205 		sigaction(SIGFPE, &act, nil);
206 		act.sa_sigaction = trapmemref;
207 		sigaction(SIGBUS, &act, nil);
208 		sigaction(SIGSEGV, &act, nil);
209 		if(signal(SIGINT, SIG_IGN) != SIG_IGN)
210 			signal(SIGINT, cleanexit);
211 	} else {
212 		act.sa_sigaction = printILL;
213 		act.sa_flags = SA_SIGINFO;
214 		sigaction(SIGILL, &act, nil);
215 	}
216 }
217 
218 
219 
220 
221 void *
222 tramp(void *arg)
223 {
224 	Proc *p = arg;
225 	p->sigid = (int)pthread_self();
226 	if(pthread_setspecific(prdakey, arg)) {
227 		print("set specific data failed in tramp\n");
228 		pthread_exit(0);
229 	}
230 	p->func(p->arg);
231 	pexit("{Tramp}", 0);
232 	return NULL;
233 }
234 
235 void
236 kproc(char *name, void (*func)(void*), void *arg, int flags)
237 {
238 	pthread_t thread;
239 	Proc *p;
240 	Pgrp *pg;
241 	Fgrp *fg;
242 	Egrp *eg;
243 	pthread_attr_t attr;
244 	Sem *sem;
245 
246 	p = newproc();
247 	if(p == nil)
248 		panic("kproc: no memory");
249 	sem = malloc(sizeof(*sem));
250 	if(sem == nil)
251 		panic("can't allocate semaphore");
252 	pthread_cond_init(&sem->c, NULL);
253 	pthread_mutex_init(&sem->m, NULL);
254 	sem->v = 0;
255 	p->os = sem;
256 
257 	if(flags & KPDUPPG) {
258 		pg = up->env->pgrp;
259 		incref(&pg->r);
260 		p->env->pgrp = pg;
261 	}
262 	if(flags & KPDUPFDG) {
263 		fg = up->env->fgrp;
264 		incref(&fg->r);
265 		p->env->fgrp = fg;
266 	}
267 	if(flags & KPDUPENVG) {
268 		eg = up->env->egrp;
269 		incref(&eg->r);
270 		p->env->egrp = eg;
271 	}
272 
273 	p->env->uid = up->env->uid;
274 	p->env->gid = up->env->gid;
275 	kstrdup(&p->env->user, up->env->user);
276 
277 	strcpy(p->text, name);
278 
279 	p->func = func;
280 	p->arg = arg;
281 
282 	lock(&procs.l);
283 	if(procs.tail != nil) {
284 		p->prev = procs.tail;
285 		procs.tail->next = p;
286 	} else {
287 		procs.head = p;
288 		p->prev = nil;
289 	}
290 	procs.tail = p;
291 	unlock(&procs.l);
292 
293 	if(pthread_attr_init(&attr) == -1)
294 		panic("pthread_attr_init failed");
295 
296 	pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
297 	pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
298 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
299 
300 	if(pthread_create(&thread, &attr, tramp, p))
301 		panic("thr_create failed\n");
302 	pthread_attr_destroy(&attr);
303 }
304 
305 int
306 segflush(void *va, ulong len)
307 {
308 	kern_return_t   err;
309 	vm_machine_attribute_val_t value = MATTR_VAL_ICACHE_FLUSH;
310 
311 	err = vm_machine_attribute( (vm_map_t)mach_task_self(),
312 		(vm_address_t)va,
313 		(vm_size_t)len,
314 		MATTR_CACHE,
315 		&value);
316 	if(err != KERN_SUCCESS)
317 		print("segflush: failure (%d) address %lud\n", err, va);
318 	return (int)err;
319 }
320 
321 void
322 oshostintr(Proc *p)
323 {
324 	pthread_kill((pthread_t)p->sigid, SIGUSR1);
325 }
326 
327 void
328 osblock(void)
329 {
330 	Sem *sem;
331 
332 	sem = up->os;
333 	pthread_mutex_lock(&sem->m);
334 	while(sem->v == 0)
335 		pthread_cond_wait(&sem->c, &sem->m);
336 	sem->v--;
337 	pthread_mutex_unlock(&sem->m);
338 }
339 
340 void
341 osready(Proc *p)
342 {
343 	Sem *sem;
344 
345 	sem = p->os;
346 	pthread_mutex_lock(&sem->m);
347 	sem->v++;
348 	pthread_cond_signal(&sem->c);
349 	pthread_mutex_unlock(&sem->m);
350 }
351 
352 void
353 oslongjmp(void *regs, osjmpbuf env, int val)
354 {
355 	USED(regs);
356 	siglongjmp(env, val);
357 }
358 
359 struct termios tinit;
360 
361 static void
362 termset(void)
363 {
364 	struct termios t;
365 
366 	tcgetattr(0, &t);
367 	tinit = t;
368 	t.c_lflag &= ~(ICANON | ECHO | ISIG);
369 	t.c_cc[VMIN] = 1;
370 	t.c_cc[VTIME] = 0;
371 	tcsetattr(0, TCSANOW, &t);
372 }
373 
374 static void
375 termrestore(void)
376 {
377 	tcsetattr(0, TCSANOW, &tinit);
378 }
379 
380 
381 void
382 cleanexit(int x)
383 {
384 	USED(x);
385 
386 	if(up->intwait) {
387 		up->intwait = 0;
388 		return;
389 	}
390 
391 	if(dflag == 0)
392 		termrestore();
393 
394 	exit(0);
395 }
396 
397 
398 
399 void
400 osreboot(char *file, char **argv)
401 {
402 	if(dflag == 0)
403 		termrestore();
404 	execvp(file, argv);
405 	panic("reboot failure");
406 }
407 
408 
409 
410 int gidnobody= -1, uidnobody= -1;
411 
412 void
413 getnobody()
414 {
415 	struct passwd *pwd;
416 
417 	if((pwd = getpwnam("nobody"))) {
418 		uidnobody = pwd->pw_uid;
419 		gidnobody = pwd->pw_gid;
420 	}
421 }
422 
423 void
424 libinit(char *imod)
425 {
426 	struct passwd *pw;
427 	Proc *p;
428 	char	sys[64];
429 
430 	setsid();
431 
432 	// setup personality
433 	gethostname(sys, sizeof(sys));
434 	kstrdup(&ossysname, sys);
435 	getnobody();
436 
437 	if(dflag == 0)
438 		termset();
439 
440 	setsigs();
441 
442 	if(pthread_key_create(&prdakey, NULL))
443 		print("key_create failed\n");
444 
445 	p = newproc();
446 	if(pthread_setspecific(prdakey, p))
447 		panic("set specific thread data failed\n");
448 
449 	pw = getpwuid(getuid());
450 	if(pw != nil)
451 		kstrdup(&eve, pw->pw_name);
452 	else
453 		print("cannot getpwuid\n");
454 
455 	up->env->uid = getuid();
456 	up->env->gid = getgid();
457 
458 	emuinit(imod);
459 }
460 
461 
462 
463 int
464 readkbd(void)
465 {
466 	int	n;
467 	char	buf[1];
468 
469 	n = read(0, buf, sizeof(buf));
470 	if(n < 0)
471 		print("keyboard close (n=%d, %s)\n", n, strerror(errno));
472 	if(n <= 0)
473 		pexit("keyboard thread", 0);
474 
475 	switch(buf[0]) {
476 	case '\r':
477 		buf[0] = '\n';
478 		break;
479 	case DELETE:
480 		cleanexit(0);
481 		break;
482 	}
483 	return buf[0];
484 }
485 
486 /*
487  * Return an abitrary millisecond clock time
488  */
489 long
490 osmillisec(void)
491 {
492 	static long	sec0 = 0, usec0;
493 	struct timeval t;
494 
495 	if(gettimeofday(&t, NULL) < 0)
496 		return(0);
497 	if(sec0 == 0) {
498 		sec0 = t.tv_sec;
499 		usec0 = t.tv_usec;
500 	}
501 	return((t.tv_sec - sec0) * 1000 + (t.tv_usec - usec0 + 500) / 1000);
502 }
503 
504 /*
505  * Return the time since the epoch in nanoseconds and microseconds
506  * The epoch is defined at 1 Jan 1970
507  */
508 vlong
509 osnsec(void)
510 {
511 	struct timeval t;
512 
513 	gettimeofday(&t, nil);
514 	return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
515 }
516 
517 vlong
518 osusectime(void)
519 {
520 	struct timeval t;
521 
522 	gettimeofday(&t, nil);
523 	return (vlong)t.tv_sec * 1000000 + t.tv_usec;
524 }
525 int
526 osmillisleep(ulong milsec)
527 {
528 	struct timespec time;
529 	time.tv_sec = milsec / 1000;
530 	time.tv_nsec = (milsec % 1000) * 1000000;
531 	nanosleep(&time, nil);
532 	return 0;
533 }
534 
535 int
536 limbosleep(ulong milsec)
537 {
538 	return osmillisleep(milsec);
539 }
540 
541 void
542 osyield(void)
543 {
544 	pthread_yield_np();
545 }
546 
547 void
548 ospause(void)
549 {
550 	for(;;)
551 		pause();
552 }
553 
554 void
555 oslopri(void)
556 {
557 //	pthread_setschedparam(pthread_t thread,  int policy, const struct sched_param *param);
558 	setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4);
559 }
560 
561 __typeof__(sbrk(0))
562 sbrk(int size)
563 {
564 	void *brk;
565 	kern_return_t   err;
566 
567 	err = vm_allocate( (vm_map_t) mach_task_self(),
568                        (vm_address_t *)&brk,
569                        size,
570                        VM_FLAGS_ANYWHERE);
571 	if(err != KERN_SUCCESS)
572 		brk = (void*)-1;
573 	return brk;
574 }
575