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