0.6.7.22: removed CVS dollar-Header-dollar tags from sources
[sbcl.git] / src / runtime / bsd-os.c
1 /*
2  * OS-dependent routines for BSD-ish systems
3  *
4  * This file (along with os.h) exports an OS-independent interface to
5  * the operating system VM facilities. This interface looks a lot like
6  * the Mach interface (but simpler in some places). For some operating
7  * systems, a subset of these functions will have to be emulated.
8  */
9
10 /*
11  * This software is part of the SBCL system. See the README file for
12  * more information.
13  *
14  * This software is derived from the CMU CL system, which was
15  * written at Carnegie Mellon University and released into the
16  * public domain. The software is in the public domain and is
17  * provided with absolutely no warranty. See the COPYING and CREDITS
18  * files for more information.
19  */
20
21 #include <stdio.h>
22 #include <sys/param.h>
23 #include <sys/file.h>
24 #include "./signal.h"
25 #include "os.h"
26 #include "arch.h"
27 #include "globals.h"
28 #include "interrupt.h"
29 #include "lispregs.h"
30 #include "sbcl.h"
31
32 #include <sys/types.h>
33 #include <signal.h>
34 /* #include <sys/sysinfo.h> */
35 #include <sys/proc.h>
36 #include "validate.h"
37 vm_size_t os_vm_page_size;
38
39 #if defined GENCGC
40 #include "gencgc.h"
41 #endif
42
43 /* The different BSD variants have diverged in exactly where they
44  * store signal context information, but at least they tend to use the
45  * same stems to name the structure fields, so by using this macro we
46  * can share a fair amount of code between different variants. */
47 #if defined __FreeBSD__
48 #define CONTEXT_ADDR_FROM_STEM(stem) &context->uc_mcontext.mc_ ## stem
49 #elif defined __OpenBSD__
50 #define CONTEXT_ADDR_FROM_STEM(stem) &context->sc_ ## stem
51 #else
52 #error unsupported BSD variant
53 #endif
54 \f
55 void
56 os_init(void)
57 {
58     os_vm_page_size = getpagesize();
59 }
60
61 /* KLUDGE: There is strong family resemblance in the signal context
62  * stuff in FreeBSD and OpenBSD, but in detail they're different in
63  * almost every line of code. It would be nice to find some way to
64  * factor out the commonality better; failing that, it might be best
65  * just to split this generic-BSD code into one variant for each BSD. */
66    
67 int *
68 os_context_register_addr(os_context_t *context, int offset)
69 {
70     switch(offset) {
71     case  0:
72         return CONTEXT_ADDR_FROM_STEM(eax);
73     case  2:
74         return CONTEXT_ADDR_FROM_STEM(ecx);
75     case  4:
76         return CONTEXT_ADDR_FROM_STEM(edx);
77     case  6:
78         return CONTEXT_ADDR_FROM_STEM(ebx);
79     case  8:
80         return CONTEXT_ADDR_FROM_STEM(esp);
81     case 10:
82         return CONTEXT_ADDR_FROM_STEM(ebp);
83     case 12:
84         return CONTEXT_ADDR_FROM_STEM(esi);
85     case 14:
86         return CONTEXT_ADDR_FROM_STEM(edi);
87     default:
88         return 0;
89     }
90 }
91
92 int *
93 os_context_pc_addr(os_context_t *context)
94 {
95 #if defined __FreeBSD__
96     return CONTEXT_ADDR_FROM_STEM(eip);
97 #elif defined __OpenBSD__
98     return CONTEXT_ADDR_FROM_STEM(pc);
99 #else
100 #error unsupported BSD variant
101 #endif
102 }
103
104 int *
105 os_context_sp_addr(os_context_t *context)
106 {
107     return CONTEXT_ADDR_FROM_STEM(esp);
108 }
109
110 sigset_t *
111 os_context_sigmask_addr(os_context_t *context)
112 {
113     /* (Unlike most of the other context fields that we access, the
114      * signal mask field is a field of the basic, outermost context
115      * struct itself both in FreeBSD 4.0 and in OpenBSD 2.6.) */
116 #if defined __FreeBSD__
117     return &context->uc_sigmask;
118 #elif defined __OpenBSD__
119     return &context->sc_mask;
120 #else
121 #error unsupported BSD variant
122 #endif
123 }
124
125 os_vm_address_t
126 os_validate(os_vm_address_t addr, os_vm_size_t len)
127 {
128     int flags = MAP_PRIVATE | MAP_ANON;
129
130     if (addr)
131         flags |= MAP_FIXED;
132
133     addr = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
134
135     if (addr == MAP_FAILED) {
136         perror("mmap");
137         return NULL;
138     }
139
140     return addr;
141 }
142
143 void
144 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
145 {
146     if (munmap(addr, len) == -1)
147         perror("munmap");
148 }
149
150 os_vm_address_t
151 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
152 {
153     addr = mmap(addr, len,
154                 OS_VM_PROT_ALL,
155                 MAP_PRIVATE | MAP_FILE | MAP_FIXED,
156                 fd, (off_t) offset);
157
158     if (addr == MAP_FAILED) {
159         perror("mmap");
160         lose("unexpected mmap(..) failure");
161     }
162
163     return addr;
164 }
165
166 void
167 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
168 {
169 }
170
171 void
172 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
173 {
174     if (mprotect(address, length, prot) == -1) {
175         perror("mprotect");
176     }
177 }
178 \f
179 static boolean
180 in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
181 {
182     char* beg = (char*) sbeg;
183     char* end = (char*) sbeg + slen;
184     char* adr = (char*) a;
185     return (adr >= beg && adr < end);
186 }
187
188 boolean
189 is_valid_lisp_addr(os_vm_address_t addr)
190 {
191     return in_range_p(addr, READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE)
192         || in_range_p(addr, STATIC_SPACE_START   , STATIC_SPACE_SIZE   )
193         || in_range_p(addr, DYNAMIC_SPACE_START  , DYNAMIC_SPACE_SIZE  )
194         || in_range_p(addr, CONTROL_STACK_START  , CONTROL_STACK_SIZE  )
195         || in_range_p(addr, BINDING_STACK_START  , BINDING_STACK_SIZE  );
196 }
197 \f
198 /*
199  * any OS-dependent special low-level handling for signals
200  */
201
202 #if !defined GENCGC
203
204 void
205 os_install_interrupt_handlers(void)
206 {}
207
208 #else
209
210 /*
211  * The GENCGC needs to be hooked into whatever signal is raised for
212  * page fault on this OS.
213  */
214 static void
215 memory_fault_handler(int signal, siginfo_t *siginfo, void *void_context)
216 {
217     /* The way that we extract low level information like the fault
218      * address is not specified by POSIX. */
219 #if defined __FreeBSD__
220     void *fault_addr = siginfo->si_addr;
221 #elif defined __OpenBSD__
222     void *fault_addr = siginfo->si_addr;
223 #else
224 #error unsupported BSD variant
225 #endif
226     if (!gencgc_handle_wp_violation(fault_addr)) {
227         interrupt_handle_now(signal, siginfo, void_context);
228     }
229 }
230 void
231 os_install_interrupt_handlers(void)
232 {
233 #if defined __FreeBSD__
234     interrupt_install_low_level_handler(SIGBUS, memory_fault_handler);
235 #elif defined __OpenBSD__
236     interrupt_install_low_level_handler(SIGSEGV, memory_fault_handler);
237 #else
238 #error unsupported BSD variant
239 #endif
240 }
241
242 #endif /* !defined GENCGC */
243 \f
244 /*
245  * stuff to help work with dynamically linked libraries
246  */
247
248 /* feh!
249  *
250  * DL_WORKAROUND enables "stubbing" of various functions from libc et
251  * al. This is necessary when using dynamic linking in FreeBSD, as the
252  * symbols in the dynamic libraries will not have known addresses (in
253  * sbcl.nm).
254  *
255  * FIXME: This flag should be set in Config.bsd */
256 #if defined __FreeBSD__
257 #define DL_WORKAROUND 1
258 #elif defined __OpenBSD__
259 /* SBCL doesn't (yet?) work at all with dynamic libs on OpenBSD, so we
260  * wouldn't get any use out of these stubs. -- WHN 20001001 */
261 #define DL_WORKAROUND 0
262 #else
263 #error unsupported BSD variant
264 #endif
265
266 #if DL_WORKAROUND
267 #include <unistd.h>
268 #include <dlfcn.h>
269 #include <math.h>
270 #include <sys/types.h>
271 #include <dirent.h>
272 #include <stdlib.h>
273 #include <sys/stat.h>
274 #include <time.h>
275 #include <sys/resource.h>
276 #include <signal.h>
277 #include <fcntl.h>
278
279 void *ldso_stub__dlopen(const char *path, int mode)
280 {
281   return dlopen(path, mode);
282 }
283
284 void *ldso_stub__dlsym(void *handle, const char *symbol)
285 {
286   return dlsym(handle, symbol);
287 }
288
289 const char *ldso_stub__dlerror(void)
290 {
291   return dlerror();
292 }
293 int ldso_stub__access(const char *path, int mode)
294 {
295   return access(path, mode);
296 }
297
298 double ldso_stub__acos(double x)
299 {
300   return acos(x);
301 }
302
303 double ldso_stub__acosh(double x)
304 {
305   return acosh(x);
306 }
307
308 double ldso_stub__asin(double x)
309 {
310   return asin(x);
311 }
312
313 double ldso_stub__asinh(double x)
314 {
315   return asin(x);
316 }
317
318 double ldso_stub__atanh(double x)
319 {
320   return atanh(x);
321 }
322
323
324 int ldso_stub__chdir(const char *path)
325 {
326   return chdir(path);
327 }
328
329 int ldso_stub__close(int d)
330 {
331   return close(d);
332 }
333
334 int ldso_stub__closedir(DIR *dirp)
335 {
336   return closedir(dirp);
337 }
338
339 double ldso_stub__cosh(double x)
340 {
341   return cosh(x);
342 }
343
344 void ldso_stub__exit(int status)
345 {
346   exit(status);
347 }
348
349 void ldso_stub__free(void *ptr)
350 {
351   free(ptr);
352 }
353
354 int ldso_stub__fstat(int fd, struct stat *sb)
355 {
356   return fstat(fd, sb);
357 }
358
359 int ldso_stub__fsync(int fd)
360 {
361   return fsync(fd);
362 }
363
364 char *ldso_stub__getenv(const char *name)
365 {
366   return getenv(name);
367 }
368
369 int ldso_stub__gethostname(char *name, int namelen)
370 {
371   return gethostname(name, namelen);
372 }
373
374 pid_t ldso_stub__getpid(void)
375 {
376   return getpid();
377 }
378
379 int ldso_stub__getrusage(int who, struct rusage *rusage)
380 {
381   return getrusage(who, rusage);
382 }
383
384 int ldso_stub__gettimeofday(struct timeval *tp, struct timezone *tzp)
385 {
386   return gettimeofday(tp, tzp);
387 }
388
389 uid_t ldso_stub__getuid(void)
390 {
391   return getuid();
392 }
393
394 char *ldso_stub__getwd(char *buf)
395 {
396   return getwd(buf);
397 }
398
399 double ldso_stub__hypot(double x, double y)
400 {
401   return hypot(x, y);
402 }
403
404 int ldso_stub__kill(pid_t pid, int sig)
405 {
406   return kill(pid, sig);
407 }
408
409 int ldso_stub__killpg(pid_t pgrp, int sig)
410 {
411   return killpg(pgrp, sig);
412 }
413
414 off_t ldso_stub__lseek(int fildes, off_t offset, int whence)
415 {
416   return lseek(fildes, offset, whence);
417 }
418
419 int ldso_stub__lstat(const char *path, struct stat *sb)
420 {
421   return lstat(path, sb);
422 }
423
424 void *ldso_stub__malloc(size_t size)
425 {
426   return malloc(size);
427 }
428
429 int ldso_stub__mkdir(const char *path, mode_t mode)
430 {
431   return mkdir(path, mode);
432 }
433
434 int ldso_stub__open(const char *path, int flags, mode_t mode)
435 {
436   return open(path, flags, mode);
437 }
438
439 DIR *ldso_stub__opendir(const char *filename)
440 {
441   return opendir(filename);
442 }
443
444 double ldso_stub__pow(double x, double y)
445 {
446   return pow(x, y);
447 }
448
449 ssize_t ldso_stub__read(int d, void *buf, size_t nbytes)
450 {
451   return read(d, buf, nbytes);
452 }
453
454 struct dirent *ldso_stub__readdir(DIR *dirp)
455 {
456   return readdir(dirp);
457 }
458
459 int ldso_stub__readlink(const char *path, char *buf, int bufsiz)
460 {
461   return readlink(path, buf, bufsiz);
462 }
463
464 int ldso_stub__rename(const char *from, const char *to)
465 {
466   return rename(from, to);
467 }
468
469 int ldso_stub__select(int nfds, fd_set *readfs, fd_set *writefds, 
470                       fd_set *exceptfds, struct timeval *timeout)
471 {
472   return select(nfds, readfs, writefds, exceptfds, timeout);
473 }
474
475 int ldso_stub__sigblock(int mask)
476 {
477   return sigblock(mask);
478 }
479
480 int ldso_stub__sigpause(int sigmask)
481 {
482   return sigpause(sigmask);
483 }
484
485 int ldso_stub__sigsetmask(int mask)
486 {
487   return sigsetmask(mask);
488 }
489
490 double ldso_stub__sinh(double x)
491 {
492   return sin(x);
493 }
494
495 int ldso_stub__stat(const char *path, struct stat *sb)
496 {
497   return stat(path, sb);
498 }
499
500 double ldso_stub__tanh(double x)
501 {
502   return tanh(x);
503 }
504
505 /* tzname */
506
507 int ldso_stub__unlink(const char *path)
508 {
509   return unlink(path);
510 }
511
512 ssize_t ldso_stub__write(int d, const void *buf, size_t nbytes)
513 {
514   return write(d, buf, nbytes);
515 }
516
517 pid_t ldso_stub__wait3(int *status, int options, struct rusage *rusage)
518 {
519   return wait3(status, options, rusage);
520 }
521
522 #endif /* DL_WORKAROUND */