/[cmucl]/src/lisp/NetBSD-os.c
ViewVC logotype

Contents of /src/lisp/NetBSD-os.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.20 - (show annotations)
Thu Sep 1 05:18:26 2011 UTC (2 years, 7 months ago) by rtoy
Branch: MAIN
CVS Tags: GIT-CONVERSION, snapshot-2011-09, HEAD
Changes since 1.19: +5 -1 lines
File MIME type: text/plain
Add os_init0 to allow for some really early OS inits.

On Linux, os_init can re-exec lisp to set up the correct personality.
Not normally a problem, but if any output happens before os_init is
called, the output appears to happen twice.  So add os_init0 to do
this early on, before any output.  This is a bit of a kludge.

lisp/lisp.c:
o Call os_init0 early in main.

lisp/Linux-os.c:
o Move the personality stuff from os_init to os_init0.

lisp/Darwin-os.c:
lisp/FreeBSD-os.c:
lisp/NetBSD-os.c:
lisp/OpenBSD-os.c:
lisp/hpux-os.c:
lisp/irix-os.c:
lisp/mach-os.c:
lisp/osf1-os.c:
lisp/solaris-os.c:
lisp/sunos-os.c:
o Add dummy implementation of os_init0.  These OSes don't (currently)
  need anything special.

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

  ViewVC Help
Powered by ViewVC 1.1.5