0.pre8.112:
[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 "interr.h"
30 #include "lispregs.h"
31 #include "sbcl.h"
32 #include "thread.h"
33
34 #include <sys/types.h>
35 #include <signal.h>
36 /* #include <sys/sysinfo.h> */
37 #include <sys/proc.h>
38 #include "validate.h"
39 vm_size_t os_vm_page_size;
40
41
42 /* The different BSD variants have diverged in exactly where they
43  * store signal context information, but at least they tend to use the
44  * same stems to name the structure fields, so by using this macro we
45  * can share a fair amount of code between different variants. */
46 #if defined __FreeBSD__
47 #define CONTEXT_ADDR_FROM_STEM(stem) &context->uc_mcontext.mc_ ## stem
48 #elif defined __OpenBSD__
49 #define CONTEXT_ADDR_FROM_STEM(stem) &context->sc_ ## stem
50 #else
51 #error unsupported BSD variant
52 #endif
53 \f
54 void
55 os_init(void)
56 {
57     os_vm_page_size = getpagesize();
58 }
59
60 /* KLUDGE: There is strong family resemblance in the signal context
61  * stuff in FreeBSD and OpenBSD, but in detail they're different in
62  * almost every line of code. It would be nice to find some way to
63  * factor out the commonality better; failing that, it might be best
64  * just to split this generic-BSD code into one variant for each BSD. */
65    
66 int *
67 os_context_register_addr(os_context_t *context, int offset)
68 {
69     switch(offset) {
70     case  0:
71         return CONTEXT_ADDR_FROM_STEM(eax);
72     case  2:
73         return CONTEXT_ADDR_FROM_STEM(ecx);
74     case  4:
75         return CONTEXT_ADDR_FROM_STEM(edx);
76     case  6:
77         return CONTEXT_ADDR_FROM_STEM(ebx);
78     case  8:
79         return CONTEXT_ADDR_FROM_STEM(esp);
80     case 10:
81         return CONTEXT_ADDR_FROM_STEM(ebp);
82     case 12:
83         return CONTEXT_ADDR_FROM_STEM(esi);
84     case 14:
85         return CONTEXT_ADDR_FROM_STEM(edi);
86     default:
87         return 0;
88     }
89 }
90
91 int *
92 os_context_pc_addr(os_context_t *context)
93 {
94 #if defined __FreeBSD__
95     return CONTEXT_ADDR_FROM_STEM(eip);
96 #elif defined __OpenBSD__
97     return CONTEXT_ADDR_FROM_STEM(pc);
98 #else
99 #error unsupported BSD variant
100 #endif
101 }
102
103 int *
104 os_context_sp_addr(os_context_t *context)
105 {
106     return CONTEXT_ADDR_FROM_STEM(esp);
107 }
108
109 sigset_t *
110 os_context_sigmask_addr(os_context_t *context)
111 {
112     /* (Unlike most of the other context fields that we access, the
113      * signal mask field is a field of the basic, outermost context
114      * struct itself both in FreeBSD 4.0 and in OpenBSD 2.6.) */
115 #if defined __FreeBSD__
116     return &context->uc_sigmask;
117 #elif defined __OpenBSD__
118     return &context->sc_mask;
119 #else
120 #error unsupported BSD variant
121 #endif
122 }
123
124 os_vm_address_t
125 os_validate(os_vm_address_t addr, os_vm_size_t len)
126 {
127     int flags = MAP_PRIVATE | MAP_ANON;
128
129     if (addr)
130         flags |= MAP_FIXED;
131
132     addr = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
133
134     if (addr == MAP_FAILED) {
135         perror("mmap");
136         return NULL;
137     }
138
139     return addr;
140 }
141
142 void
143 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
144 {
145     if (munmap(addr, len) == -1)
146         perror("munmap");
147 }
148
149 os_vm_address_t
150 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
151 {
152     addr = mmap(addr, len,
153                 OS_VM_PROT_ALL,
154                 MAP_PRIVATE | MAP_FILE | MAP_FIXED,
155                 fd, (off_t) offset);
156
157     if (addr == MAP_FAILED) {
158         perror("mmap");
159         lose("unexpected mmap(..) failure");
160     }
161
162     return addr;
163 }
164
165 /* FIXME: If this can be a no-op on BSD/x86, then it 
166  * deserves a more precise name.
167  *
168  * (Perhaps os_prepare_data_area_to_be_executed()?) */
169 void
170 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
171 {
172 }
173
174 void
175 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
176 {
177     if (mprotect(address, length, prot) == -1) {
178         perror("mprotect");
179     }
180 }
181 \f
182 static boolean
183 in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
184 {
185     char* beg = (char*) sbeg;
186     char* end = (char*) sbeg + slen;
187     char* adr = (char*) a;
188     return (adr >= beg && adr < end);
189 }
190
191 boolean
192 is_valid_lisp_addr(os_vm_address_t addr)
193 {
194     struct thread *th;
195     if(in_range_p(addr, READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE) ||
196        in_range_p(addr, STATIC_SPACE_START   , STATIC_SPACE_SIZE) ||
197        in_range_p(addr, DYNAMIC_SPACE_START  , DYNAMIC_SPACE_SIZE))
198         return 1;
199     for_each_thread(th) {
200         if((th->control_stack_start <= addr) && (addr < th->control_stack_end))
201             return 1;
202         if(in_range_p(addr, th->binding_stack_start, BINDING_STACK_SIZE))
203             return 1;
204     }
205     return 0;
206 }
207 \f
208 /*
209  * any OS-dependent special low-level handling for signals
210  */
211
212 #if defined LISP_FEATURE_GENCGC
213
214 /*
215  * The GENCGC needs to be hooked into whatever signal is raised for
216  * page fault on this OS.
217  */
218 static void
219 memory_fault_handler(int signal, siginfo_t *siginfo, void *void_context)
220 {
221     /* The way that we extract low level information like the fault
222      * address is not specified by POSIX. */
223 #if defined __FreeBSD__
224     void *fault_addr = siginfo->si_addr;
225 #elif defined __OpenBSD__
226     void *fault_addr = siginfo->si_addr;
227 #else
228 #error unsupported BSD variant
229 #endif
230     os_context_t *context = arch_os_get_context(&void_context);
231    if (!gencgc_handle_wp_violation(fault_addr)) 
232         if(!handle_control_stack_guard_triggered(context,fault_addr))
233             /* FIXME is this context or void_context?  not that it */
234             /* makes a difference currently except on linux/sparc */
235             interrupt_handle_now(signal, siginfo, void_context);
236 }
237 void
238 os_install_interrupt_handlers(void)
239 {
240     SHOW("os_install_interrupt_handlers()/bsd-os/defined(GENCGC)");
241     undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT,
242                                                  memory_fault_handler);
243     SHOW("leaving os_install_interrupt_handlers()");
244 }
245
246 #else
247 /* As of 2002.07.31, this configuration has never been tested */
248 void
249 os_install_interrupt_handlers(void)
250 {
251     SHOW("os_install_interrupt_handlers()/bsd-os/!defined(GENCGC)");
252 }
253
254 #endif /* defined GENCGC */
255 \f
256 /* threads */
257
258 /* no threading in any *BSD variant on any CPU (yet? in sbcl-0.8.0 anyway) */
259 #ifdef LISP_FEATURE_SB_THREAD
260 #error "Define threading support functions"
261 #else
262 struct thread *arch_os_get_current_thread() {
263     return all_threads;
264 }
265 int arch_os_thread_init(struct thread *thread) {
266     return 1;                  /* success */
267 }
268 int arch_os_thread_cleanup(struct thread *thread) {
269     return 1;                  /* success */
270 }
271 #endif