0.8.9.37:
[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 <unistd.h>
25 #include <assert.h>
26 #include "sbcl.h"
27 #include "./signal.h"
28 #include "os.h"
29 #include "arch.h"
30 #include "globals.h"
31 #include "interrupt.h"
32 #include "interr.h"
33 #include "lispregs.h"
34 #include "thread.h"
35
36 #include <sys/types.h>
37 #include <signal.h>
38 /* #include <sys/sysinfo.h> */
39 #include "validate.h"
40
41 \f
42 os_vm_size_t os_vm_page_size;
43
44 #ifdef __NetBSD__
45 #include <sys/resource.h>
46 #include <sys/sysctl.h>
47 #include <string.h>
48
49 static void netbsd_init();
50 #endif /* __NetBSD__ */
51  
52 void os_init(void)
53 {
54     os_vm_page_size = getpagesize();
55
56 #ifdef __NetBSD__
57     netbsd_init();
58 #endif /* __NetBSD__ */
59 }
60
61 int *os_context_pc_addr(os_context_t *context)
62 {
63 #if defined __FreeBSD__
64     return CONTEXT_ADDR_FROM_STEM(eip);
65 #elif defined __OpenBSD__
66     return CONTEXT_ADDR_FROM_STEM(pc);
67 #elif defined __NetBSD__
68     return CONTEXT_ADDR_FROM_STEM(EIP);
69 #elif defined LISP_FEATURE_DARWIN
70     return &context->uc_mcontext->ss.srr0;
71 #else
72 #error unsupported BSD variant
73 #endif
74 }
75
76 sigset_t *
77 os_context_sigmask_addr(os_context_t *context)
78 {
79     /* (Unlike most of the other context fields that we access, the
80      * signal mask field is a field of the basic, outermost context
81      * struct itself both in FreeBSD 4.0 and in OpenBSD 2.6.) */
82 #if defined __FreeBSD__  || __NetBSD__ || defined LISP_FEATURE_DARWIN
83     return &context->uc_sigmask;
84 #elif defined __OpenBSD__
85     return &context->sc_mask;
86 #else
87 #error unsupported BSD variant
88 #endif
89 }
90
91 os_vm_address_t
92 os_validate(os_vm_address_t addr, os_vm_size_t len)
93 {
94     int flags = MAP_PRIVATE | MAP_ANON;
95
96     if (addr)
97         flags |= MAP_FIXED;
98
99     addr = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
100
101     if (addr == MAP_FAILED) {
102         perror("mmap");
103         return NULL;
104     }
105
106     return addr;
107 }
108
109 void
110 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
111 {
112     if (munmap(addr, len) == -1)
113         perror("munmap");
114 }
115
116 os_vm_address_t
117 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
118 {
119     addr = mmap(addr, len,
120                 OS_VM_PROT_ALL,
121                 MAP_PRIVATE | MAP_FILE | MAP_FIXED,
122                 fd, (off_t) offset);
123
124     if (addr == MAP_FAILED) {
125         perror("mmap");
126         lose("unexpected mmap(..) failure");
127     }
128
129     return addr;
130 }
131
132 void
133 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
134 {
135     if (mprotect(address, length, prot) == -1) {
136         perror("mprotect");
137     }
138 }
139 \f
140 static boolean
141 in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
142 {
143     char* beg = (char*) sbeg;
144     char* end = (char*) sbeg + slen;
145     char* adr = (char*) a;
146     return (adr >= beg && adr < end);
147 }
148
149 boolean
150 is_valid_lisp_addr(os_vm_address_t addr)
151 {
152     struct thread *th;
153     if(in_range_p(addr, READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE) ||
154        in_range_p(addr, STATIC_SPACE_START   , STATIC_SPACE_SIZE) ||
155        in_range_p(addr, DYNAMIC_SPACE_START  , DYNAMIC_SPACE_SIZE))
156         return 1;
157     for_each_thread(th) {
158         if((th->control_stack_start <= addr) && (addr < th->control_stack_end))
159             return 1;
160         if(in_range_p(addr, th->binding_stack_start, BINDING_STACK_SIZE))
161             return 1;
162     }
163     return 0;
164 }
165 \f
166 /*
167  * any OS-dependent special low-level handling for signals
168  */
169
170 #if defined LISP_FEATURE_GENCGC
171
172 /*
173  * The GENCGC needs to be hooked into whatever signal is raised for
174  * page fault on this OS.
175  */
176 static void
177 memory_fault_handler(int signal, siginfo_t *siginfo, void *void_context)
178 {
179     /* The way that we extract low level information like the fault
180      * address is not specified by POSIX. */
181 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
182     void *fault_addr = siginfo->si_addr;
183 #elif defined LISP_FEATURE_DARWIN
184     void *fault_addr = siginfo->si_addr;
185 #else
186 #error unsupported BSD variant
187 #endif
188
189     os_context_t *context = arch_os_get_context(&void_context);
190     if (!gencgc_handle_wp_violation(fault_addr)) 
191         if(!handle_control_stack_guard_triggered(context,fault_addr))
192             /* FIXME is this context or void_context?  not that it */
193             /* makes a difference currently except on linux/sparc */
194             interrupt_handle_now(signal, siginfo, void_context);
195 }
196 void
197 os_install_interrupt_handlers(void)
198 {
199     SHOW("os_install_interrupt_handlers()/bsd-os/defined(GENCGC)");
200     undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT,
201                                                  memory_fault_handler);
202     SHOW("leaving os_install_interrupt_handlers()");
203 }
204
205 #else /* Currently Darwin only */
206
207 static void
208 sigsegv_handler(int signal, siginfo_t *info, void* void_context)
209 {
210     os_context_t *context = arch_os_get_context(&void_context);
211     unsigned int pc =  (unsigned int *)(*os_context_pc_addr(context));
212     os_vm_address_t addr;
213     
214     addr = arch_get_bad_addr(signal,info,context);
215     if(!interrupt_maybe_gc(signal, info, context))
216         if(!handle_control_stack_guard_triggered(context,addr))
217             interrupt_handle_now(signal, info, context);
218     /* Work around G5 bug; fix courtesy gbyers */
219     sigreturn(void_context);
220 }
221
222 void
223 os_install_interrupt_handlers(void)
224 {
225     SHOW("os_install_interrupt_handlers()/bsd-os/!defined(GENCGC)");
226     undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT,
227                                                  sigsegv_handler);
228 }
229
230 #endif /* defined GENCGC */
231
232 #ifdef __NetBSD__
233 static void netbsd_init()
234 {
235     struct rlimit rl;
236     int mib[2], osrev;
237     size_t len;
238
239     /* Are we running on a sufficiently functional kernel? */
240     mib[0] = CTL_KERN;
241     mib[1] = KERN_OSREV;
242
243     len = sizeof(osrev);
244     sysctl(mib, 2, &osrev, &len, NULL, 0);
245
246     /* If we're older than 2.0... */
247     if (osrev < 200000000) {
248         fprintf(stderr, "osrev = %d (needed at least 200000000).\n", osrev);
249         lose("NetBSD kernel too old to run sbcl.\n");
250     }
251     
252     /* NetBSD counts mmap()ed space against the process's data size limit,
253      * so yank it up. This might be a nasty thing to do? */
254     getrlimit (RLIMIT_DATA, &rl);
255     /* Amazingly for such a new port, the provenance and meaning of
256        this number are unknown.  It might just mean REALLY_BIG_LIMIT,
257        or possibly it should be calculated from dynamic space size.
258        -- CSR, 2004-04-08 */
259     rl.rlim_cur = 1073741824;
260     if (setrlimit (RLIMIT_DATA, &rl) < 0) {
261         fprintf (stderr, 
262                  "RUNTIME WARNING: unable to raise process data size limit:\n\
263   %s.\n\
264 The system may fail to start.\n",
265                  strerror(errno));
266     }
267 }
268 #endif /* __NetBSD__ */
269 \f
270 /* threads */
271
272 /* no threading in any *BSD variant on any CPU (yet? in sbcl-0.8.0 anyway) */
273 #ifdef LISP_FEATURE_SB_THREAD
274 #error "Define threading support functions"
275 #else
276 int arch_os_thread_init(struct thread *thread) {
277   stack_t sigstack;
278 #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
279     /* Signal handlers are run on the control stack, so if it is exhausted
280      * we had better use an alternate stack for whatever signal tells us
281      * we've exhausted it */
282     sigstack.ss_sp=((void *) thread)+dynamic_values_bytes;
283     sigstack.ss_flags=0;
284     sigstack.ss_size = 32*SIGSTKSZ;
285     sigaltstack(&sigstack,0);
286 #endif
287     return 1;                  /* success */
288 }
289 int arch_os_thread_cleanup(struct thread *thread) {
290     return 1;                  /* success */
291 }
292 #endif