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