xref: /inferno-os/emu/MacOSX/os.c (revision 90ccc69f5be0b7e26c3607dac07340fe3e271509)
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 int
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 	up->kid = p;
295 
296 	if(pthread_attr_init(&attr) == -1)
297 		panic("pthread_attr_init failed");
298 
299 	errno = 0;
300 	pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
301 	if(errno)
302 		panic("pthread_attr_setschedpolicy failed");
303 
304 	pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
305 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
306 
307 	if(pthread_create(&thread, &attr, tramp, p))
308 		panic("thr_create failed\n");
309 	pthread_attr_destroy(&attr);
310 
311 	return (int)thread;
312 }
313 
314 int
315 segflush(void *va, ulong len)
316 {
317 	kern_return_t   err;
318 	vm_machine_attribute_val_t value = MATTR_VAL_ICACHE_FLUSH;
319 
320 	err = vm_machine_attribute( (vm_map_t)mach_task_self(),
321 		(vm_address_t)va,
322 		(vm_size_t)len,
323 		MATTR_CACHE,
324 		&value);
325 	if(err != KERN_SUCCESS)
326 		print("segflush: failure (%d) address %lud\n", err, va);
327 	return (int)err;
328 }
329 
330 void
331 oshostintr(Proc *p)
332 {
333 fprint(2, "oshostintr %p\n", p);
334 	pthread_kill((pthread_t)p->sigid, SIGUSR1);
335 }
336 
337 void
338 osblock(void)
339 {
340 	Sem *sem;
341 
342 	sem = up->os;
343 	pthread_mutex_lock(&sem->m);
344 	while(sem->v == 0)
345 		pthread_cond_wait(&sem->c, &sem->m);
346 	sem->v--;
347 	pthread_mutex_unlock(&sem->m);
348 }
349 
350 void
351 osready(Proc *p)
352 {
353 	Sem *sem;
354 
355 	sem = p->os;
356 	pthread_mutex_lock(&sem->m);
357 	sem->v++;
358 	pthread_cond_signal(&sem->c);
359 	pthread_mutex_unlock(&sem->m);
360 }
361 
362 void
363 oslongjmp(void *regs, osjmpbuf env, int val)
364 {
365 	USED(regs);
366 	siglongjmp(env, val);
367 }
368 
369 struct termios tinit;
370 
371 static void
372 termset(void)
373 {
374 	struct termios t;
375 
376 	tcgetattr(0, &t);
377 	tinit = t;
378 	t.c_lflag &= ~(ICANON | ECHO | ISIG);
379 	t.c_cc[VMIN] = 1;
380 	t.c_cc[VTIME] = 0;
381 	tcsetattr(0, TCSANOW, &t);
382 }
383 
384 static void
385 termrestore(void)
386 {
387 	tcsetattr(0, TCSANOW, &tinit);
388 }
389 
390 
391 void
392 cleanexit(int x)
393 {
394 	USED(x);
395 
396 	if(up->intwait) {
397 		up->intwait = 0;
398 		return;
399 	}
400 
401 	if(dflag == 0)
402 		termrestore();
403 
404 	exit(0);
405 }
406 
407 
408 
409 void
410 osreboot(char *file, char **argv)
411 {
412 	if(dflag == 0)
413 		termrestore();
414 	execvp(file, argv);
415 	panic("reboot failure");
416 }
417 
418 
419 
420 int gidnobody= -1, uidnobody= -1;
421 
422 void
423 getnobody()
424 {
425 	struct passwd *pwd;
426 
427 	if((pwd = getpwnam("nobody"))) {
428 		uidnobody = pwd->pw_uid;
429 		gidnobody = pwd->pw_gid;
430 	}
431 }
432 
433 void
434 libinit(char *imod)
435 {
436 	struct passwd *pw;
437 	Proc *p;
438 	char	sys[64];
439 
440 	setsid();
441 
442 	// setup personality
443 	gethostname(sys, sizeof(sys));
444 	kstrdup(&ossysname, sys);
445 	getnobody();
446 
447 	if(dflag == 0)
448 		termset();
449 
450 	setsigs();
451 
452 	if(pthread_key_create(&prdakey, NULL))
453 		print("key_create failed\n");
454 
455 	p = newproc();
456 	if(pthread_setspecific(prdakey, p))
457 		panic("set specific thread data failed\n");
458 
459 	pw = getpwuid(getuid());
460 	if(pw != nil)
461 		kstrdup(&eve, pw->pw_name);
462 	else
463 		print("cannot getpwuid\n");
464 
465 	up->env->uid = getuid();
466 	up->env->gid = getgid();
467 
468 	emuinit(imod);
469 }
470 
471 
472 
473 int
474 readkbd(void)
475 {
476 	int	n;
477 	char	buf[1];
478 
479 	n = read(0, buf, sizeof(buf));
480 	if(n < 0)
481 		print("keyboard close (n=%d, %s)\n", n, strerror(errno));
482 	if(n <= 0)
483 		pexit("keyboard thread", 0);
484 
485 	switch(buf[0]) {
486 	case '\r':
487 		buf[0] = '\n';
488 		break;
489 	case DELETE:
490 		cleanexit(0);
491 		break;
492 	}
493 	return buf[0];
494 }
495 
496 /*
497  * Return an abitrary millisecond clock time
498  */
499 long
500 osmillisec(void)
501 {
502 	static long	sec0 = 0, usec0;
503 	struct timeval t;
504 
505 	if(gettimeofday(&t, NULL) < 0)
506 		return(0);
507 	if(sec0 == 0) {
508 		sec0 = t.tv_sec;
509 		usec0 = t.tv_usec;
510 	}
511 	return((t.tv_sec - sec0) * 1000 + (t.tv_usec - usec0 + 500) / 1000);
512 }
513 
514 /*
515  * Return the time since the epoch in nanoseconds and microseconds
516  * The epoch is defined at 1 Jan 1970
517  */
518 vlong
519 osnsec(void)
520 {
521 	struct timeval t;
522 
523 	gettimeofday(&t, nil);
524 	return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
525 }
526 
527 vlong
528 osusectime(void)
529 {
530 	struct timeval t;
531 
532 	gettimeofday(&t, nil);
533 	return (vlong)t.tv_sec * 1000000 + t.tv_usec;
534 }
535 int
536 osmillisleep(ulong milsec)
537 {
538 	struct timespec time;
539 	time.tv_sec = milsec / 1000;
540 	time.tv_nsec = (milsec % 1000) * 1000000;
541 	nanosleep(&time, nil);
542 	return 0;
543 }
544 
545 int
546 limbosleep(ulong milsec)
547 {
548 	return osmillisleep(milsec);
549 }
550 
551 void
552 osyield(void)
553 {
554 	pthread_yield_np();
555 }
556 
557 void
558 ospause(void)
559 {
560 	for(;;)
561 		pause();
562 }
563 
564 void
565 oslopri(void)
566 {
567 //	pthread_setschedparam(pthread_t thread,  int policy, const struct sched_param *param);
568 	setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4);
569 }
570 
571 __typeof__(sbrk(0))
572 sbrk(int size)
573 {
574 	void *brk;
575 	kern_return_t   err;
576 
577 	err = vm_allocate( (vm_map_t) mach_task_self(),
578                        (vm_address_t *)&brk,
579                        size,
580                        VM_FLAGS_ANYWHERE);
581 	if(err != KERN_SUCCESS)
582 		brk = (void*)-1;
583 	return brk;
584 }
585