Clean up RCS ids
[projects/cmucl/cmucl.git] / src / lisp / NetBSD-os.c
CommitLineData
b39b25d0 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 *
b39b25d0 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>
b39b25d0 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>
5d2cd5df 37#include <dlfcn.h>
aa9c2237 38#include <sys/sysctl.h>
b39b25d0 39#include "validate.h"
40size_t os_vm_page_size;
41
b39b25d0 42#if defined GENCGC
43#include "gencgc.h"
44#endif
b39b25d0 45\f
9a8c1c2f 46
47void
dafb9e03 48os_init0(const char *argv[], const char *envp[])
49{}
50
51void
0f0aed07 52os_init(const char *argv[], const char *envp[])
b39b25d0 53{
9a8c1c2f 54 os_vm_page_size = OS_VM_DEFAULT_PAGESIZE;
b39b25d0 55}
56
daa432a5 57unsigned long *
58os_sigcontext_reg(ucontext_t *scp, int index)
b39b25d0 59{
5d2cd5df 60#ifdef i386
daa432a5 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];
5d2cd5df 78 }
5d2cd5df 79#endif
daa432a5 80 return NULL;
81}
82
83unsigned long *
84os_sigcontext_pc(ucontext_t *scp)
85{
86#ifdef i386
87 return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EIP];
88#endif
b39b25d0 89}
90
7fbce9e3 91unsigned char *
92os_sigcontext_fpu_reg(ucontext_t *scp, int index)
93{
94 unsigned char *reg = NULL;
95
9cf15715 96 DPRINTF(0, (stderr, "fpu reg index = %d\n", index));
97
7fbce9e3 98 if (scp->uc_flags & _UC_FPU) {
99 if (scp->uc_flags & _UC_FXSAVE) {
eecd2cbb 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 */
9cf15715 108 if (index >= 8) {
eecd2cbb 109 reg = &scp->uc_mcontext.__fpregs.__fp_reg_set.__fp_xmm_state.__fp_xmm[160 + 16*(index - 8)];
9cf15715 110 DPRINTF(0, (stderr, " sse2 = %g\n", (double) *(double*) reg));
eecd2cbb 111 } else {
112 reg = &scp->uc_mcontext.__fpregs.__fp_reg_set.__fp_xmm_state.__fp_xmm[32 + 16*index];
9cf15715 113 DPRINTF(0, (stderr, " sse2 x87 = %g\n", (double) *(long double*) reg));
eecd2cbb 114 }
115
7fbce9e3 116 } else {
eecd2cbb 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];
9cf15715 123 DPRINTF(0, (stderr, " x87 = %g\n", (double) *(long double*) reg));
7fbce9e3 124 }
125 } else {
126 reg = NULL;
127 }
128 return reg;
129}
130
131unsigned int
132os_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
9a8c1c2f 169os_vm_address_t
170os_validate(os_vm_address_t addr, os_vm_size_t len)
b39b25d0 171{
1e078503 172 int flags = MAP_PRIVATE | MAP_ANON;
9a8c1c2f 173
174 /*
175 * NetBSD 1.5.2 seems to insist on each mmap being less than 128MB.
daa432a5 176 * So we mmap in 64MB steps.
9a8c1c2f 177 */
178
179 if (addr)
180 flags |= MAP_FIXED;
9a8c1c2f 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);
b39b25d0 199 }
9a8c1c2f 200
201 return NULL;
b39b25d0 202 }
203
9a8c1c2f 204 DPRINTF(0, (stderr, " %p", resaddr));
205
206 curaddr += curlen;
207 len -= curlen;
b39b25d0 208 }
9a8c1c2f 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;
b39b25d0 217 }
9a8c1c2f 218
219 DPRINTF(0, (stderr, " %p\n", addr));
b39b25d0 220 }
221
9a8c1c2f 222 return addr;
b39b25d0 223}
224
9a8c1c2f 225void
226os_invalidate(os_vm_address_t addr, os_vm_size_t len)
b39b25d0 227{
9a8c1c2f 228 DPRINTF(0, (stderr, "os_invalidate %p %d\n", addr, len));
b39b25d0 229
9a8c1c2f 230 if (munmap(addr, len) == -1)
231 perror("munmap");
b39b25d0 232}
233
9a8c1c2f 234os_vm_address_t
235os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
b39b25d0 236{
9a8c1c2f 237 addr = mmap(addr, len,
238 OS_VM_PROT_ALL,
239 MAP_PRIVATE | MAP_FILE | MAP_FIXED, fd, (off_t) offset);
b39b25d0 240
9a8c1c2f 241 if (addr == (os_vm_address_t) - 1)
242 perror("mmap");
b39b25d0 243
9a8c1c2f 244 return addr;
b39b25d0 245}
246
9a8c1c2f 247void
248os_flush_icache(os_vm_address_t address, os_vm_size_t length)
b39b25d0 249{
250}
251
9a8c1c2f 252void
253os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
b39b25d0 254{
9a8c1c2f 255 if (mprotect(address, length, prot) == -1)
256 perror("mprotect");
b39b25d0 257}
b39b25d0 258\f
259
9a8c1c2f 260
261static boolean
262in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
b39b25d0 263{
9a8c1c2f 264 char *beg = (char *) sbeg;
265 char *end = (char *) sbeg + slen;
266 char *adr = (char *) a;
267
268 return (adr >= beg && adr < end);
b39b25d0 269}
270
9a8c1c2f 271boolean
272valid_addr(os_vm_address_t addr)
b39b25d0 273{
9a8c1c2f 274 os_vm_address_t newaddr;
b39b25d0 275
9a8c1c2f 276 newaddr = os_trunc_to_page(addr);
277
44a8f0c7
RT
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)
9a8c1c2f 280 || in_range_p(addr, DYNAMIC_0_SPACE_START, dynamic_space_size)
5d2cd5df 281#ifndef GENCGC
9a8c1c2f 282 || in_range_p(addr, DYNAMIC_1_SPACE_START, dynamic_space_size)
5d2cd5df 283#endif
44a8f0c7
RT
284 || in_range_p(addr, CONTROL_STACK_START, control_stack_size)
285 || in_range_p(addr, BINDING_STACK_START, binding_stack_size))
9a8c1c2f 286 return TRUE;
287 return FALSE;
b39b25d0 288}
b39b25d0 289\f
9a8c1c2f 290
291static void
292sigsegv_handler(HANDLER_ARGS)
b39b25d0 293{
5d2cd5df 294#if defined GENCGC
88a6f6e5 295#if SIGSEGV_VERBOSE
9a8c1c2f 296 caddr_t fault_addr = code ? code->si_addr : 0;
b39b25d0 297
9a8c1c2f 298 fprintf(stderr, "Signal %d, fault_addr=%p, page_index=%d:\n",
299 signal, fault_addr, page_index);
5d2cd5df 300#endif
301
97083c55 302 if (gc_write_barrier(code->si_addr))
9a8c1c2f 303 return;
5d2cd5df 304#endif
b39b25d0 305
9a8c1c2f 306 SAVE_CONTEXT();
b39b25d0 307
9a8c1c2f 308 DPRINTF(0, (stderr, "sigsegv:\n"));
309 interrupt_handle_now(signal, code, context);
b39b25d0 310}
311
9a8c1c2f 312static void
313sigbus_handler(HANDLER_ARGS)
b39b25d0 314{
9a8c1c2f 315 SAVE_CONTEXT();
b39b25d0 316
9a8c1c2f 317 DPRINTF(0, (stderr, "sigbus:\n"));
318 interrupt_handle_now(signal, code, context);
b39b25d0 319}
320
7fbce9e3 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 */
328static void
329sigfpe_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
9a8c1c2f 361void
362os_install_interrupt_handlers(void)
b39b25d0 363{
9a8c1c2f 364 interrupt_install_low_level_handler(SIGSEGV, sigsegv_handler);
365 interrupt_install_low_level_handler(SIGBUS, sigbus_handler);
7fbce9e3 366 interrupt_install_low_level_handler(SIGFPE, sigfpe_handler);
b39b25d0 367}
5d2cd5df 368
369void *
9a8c1c2f 370os_dlsym(const char *sym_name, lispobj lib_list)
5d2cd5df 371{
9a8c1c2f 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;
5d2cd5df 383 }
384 }
9a8c1c2f 385
386 return dlsym(RTLD_DEFAULT, sym_name);
5d2cd5df 387}
7fbce9e3 388
389void
390restore_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
2c2d669d 409 if (fpu_mode == SSE2) {
7fbce9e3 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}
aa9c2237 416
417#ifdef i386
418boolean
419os_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