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