xref: /inferno-os/emu/Linux/os.c (revision 1e1b493dfc048d301ef6b41377f0a3665ee7f3fc)
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	<stdint.h>
12 
13 #include	"dat.h"
14 #include	"fns.h"
15 #include	"error.h"
16 #include <fpuctl.h>
17 
18 #include <semaphore.h>
19 
20 #include	<raise.h>
21 
22 /* glibc 2.3.3-NTPL messes up getpid() by trying to cache the result, so we'll do it ourselves */
23 #include	<sys/syscall.h>
24 #define	getpid()	syscall(SYS_getpid)
25 
26 enum
27 {
28 	DELETE	= 0x7f,
29 	CTRLC	= 'C'-'@',
30 	NSTACKSPERALLOC = 16,
31 	X11STACK=	256*1024
32 };
33 char *hosttype = "Linux";
34 
35 typedef sem_t	Sem;
36 
37 extern int dflag;
38 
39 int	gidnobody = -1;
40 int	uidnobody = -1;
41 static struct 	termios tinit;
42 
43 static void
44 sysfault(char *what, void *addr)
45 {
46 	char buf[64];
47 
48 	snprint(buf, sizeof(buf), "sys: %s%#p", what, addr);
49 	disfault(nil, buf);
50 }
51 
52 static void
53 trapILL(int signo, siginfo_t *si, void *a)
54 {
55 	USED(signo);
56 	USED(a);
57 	sysfault("illegal instruction pc=", si->si_addr);
58 }
59 
60 static int
61 isnilref(siginfo_t *si)
62 {
63 	return si != 0 && (si->si_addr == (void*)~(uintptr_t)0 || (uintptr_t)si->si_addr < 512);
64 }
65 
66 static void
67 trapmemref(int signo, siginfo_t *si, void *a)
68 {
69 	USED(a);	/* ucontext_t*, could fetch pc in machine-dependent way */
70 	if(isnilref(si))
71 		disfault(nil, exNilref);
72 	else if(signo == SIGBUS)
73 		sysfault("bad address addr=", si->si_addr);	/* eg, misaligned */
74 	else
75 		sysfault("segmentation violation addr=", si->si_addr);
76 }
77 
78 static void
79 trapFPE(int signo, siginfo_t *si, void *a)
80 {
81 	char buf[64];
82 
83 	USED(signo);
84 	USED(a);
85 	snprint(buf, sizeof(buf), "sys: fp: exception status=%.4lux pc=%#p", getfsr(), si->si_addr);
86 	disfault(nil, buf);
87 }
88 
89 static void
90 trapUSR1(int signo)
91 {
92 	int intwait;
93 
94 	USED(signo);
95 
96 	intwait = up->intwait;
97 	up->intwait = 0;	/* clear it to let proc continue in osleave */
98 
99 	if(up->type != Interp)		/* Used to unblock pending I/O */
100 		return;
101 
102 	if(intwait == 0)		/* Not posted so it's a sync error */
103 		disfault(nil, Eintr);	/* Should never happen */
104 }
105 
106 void
107 oslongjmp(void *regs, osjmpbuf env, int val)
108 {
109 	USED(regs);
110 	siglongjmp(env, val);
111 }
112 
113 static void
114 termset(void)
115 {
116 	struct termios t;
117 
118 	tcgetattr(0, &t);
119 	tinit = t;
120 	t.c_lflag &= ~(ICANON|ECHO|ISIG);
121 	t.c_cc[VMIN] = 1;
122 	t.c_cc[VTIME] = 0;
123 	tcsetattr(0, TCSANOW, &t);
124 }
125 
126 static void
127 termrestore(void)
128 {
129 	tcsetattr(0, TCSANOW, &tinit);
130 }
131 
132 void
133 cleanexit(int x)
134 {
135 	USED(x);
136 
137 	if(up->intwait) {
138 		up->intwait = 0;
139 		return;
140 	}
141 
142 	if(dflag == 0)
143 		termrestore();
144 
145 	kill(0, SIGKILL);
146 	exit(0);
147 }
148 
149 void
150 osreboot(char *file, char **argv)
151 {
152 	if(dflag == 0)
153 		termrestore();
154 	execvp(file, argv);
155 	error("reboot failure");
156 }
157 
158 void
159 libinit(char *imod)
160 {
161 	struct sigaction act;
162 	struct passwd *pw;
163 	Proc *p;
164 	char sys[64];
165 
166 	setsid();
167 
168 	gethostname(sys, sizeof(sys));
169 	kstrdup(&ossysname, sys);
170 	pw = getpwnam("nobody");
171 	if(pw != nil) {
172 		uidnobody = pw->pw_uid;
173 		gidnobody = pw->pw_gid;
174 	}
175 
176 	if(dflag == 0)
177 		termset();
178 
179 	memset(&act, 0, sizeof(act));
180 	act.sa_handler = trapUSR1;
181 	sigaction(SIGUSR1, &act, nil);
182 
183 	act.sa_handler = SIG_IGN;
184 	sigaction(SIGCHLD, &act, nil);
185 
186 	/*
187 	 * For the correct functioning of devcmd in the
188 	 * face of exiting slaves
189 	 */
190 	signal(SIGPIPE, SIG_IGN);
191 	if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
192 		signal(SIGTERM, cleanexit);
193 	if(signal(SIGINT, SIG_IGN) != SIG_IGN)
194 		signal(SIGINT, cleanexit);
195 
196 	if(sflag == 0) {
197 		act.sa_flags = SA_SIGINFO;
198 		act.sa_sigaction = trapILL;
199 		sigaction(SIGILL, &act, nil);
200 		act.sa_sigaction = trapFPE;
201 		sigaction(SIGFPE, &act, nil);
202 		act.sa_sigaction = trapmemref;
203 		sigaction(SIGBUS, &act, nil);
204 		sigaction(SIGSEGV, &act, nil);
205 		act.sa_flags &= ~SA_SIGINFO;
206 	}
207 
208 	p = newproc();
209 	kprocinit(p);
210 
211 	pw = getpwuid(getuid());
212 	if(pw != nil)
213 		kstrdup(&eve, pw->pw_name);
214 	else
215 		print("cannot getpwuid\n");
216 
217 	p->env->uid = getuid();
218 	p->env->gid = getgid();
219 
220 	emuinit(imod);
221 }
222 
223 int
224 readkbd(void)
225 {
226 	int n;
227 	char buf[1];
228 
229 	n = read(0, buf, sizeof(buf));
230 	if(n < 0)
231 		print("keyboard close (n=%d, %s)\n", n, strerror(errno));
232 	if(n <= 0)
233 		pexit("keyboard thread", 0);
234 
235 	switch(buf[0]) {
236 	case '\r':
237 		buf[0] = '\n';
238 		break;
239 	case DELETE:
240 		buf[0] = 'H' - '@';
241 		break;
242 	case CTRLC:
243 		cleanexit(0);
244 		break;
245 	}
246 	return buf[0];
247 }
248 
249 /*
250  * Return an abitrary millisecond clock time
251  */
252 long
253 osmillisec(void)
254 {
255 	static long sec0 = 0, usec0;
256 	struct timeval t;
257 
258 	if(gettimeofday(&t,(struct timezone*)0)<0)
259 		return 0;
260 
261 	if(sec0 == 0) {
262 		sec0 = t.tv_sec;
263 		usec0 = t.tv_usec;
264 	}
265 	return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000;
266 }
267 
268 /*
269  * Return the time since the epoch in nanoseconds and microseconds
270  * The epoch is defined at 1 Jan 1970
271  */
272 vlong
273 osnsec(void)
274 {
275 	struct timeval t;
276 
277 	gettimeofday(&t, nil);
278 	return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
279 }
280 
281 vlong
282 osusectime(void)
283 {
284 	struct timeval t;
285 
286 	gettimeofday(&t, nil);
287 	return (vlong)t.tv_sec * 1000000 + t.tv_usec;
288 }
289 
290 int
291 osmillisleep(ulong milsec)
292 {
293 	struct  timespec time;
294 
295 	time.tv_sec = milsec/1000;
296 	time.tv_nsec= (milsec%1000)*1000000;
297 	nanosleep(&time, NULL);
298 	return 0;
299 }
300 
301 int
302 limbosleep(ulong milsec)
303 {
304 	return osmillisleep(milsec);
305 }
306