7a06222cd33a6e947c010898e9c44f41d1544ca7
[projects/cmucl/cmucl.git] / src / lisp / FreeBSD-os.c
1 /*
2  * FreeBSD-os.c. Maybe could be just BSD-os.c
3  * From osf1-os.c,v 1.1 94/03/27 15:30:51 hallgren Exp $
4  *
5  * OS-dependent routines.  This file (along with os.h) exports an
6  * OS-independent interface to the operating system VM facilities.
7  * Suprisingly, this interface looks a lot like the Mach interface
8  * (but simpler in some places).  For some operating systems, a subset
9  * of these functions will have to be emulated.
10  *
11  * This is the OSF1 version.  By Sean Hallgren.
12  * Much hacked by Paul Werkowski
13  * GENCGC support by Douglas Crosher, 1996, 1997.
14  *
15  * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/FreeBSD-os.c,v 1.38 2011/09/01 05:18:26 rtoy Exp $
16  *
17  */
18
19 #include "os.h"
20 #include <sys/file.h>
21 #include <machine/npx.h>
22 #include <errno.h>
23 #include "arch.h"
24 #include "globals.h"
25 #include "interrupt.h"
26 #include "lispregs.h"
27 #include "internals.h"
28
29 #include <signal.h>
30 #include <dlfcn.h>
31 #include "validate.h"
32 #include <stdio.h>
33 #include <unistd.h>
34
35 #if defined GENCGC
36 #include "gencgc.h"
37 #endif
38
39 vm_size_t os_vm_page_size;
40
41 void
42 os_init0(const char *argv[], const char *envp[])
43 {}
44
45 void
46 os_init(const char *argv[], const char *envp[])
47 {
48     os_vm_page_size = getpagesize();
49 }
50
51 unsigned long *
52 os_sigcontext_reg(ucontext_t *scp, int index)
53 {
54     __register_t *rv;
55
56     switch (index) {
57       case 0:
58         rv = &scp->uc_mcontext.mc_eax;
59         break;
60       case 2:
61         rv = &scp->uc_mcontext.mc_ecx;
62         break;
63       case 4:
64         rv = &scp->uc_mcontext.mc_edx;
65         break;
66       case 6:
67         rv = &scp->uc_mcontext.mc_ebx;
68         break;
69       case 8:
70         rv = &scp->uc_mcontext.mc_esp;
71         break;
72       case 10:
73         rv = &scp->uc_mcontext.mc_ebp;
74         break;
75       case 12:
76         rv = &scp->uc_mcontext.mc_esi;
77         break;
78       case 14:
79         rv = &scp->uc_mcontext.mc_edi;
80         break;
81       default:
82         rv = NULL;
83     }
84     
85     /* Pre-cast to (void *), to avoid the compiler warning:
86      * dereferencing type-punned pointer will break strict-aliasing rules
87      */
88     return (unsigned long *) (void *) rv;
89 }
90
91 unsigned long *
92 os_sigcontext_pc(ucontext_t *scp)
93 {
94     return (unsigned long *) (void *) &scp->uc_mcontext.mc_eip;
95 }
96
97 unsigned char *
98 os_sigcontext_fpu_reg(ucontext_t *scp, int index)
99 {
100     union savefpu *sv = (union savefpu *) scp->uc_mcontext.mc_fpstate;
101     int fpformat = scp->uc_mcontext.mc_fpformat;
102     unsigned char *reg = NULL;
103
104     switch (fpformat) {
105       case _MC_FPFMT_XMM:
106           if (index < 8) {
107               reg = sv->sv_xmm.sv_fp[index].fp_acc.fp_bytes;
108           } else {
109               reg = sv->sv_xmm.sv_xmm[index - 8].xmm_bytes;
110           }
111           break;
112       case _MC_FPFMT_387:
113           reg = sv->sv_87.sv_ac[index].fp_bytes;
114           break;
115       case _MC_FPFMT_NODEV:
116           reg = NULL;
117           break;
118     }
119     return reg;
120 }
121
122 unsigned int
123 os_sigcontext_fpu_modes(ucontext_t *scp)
124 {
125     unsigned int modes;
126
127     union savefpu *sv = (union savefpu *) scp->uc_mcontext.mc_fpstate;
128     int fpformat = scp->uc_mcontext.mc_fpformat;
129     struct env87 *env_87 = &sv->sv_87.sv_env;
130     struct envxmm *env_xmm = &sv->sv_xmm.sv_env;
131     u_int16_t cw;
132     u_int16_t sw;
133
134     if (fpformat == _MC_FPFMT_XMM) {
135         cw = env_xmm->en_cw;
136         sw = env_xmm->en_sw;
137     } else if (fpformat == _MC_FPFMT_387) {
138         cw = env_87->en_cw & 0xffff;
139         sw = env_87->en_sw & 0xffff;
140     } else { /* _MC_FPFMT_NODEV */
141         cw = 0;
142         sw = 0x3f;
143     }
144
145     modes = ((cw & 0x3f) << 7) | (sw & 0x3f);
146
147 #ifdef FEATURE_SSE2
148     if (fpu_mode == SSE2) {
149         u_int32_t mxcsr = env_xmm->en_mxcsr;
150
151         DPRINTF(0, (stderr, "SSE2 modes = %08x\n", (int)mxcsr));
152         modes |= mxcsr;
153     }
154 #endif
155     modes ^= (0x3f << 7);
156     return modes;
157 }
158
159 os_vm_address_t
160 os_validate(os_vm_address_t addr, os_vm_size_t len)
161 {
162     int flags = MAP_PRIVATE | MAP_ANON;
163
164     if (addr)
165         flags |= MAP_FIXED;
166
167     addr = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
168
169     if (addr == (os_vm_address_t) - 1) {
170         perror("mmap");
171         return NULL;
172     }
173
174     return addr;
175 }
176
177 void
178 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
179 {
180     if (munmap(addr, len) == -1)
181         perror("munmap");
182 }
183
184 os_vm_address_t
185 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
186 {
187     addr = mmap(addr, len, OS_VM_PROT_ALL,
188                 MAP_PRIVATE | MAP_FILE | MAP_FIXED, fd, (off_t) offset);
189
190     if (addr == (os_vm_address_t) - 1)
191         perror("mmap");
192
193     return addr;
194 }
195
196 void
197 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
198 {
199 }
200
201 void
202 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
203 {
204     if (mprotect(address, length, prot) == -1)
205         perror("mprotect");
206 }
207 \f
208
209
210 static boolean
211 in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
212 {
213     char *beg = (char *) sbeg;
214     char *end = (char *) sbeg + slen;
215     char *adr = (char *) a;
216
217     return adr >= beg && adr < end;
218 }
219
220 boolean
221 valid_addr(os_vm_address_t addr)
222 {
223     os_vm_address_t newaddr;
224
225     newaddr = os_trunc_to_page(addr);
226
227     if (in_range_p(addr, READ_ONLY_SPACE_START, read_only_space_size)
228         || in_range_p(addr, STATIC_SPACE_START, static_space_size)
229         || in_range_p(addr, DYNAMIC_0_SPACE_START, dynamic_space_size)
230 #ifndef GENCGC
231         || in_range_p(addr, DYNAMIC_1_SPACE_START, dynamic_space_size)
232 #endif
233         || in_range_p(addr, CONTROL_STACK_START, control_stack_size)
234         || in_range_p(addr, BINDING_STACK_START, binding_stack_size))
235         return TRUE;
236     return FALSE;
237 }
238 \f
239
240 static void
241 protection_violation_handler(HANDLER_ARGS)
242 {
243 #ifdef RED_ZONE_HIT
244     if (os_control_stack_overflow(code->si_addr, context))
245         return;
246 #endif
247
248 #if defined GENCGC
249     if (code->si_code == PROTECTION_VIOLATION_CODE) {
250         if (gc_write_barrier(code->si_addr)) {
251             return;
252         }
253     }
254 #endif
255
256     interrupt_handle_now(signal, code, context);
257 }
258
259 /*
260  * Restore the exception flags cleared by the kernel.  These bits must
261  * be set for Lisp to determine which exception caused the signal.  At
262  * present, there is no way to distinguish underflow exceptions from
263  * denormalized operand exceptions.  An underflow exception is assumed
264  * if the subcode is FPE_FLTUND.
265  */
266 static void
267 sigfpe_handler(HANDLER_ARGS)
268 {
269     ucontext_t *ucontext = (ucontext_t *) context;
270     union savefpu *sv = (union savefpu *) ucontext->uc_mcontext.mc_fpstate;
271     int fpformat = ucontext->uc_mcontext.mc_fpformat;
272     unsigned char trap = 0;
273
274     switch (code->si_code) {
275       case FPE_FLTDIV:          /* ZE */
276           trap = 0x04;
277           break;
278       case FPE_FLTOVF:          /* OE */
279           trap = 0x08;
280           break;
281       case FPE_FLTUND:          /* DE or UE */
282           trap = 0x10;
283           break;
284       case FPE_FLTRES:          /* PE */
285           trap = 0x20;
286           break;
287       case FPE_FLTINV:          /* IE */
288           trap = 0x01;
289           break;
290     }
291
292     switch (fpformat) {
293       case _MC_FPFMT_XMM:
294           sv->sv_xmm.sv_env.en_sw |= trap;
295           break;
296       case _MC_FPFMT_387:
297           sv->sv_87.sv_env.en_sw |= trap;
298           break;
299     }
300     interrupt_handle_now(signal, code, context);
301 }
302
303 void
304 os_install_interrupt_handlers(void)
305 {
306     interrupt_install_low_level_handler(PROTECTION_VIOLATION_SIGNAL,
307                                         protection_violation_handler);
308     interrupt_install_low_level_handler(SIGFPE, sigfpe_handler);
309 }
310
311 void *
312 os_dlsym(const char *sym_name, lispobj lib_list)
313 {
314     static void *program_handle;
315
316     if (!program_handle)
317         program_handle = dlopen((void *) 0, RTLD_LAZY | RTLD_GLOBAL);
318
319     if (lib_list != NIL) {
320         lispobj lib_list_head;
321
322         for (lib_list_head = lib_list;
323              lib_list_head != NIL; lib_list_head = CONS(lib_list_head)->cdr) {
324             struct cons *lib_cons = CONS(CONS(lib_list_head)->car);
325             struct sap *dlhandle = (struct sap *)PTR(lib_cons->car);
326             void *sym_addr = dlsym((void *)dlhandle->pointer, sym_name);
327
328             if (sym_addr)
329                 return sym_addr;
330         }
331     }
332     return dlsym(program_handle, sym_name);
333 }
334
335 void
336 restore_fpu(ucontext_t *scp)
337 {
338     union savefpu *sv = (union savefpu *) scp->uc_mcontext.mc_fpstate;
339     int fpformat = scp->uc_mcontext.mc_fpformat;
340     struct env87 *env_87 = &sv->sv_87.sv_env;
341     struct envxmm *env_xmm = &sv->sv_xmm.sv_env;
342     u_int16_t cw;
343
344     if (fpformat == _MC_FPFMT_XMM) {
345         cw = env_xmm->en_cw;
346     } else if (fpformat == _MC_FPFMT_387) {
347         cw = env_87->en_cw & 0xffff;
348     } else { /* _MC_FPFMT_NODEV */
349         return;
350     }
351     DPRINTF(0, (stderr, "restore_fpu:  cw = %08x\n", (int)cw));
352     __asm__ __volatile__ ("fldcw %0"::"m"(*&cw));
353
354 #ifdef FEATURE_SSE2
355     if (fpu_mode == SSE2) {
356         u_int32_t mxcsr = env_xmm->en_mxcsr;
357
358         DPRINTF(0, (stderr, "restore_fpu:  mxcsr (raw) = %04x\n", mxcsr));
359         __asm__ __volatile__ ("ldmxcsr %0"::"m"(*&mxcsr));
360     }
361 #endif
362 }
363
364 #ifdef i386
365 boolean
366 os_support_sse2()
367 {
368     return TRUE;
369 }
370 #endif
371