Clean up RCS ids
[projects/cmucl/cmucl.git] / src / lisp / NetBSD-os.c
1 /*
2  * NetBSD-os.c.
3  * From OpenBSD-os.c 1.1 2001/12/06 19:15:44 pmai Exp
4  * From FreeBSD-os.c 1.6 2000/10/24 13:32:30 dtc Exp
5  *
6  * OS-dependent routines.  This file (along with os.h) exports an
7  * OS-independent interface to the operating system VM facilities.
8  * Suprisingly, this interface looks a lot like the Mach interface
9  * (but simpler in some places).  For some operating systems, a subset
10  * of these functions will have to be emulated.
11  *
12  * This is the OSF1 version.  By Sean Hallgren.
13  * Much hacked by Paul Werkowski
14  * GENCGC support by Douglas Crosher, 1996, 1997.
15  * Frobbed for OpenBSD by Pierre R. Mai, 2001.
16  * Frobbed for NetBSD by Pierre R. Mai, 2002.
17  *
18  *
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/param.h>
24 #include <sys/file.h>
25 #include <errno.h>
26 #include "os.h"
27 #include "arch.h"
28 #include "globals.h"
29 #include "interrupt.h"
30 #include "lispregs.h"
31 #include "internals.h"
32
33 #include <sys/types.h>
34 #include <signal.h>
35 /* #include <sys/sysinfo.h> */
36 #include <sys/proc.h>
37 #include <dlfcn.h>
38 #include <sys/sysctl.h>
39 #include "validate.h"
40 size_t os_vm_page_size;
41
42 #if defined GENCGC
43 #include "gencgc.h"
44 #endif
45 \f
46
47 void
48 os_init0(const char *argv[], const char *envp[])
49 {}
50
51 void
52 os_init(const char *argv[], const char *envp[])
53 {
54     os_vm_page_size = OS_VM_DEFAULT_PAGESIZE;
55 }
56
57 unsigned long *
58 os_sigcontext_reg(ucontext_t *scp, int index)
59 {
60 #ifdef i386
61     switch (index) {
62     case 0:
63         return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EAX];
64     case 2:
65         return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_ECX];
66     case 4:
67         return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EDX];
68     case 6:
69         return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EBX];
70     case 8:
71         return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_ESP];
72     case 10:
73         return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EBP];
74     case 12:
75         return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_ESI];
76     case 14:
77         return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EDI];
78     }
79 #endif
80     return NULL;
81 }
82
83 unsigned long *
84 os_sigcontext_pc(ucontext_t *scp)
85 {
86 #ifdef i386
87     return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EIP];
88 #endif
89 }
90
91 unsigned char *
92 os_sigcontext_fpu_reg(ucontext_t *scp, int index)
93 {
94     unsigned char *reg = NULL;
95
96     DPRINTF(0, (stderr, "fpu reg index = %d\n", index));
97     
98     if (scp->uc_flags & _UC_FPU) {
99         if (scp->uc_flags & _UC_FXSAVE) {
100             /*
101              * fp_xmm is an array of bytes in the format of the FXSAVE
102              * instruction.  The x87 registers are at offset 32 from
103              * the start and each entry takes 16 bytes (only 10
104              * needed).  The XMM registers are at offset 160 from the
105              * start of the array, and each XMM register is 16 bytes
106              * long.
107              */
108             if (index >= 8) {
109                 reg = &scp->uc_mcontext.__fpregs.__fp_reg_set.__fp_xmm_state.__fp_xmm[160 + 16*(index - 8)];
110                 DPRINTF(0, (stderr, " sse2 = %g\n", (double) *(double*) reg));
111             } else {
112                 reg = &scp->uc_mcontext.__fpregs.__fp_reg_set.__fp_xmm_state.__fp_xmm[32 + 16*index];
113                 DPRINTF(0, (stderr, " sse2 x87 = %g\n", (double) *(long double*) reg));
114             }
115             
116         } else {
117             /*
118              * In this case, we have the FNSAVE format.  The x87
119              * registers are located at offset 28 and take 10 bytes
120              * each.
121              */
122             reg = &scp->uc_mcontext.__fpregs.__fp_reg_set.__fpchip_state.__fp_state[28 + 10*index];
123             DPRINTF(0, (stderr, " x87 = %g\n", (double) *(long double*) reg));
124         }
125     } else {
126         reg = NULL;
127     }
128     return reg;
129 }
130
131 unsigned int
132 os_sigcontext_fpu_modes(ucontext_t *scp)
133 {
134     unsigned int modes;
135
136     union savefpu *sv = (union savefpu *) &scp->uc_mcontext.__fpregs.__fp_reg_set;
137     struct env87 *env_87 = (struct env87 *) &sv->sv_87.sv_env;
138     struct envxmm *env_xmm = (struct envxmm *) &sv->sv_xmm.sv_env;
139     u_int16_t cw;
140     u_int16_t sw;
141
142     if (scp->uc_flags & _UC_FPU) {
143         if (scp->uc_flags & _UC_FXSAVE) {
144             cw = env_xmm->en_cw;
145             sw = env_xmm->en_sw;
146         } else {
147             cw = env_87->en_cw & 0xffff;
148             sw = env_87->en_sw & 0xffff;
149         }
150     } else {
151         cw = 0;
152         sw = 0x3f;
153     }
154
155     modes = ((cw & 0x3f) << 7) | (sw & 0x3f);
156
157 #ifdef FEATURE_SSE2
158     if (fpu_mode == SSE2) {
159         u_int32_t mxcsr = env_xmm->en_mxcsr;
160
161         DPRINTF(0, (stderr, "SSE2 modes = %08x\n", (int)mxcsr));
162         modes |= mxcsr;
163     }
164 #endif
165     modes ^= (0x3f << 7);
166     return modes;
167 }
168
169 os_vm_address_t
170 os_validate(os_vm_address_t addr, os_vm_size_t len)
171 {
172     int flags = MAP_PRIVATE | MAP_ANON;
173
174     /*
175      * NetBSD 1.5.2 seems to insist on each mmap being less than 128MB.
176      * So we mmap in 64MB steps.
177      */
178
179     if (addr)
180         flags |= MAP_FIXED;
181
182     DPRINTF(0, (stderr, "os_validate %p %d =>", addr, len));
183
184     if (addr) {
185         os_vm_address_t curaddr = addr;
186
187         while (len > 0) {
188             os_vm_address_t resaddr;
189             int curlen = MIN(64 * 1024 * 1024, len);
190
191             resaddr = mmap(curaddr, curlen, OS_VM_PROT_ALL, flags, -1, 0);
192
193             if (resaddr == (os_vm_address_t) - 1) {
194                 perror("mmap");
195
196                 while (curaddr > addr) {
197                     curaddr -= 64 * 1024 * 1024;
198                     munmap(curaddr, 64 * 1024 * 1024);
199                 }
200
201                 return NULL;
202             }
203
204             DPRINTF(0, (stderr, " %p", resaddr));
205
206             curaddr += curlen;
207             len -= curlen;
208         }
209
210         DPRINTF(0, (stderr, "\n"));
211     } else {
212         addr = mmap(0, len, OS_VM_PROT_ALL, flags, -1, 0);
213
214         if (addr == (os_vm_address_t) - 1) {
215             perror("mmap");
216             return NULL;
217         }
218
219         DPRINTF(0, (stderr, " %p\n", addr));
220     }
221
222     return addr;
223 }
224
225 void
226 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
227 {
228     DPRINTF(0, (stderr, "os_invalidate %p %d\n", addr, len));
229
230     if (munmap(addr, len) == -1)
231         perror("munmap");
232 }
233
234 os_vm_address_t
235 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
236 {
237     addr = mmap(addr, len,
238                 OS_VM_PROT_ALL,
239                 MAP_PRIVATE | MAP_FILE | MAP_FIXED, fd, (off_t) offset);
240
241     if (addr == (os_vm_address_t) - 1)
242         perror("mmap");
243
244     return addr;
245 }
246
247 void
248 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
249 {
250 }
251
252 void
253 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
254 {
255     if (mprotect(address, length, prot) == -1)
256         perror("mprotect");
257 }
258 \f
259
260
261 static boolean
262 in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
263 {
264     char *beg = (char *) sbeg;
265     char *end = (char *) sbeg + slen;
266     char *adr = (char *) a;
267
268     return (adr >= beg && adr < end);
269 }
270
271 boolean
272 valid_addr(os_vm_address_t addr)
273 {
274     os_vm_address_t newaddr;
275
276     newaddr = os_trunc_to_page(addr);
277
278     if (in_range_p(addr, READ_ONLY_SPACE_START, read_only_space_size)
279         || in_range_p(addr, STATIC_SPACE_START, static_space_size)
280         || in_range_p(addr, DYNAMIC_0_SPACE_START, dynamic_space_size)
281 #ifndef GENCGC
282         || in_range_p(addr, DYNAMIC_1_SPACE_START, dynamic_space_size)
283 #endif
284         || in_range_p(addr, CONTROL_STACK_START, control_stack_size)
285         || in_range_p(addr, BINDING_STACK_START, binding_stack_size))
286         return TRUE;
287     return FALSE;
288 }
289 \f
290
291 static void
292 sigsegv_handler(HANDLER_ARGS)
293 {
294 #if defined GENCGC
295 #if SIGSEGV_VERBOSE
296     caddr_t fault_addr = code ? code->si_addr : 0;
297
298     fprintf(stderr, "Signal %d, fault_addr=%p, page_index=%d:\n",
299             signal, fault_addr, page_index);
300 #endif
301
302     if (gc_write_barrier(code->si_addr))
303         return;
304 #endif
305
306     SAVE_CONTEXT();
307
308     DPRINTF(0, (stderr, "sigsegv:\n"));
309     interrupt_handle_now(signal, code, context);
310 }
311
312 static void
313 sigbus_handler(HANDLER_ARGS)
314 {
315     SAVE_CONTEXT();
316
317     DPRINTF(0, (stderr, "sigbus:\n"));
318     interrupt_handle_now(signal, code, context);
319 }
320
321 /*
322  * Restore the exception flags cleared by the kernel.  These bits must
323  * be set for Lisp to determine which exception caused the signal.  At
324  * present, there is no way to distinguish underflow exceptions from
325  * denormalized operand exceptions.  An underflow exception is assumed
326  * if the subcode is FPE_FLTUND.
327  */
328 static void
329 sigfpe_handler(HANDLER_ARGS)
330 {
331     ucontext_t *ucontext = (ucontext_t *) context;
332     union savefpu *sv = (union savefpu *) &ucontext->uc_mcontext.__fpregs.__fp_reg_set;
333     unsigned char trap = 0;
334
335     switch (code->si_code) {
336       case FPE_FLTDIV:          /* ZE */
337           trap = 0x04;
338           break;
339       case FPE_FLTOVF:          /* OE */
340           trap = 0x08;
341           break;
342       case FPE_FLTUND:          /* DE or UE */
343           trap = 0x10;
344           break;
345       case FPE_FLTRES:          /* PE */
346           trap = 0x20;
347           break;
348       case FPE_FLTINV:          /* IE */
349           trap = 0x01;
350           break;
351     }
352
353     if (ucontext->uc_flags & _UC_FXSAVE) {
354         sv->sv_xmm.sv_env.en_sw |= trap;
355     } else {
356         sv->sv_87.sv_env.en_sw |= trap;
357     }
358     interrupt_handle_now(signal, code, context);
359 }
360
361 void
362 os_install_interrupt_handlers(void)
363 {
364     interrupt_install_low_level_handler(SIGSEGV, sigsegv_handler);
365     interrupt_install_low_level_handler(SIGBUS, sigbus_handler);
366     interrupt_install_low_level_handler(SIGFPE, sigfpe_handler);
367 }
368
369 void *
370 os_dlsym(const char *sym_name, lispobj lib_list)
371 {
372     if (lib_list != NIL) {
373         lispobj lib_list_head;
374
375         for (lib_list_head = lib_list;
376              lib_list_head != NIL; lib_list_head = CONS(lib_list_head)->cdr) {
377             struct cons *lib_cons = CONS(CONS(lib_list_head)->car);
378             struct sap *dlhandle = (struct sap *) PTR(lib_cons->car);
379             void *sym_addr = dlsym((void *) dlhandle->pointer, sym_name);
380
381             if (sym_addr)
382                 return sym_addr;
383         }
384     }
385
386     return dlsym(RTLD_DEFAULT, sym_name);
387 }
388
389 void
390 restore_fpu(ucontext_t *scp)
391 {
392     union savefpu *sv = (union savefpu *) &scp->uc_mcontext.__fpregs.__fp_reg_set;
393     struct env87 *env_87 = &sv->sv_87.sv_env;
394     struct envxmm *env_xmm = &sv->sv_xmm.sv_env;
395     u_int16_t cw;
396
397     if (scp->uc_flags & _UC_FPU) {
398         if (scp->uc_flags & _UC_FXSAVE) {
399             cw = env_xmm->en_cw;
400         } else {
401             cw = env_87->en_cw & 0xffff;
402         }
403     } else {
404         return;
405     }
406     DPRINTF(0, (stderr, "restore_fpu:  cw = %08x\n", (int)cw));
407     __asm__ __volatile__ ("fldcw %0"::"m"(*&cw));
408
409     if (fpu_mode == SSE2) {
410         u_int32_t mxcsr = env_xmm->en_mxcsr;
411
412         DPRINTF(0, (stderr, "restore_fpu:  mxcsr (raw) = %04x\n", mxcsr));
413         __asm__ __volatile__ ("ldmxcsr %0"::"m"(*&mxcsr));
414     }
415 }
416
417 #ifdef i386
418 boolean
419 os_support_sse2()
420 {
421     int support_sse2;
422     size_t len;
423
424     if (sysctlbyname("machdep.sse2", &support_sse2, &len,
425                      NULL, 0) == 0 && support_sse2 != 0)
426         return TRUE;
427     else
428         return FALSE;
429 }
430 #endif