Clean up RCS ids
[projects/cmucl/cmucl.git] / src / lisp / Darwin-os.c
1 /*
2  * Darwin-os.c.
3  * From FreeBSD-os.c 1.6 2000/10/24 13:32:30 dtc 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  * Frobbed for OpenBSD by Pierre R. Mai, 2001.
15  * Frobbed for Darwin by Pierre R. Mai, 2003.
16  *
17  */
18
19 #include <stdio.h>
20 #include <sys/param.h>
21 #include <sys/file.h>
22 #include <errno.h>
23 #include <dlfcn.h>
24 #include <string.h>
25 #include "os.h"
26 #include "arch.h"
27 #include "globals.h"
28 #include "interrupt.h"
29 #include "lispregs.h"
30 #include "internals.h"
31 #ifdef GENCGC
32 #include "gencgc.h"
33 #endif
34
35 #include <sys/types.h>
36 #include <signal.h>
37 /* #include <sys/sysinfo.h> */
38 /* #include <sys/proc.h> */
39 /* For timebase info */
40 #include <sys/sysctl.h>
41
42
43 /* Need this to define ppc_saved_state_t (for 10.4) */
44 #include <mach/thread_status.h>
45
46 #include "validate.h"
47 vm_size_t os_vm_page_size;
48
49 \f
50
51 /*
52  * This is accessed by Lisp!  Make this a static symbol?
53  */
54 int cycles_per_tick = 1;
55
56 /*
57  * Compute the conversion factor from the numbef of time base ticks to
58  * clock frequency.  The timebase counter on PPC is not a cycle
59  * counter; we have to derive the relationship ourselves.
60  */
61
62 #ifdef __ppc__
63 void
64 timebase_init(void)
65 {
66     int mib[2];
67     int tbfrequency;
68     int cpufrequency;
69     unsigned int miblen;
70     size_t len;
71
72     mib[0] = CTL_HW;
73 #ifndef HW_TB_FREQ
74     /*
75      * Mac OS X 10.2.8 doesn't have this, so we take it from 10.3.8,
76      * which does.
77      */
78 #define HW_TB_FREQ      23
79 #endif
80     mib[1] = HW_TB_FREQ;
81     miblen = 2;
82     len = sizeof(tbfrequency);
83
84     if (sysctl(mib, miblen, &tbfrequency, &len, NULL, 0) == -1) {
85         perror("Error getting HW_TB_FREQ from sysctl: ");
86     }
87
88     mib[0] = CTL_HW;
89     mib[1] = HW_CPU_FREQ;
90     miblen = 2;
91     len = sizeof(cpufrequency);
92     if (sysctl(mib, miblen, &cpufrequency, &len, NULL, 0) == -1) {
93         perror("Error getting HW_CPU_FREQ from sysctl: ");
94     }
95
96     cycles_per_tick = cpufrequency / tbfrequency;
97 }
98 #endif
99 \f
100
101 void
102 os_init0(const char *argv[], const char *envp[])
103 {}
104
105 void
106 os_init(const char *argv[], const char *envp[])
107 {
108     os_vm_page_size = OS_VM_DEFAULT_PAGESIZE;
109 #ifdef __ppc__
110     timebase_init();
111 #endif
112 }
113
114
115 #if defined(__ppc__)
116 #if __DARWIN_UNIX03
117   /* Nothing needed for 10.5 */
118 #else
119 /* For 10.4 */
120 #define __ss ss
121 #define __r0 r0
122 #define __r1 r1
123 #define __r2 r2
124 #define __r3 r3
125 #define __r4 r4
126 #define __r5 r5
127 #define __r6 r6
128 #define __r7 r7
129 #define __r8 r8
130 #define __r9 r9
131 #define __r10 r10
132 #define __r11 r11
133 #define __r12 r12
134 #define __r13 r13
135 #define __r14 r14
136 #define __r15 r15
137 #define __r16 r16
138 #define __r17 r17
139 #define __r18 r18
140 #define __r19 r19
141 #define __r20 r20
142 #define __r21 r21
143 #define __r22 r22
144 #define __r23 r23
145 #define __r24 r24
146 #define __r25 r25
147 #define __r26 r26
148 #define __r27 r27
149 #define __r28 r28
150 #define __r29 r29
151 #define __r30 r30
152 #define __r31 r31
153 #define __lr lr
154 #define __ctr ctr
155 #define __es es
156 #define __dar dar
157 #define __dsisr dsisr
158 #endif
159
160 unsigned int *
161 sc_reg(os_context_t * context, int offset)
162 {
163     _STRUCT_PPC_THREAD_STATE *state = &context->uc_mcontext->__ss;
164
165     switch (offset) {
166       case 0:
167           return &state->__r0;
168       case 1:
169           return &state->__r1;
170       case 2:
171           return &state->__r2;
172       case 3:
173           return &state->__r3;
174       case 4:
175           return &state->__r4;
176       case 5:
177           return &state->__r5;
178       case 6:
179           return &state->__r6;
180       case 7:
181           return &state->__r7;
182       case 8:
183           return &state->__r8;
184       case 9:
185           return &state->__r9;
186       case 10:
187           return &state->__r10;
188       case 11:
189           return &state->__r11;
190       case 12:
191           return &state->__r12;
192       case 13:
193           return &state->__r13;
194       case 14:
195           return &state->__r14;
196       case 15:
197           return &state->__r15;
198       case 16:
199           return &state->__r16;
200       case 17:
201           return &state->__r17;
202       case 18:
203           return &state->__r18;
204       case 19:
205           return &state->__r19;
206       case 20:
207           return &state->__r20;
208       case 21:
209           return &state->__r21;
210       case 22:
211           return &state->__r22;
212       case 23:
213           return &state->__r23;
214       case 24:
215           return &state->__r24;
216       case 25:
217           return &state->__r25;
218       case 26:
219           return &state->__r26;
220       case 27:
221           return &state->__r27;
222       case 28:
223           return &state->__r28;
224       case 29:
225           return &state->__r29;
226       case 30:
227           return &state->__r30;
228       case 31:
229           return &state->__r31;
230       case 34:
231           /*
232            * Not sure if this is really defined anywhere, but after
233            * r31 is cr, xer, lr, and ctr.  So we let 34 be lr.
234            */
235           return &state->__lr;
236       case 35:
237           return &state->__ctr;
238       case 41:
239           return &context->uc_mcontext->__es.__dar;
240       case 42:
241           return &context->uc_mcontext->__es.__dsisr;
242     }
243
244     return (unsigned int *) 0;
245 }
246 #elif defined(__i386__)
247 #if __DARWIN_UNIX03
248   /* Nothing needed for 10.5 */
249 #else
250   /* This is for 10.4 */
251 #define __ss ss
252 #define __eax eax
253 #define __ecx ecx
254 #define __edx edx
255 #define __ebx ebx
256 #define __esp esp
257 #define __ebp ebp
258 #define __esi esi
259 #define __edi edi
260 #define __eip eip  
261 #define __fs fs
262 #define __fpu_stmm0 fpu_stmm0
263 #define __fpu_stmm1 fpu_stmm1
264 #define __fpu_stmm2 fpu_stmm2
265 #define __fpu_stmm3 fpu_stmm3
266 #define __fpu_stmm4 fpu_stmm4
267 #define __fpu_stmm5 fpu_stmm5
268 #define __fpu_stmm6 fpu_stmm6
269 #define __fpu_stmm7 fpu_stmm7
270 #define __fpu_fcw   fpu_fcw
271 #define __fpu_fsw   fpu_fsw
272 #define __fpu_mxcsr fpu_mxcsr
273 #ifdef FEATURE_SSE2
274 #define __fpu_xmm0 fpu_xmm0
275 #define __fpu_xmm1 fpu_xmm1
276 #define __fpu_xmm2 fpu_xmm2
277 #define __fpu_xmm3 fpu_xmm3
278 #define __fpu_xmm4 fpu_xmm4
279 #define __fpu_xmm5 fpu_xmm5
280 #define __fpu_xmm6 fpu_xmm6
281 #define __fpu_xmm7 fpu_xmm7
282 #endif
283 #endif
284
285 unsigned long *
286 os_sigcontext_reg(ucontext_t *scp, int index)
287 {
288     switch (index) {
289     case 0:
290         return (unsigned long *) &scp->uc_mcontext->__ss.__eax;
291     case 2:
292         return (unsigned long *) &scp->uc_mcontext->__ss.__ecx;
293     case 4:
294         return (unsigned long *) &scp->uc_mcontext->__ss.__edx;
295     case 6:
296         return (unsigned long *) &scp->uc_mcontext->__ss.__ebx;
297     case 8:
298         return (unsigned long *) &scp->uc_mcontext->__ss.__esp;
299     case 10:
300         return (unsigned long *) &scp->uc_mcontext->__ss.__ebp;
301     case 12:
302         return (unsigned long *) &scp->uc_mcontext->__ss.__esi;
303     case 14:
304         return (unsigned long *) &scp->uc_mcontext->__ss.__edi;
305     }
306     return NULL;
307 }
308
309 unsigned long *
310 os_sigcontext_pc(ucontext_t *scp)
311 {
312     return (unsigned long *) &scp->uc_mcontext->__ss.__eip;
313 }
314
315 unsigned char *
316 os_sigcontext_fpu_reg(ucontext_t *scp, int index)
317 {
318     switch (index) {
319     case 0:
320         return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm0;
321     case 1:
322         return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm1;
323     case 2:
324         return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm2;
325     case 3:
326         return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm3;
327     case 4:
328         return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm4;
329     case 5:
330         return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm5;
331     case 6:
332         return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm6;
333     case 7:
334         return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm7;
335 #ifdef FEATURE_SSE2
336     case 8:
337        return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm0;
338     case 9:
339        return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm1;
340     case 10:
341        return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm2;
342     case 11:
343        return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm3;
344     case 12:
345        return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm4;
346     case 13:
347        return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm5;
348     case 14:
349        return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm6;
350     case 15:
351        return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm7;
352 #endif
353     }
354     return NULL;
355 }
356
357 unsigned int
358 os_sigcontext_fpu_modes(ucontext_t *scp)
359 {
360     unsigned int modes;
361     unsigned int mxcsr;
362     unsigned short cw, sw;
363
364     /*
365      * Get the status word and the control word.  
366      */
367     memcpy(&cw, &scp->uc_mcontext->__fs.__fpu_fcw, sizeof(cw));
368     memcpy(&sw, &scp->uc_mcontext->__fs.__fpu_fsw, sizeof(sw));
369
370     /*
371      * Put the cw in the upper bits and the status word in the lower 6
372      * bits, ignoring everything except the exception masks and the
373      * exception flags.
374      */
375     modes = ((cw & 0x3f) << 7) | (sw & 0x3f);
376     
377     DPRINTF(0, (stderr, "FPU modes = %08x (sw =  %4x, cw = %4x)\n",
378                 modes, (unsigned int) sw, (unsigned int) cw));
379
380     if (fpu_mode == SSE2) {
381       mxcsr = scp->uc_mcontext->__fs.__fpu_mxcsr;
382       DPRINTF(0, (stderr, "SSE2 modes = %08x\n", mxcsr));
383
384       modes |= mxcsr;
385     }
386     
387     DPRINTF(0, (stderr, "modes pre mask = %08x\n", modes));
388
389     /* Convert exception mask to exception enable */
390     modes ^= (0x3f << 7);
391     DPRINTF(0, (stderr, "Finale = %08x\n", modes));
392     return modes;
393 }
394
395 void
396 restore_fpu(ucontext_t *scp)
397 {
398     unsigned short cw;
399     unsigned int mxcsr;
400
401     memcpy(&cw, &scp->uc_mcontext->__fs.__fpu_fcw, sizeof(cw));
402     DPRINTF(0, (stderr, "restore_fpu: FPU cw = 0x%x\n", cw));
403     __asm__ __volatile__ ("fclex");
404     __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw));
405             
406     mxcsr = scp->uc_mcontext->__fs.__fpu_mxcsr;
407     DPRINTF(0, (stderr, "restore_fpu:  mxcsr (raw) = %04x\n", mxcsr));
408     __asm__ __volatile__ ("ldmxcsr %0" :: "m" (*&mxcsr));
409 }
410 #endif
411
412 os_vm_address_t
413 os_validate(os_vm_address_t addr, os_vm_size_t len)
414 {
415     int flags = MAP_PRIVATE | MAP_ANON;
416
417     if (addr)
418         flags |= MAP_FIXED;
419
420     DPRINTF(0, (stderr, "os_validate %p %d => ", addr, len));
421
422     addr = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
423
424     if (addr == (os_vm_address_t) - 1) {
425         perror("mmap");
426         return NULL;
427     }
428
429     DPRINTF(0, (stderr, "%p\n", addr));
430
431     return addr;
432 }
433
434 void
435 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
436 {
437     DPRINTF(0, (stderr, "os_invalidate %p %d\n", addr, len));
438
439     if (munmap(addr, len) == -1)
440         perror("munmap");
441 }
442
443 os_vm_address_t
444 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
445 {
446     addr = mmap(addr, len,
447                 OS_VM_PROT_ALL,
448                 MAP_PRIVATE | MAP_FILE | MAP_FIXED, fd, (off_t) offset);
449
450     if (addr == (os_vm_address_t) - 1)
451         perror("mmap");
452
453     return addr;
454 }
455
456 void
457 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
458 {
459 #ifdef __ppc__    
460     /* see ppc-arch.c */
461     ppc_flush_icache(address, length);
462 #endif
463 }
464
465 void
466 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
467 {
468     if (mprotect(address, length, prot) == -1)
469         perror("mprotect");
470 }
471 \f
472
473
474 static boolean
475 in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
476 {
477     char *beg = (char *) sbeg;
478     char *end = (char *) sbeg + slen;
479     char *adr = (char *) a;
480
481     return (adr >= beg && adr < end);
482 }
483
484 boolean
485 valid_addr(os_vm_address_t addr)
486 {
487     os_vm_address_t newaddr;
488
489     newaddr = os_trunc_to_page(addr);
490
491     if (in_range_p(addr, READ_ONLY_SPACE_START, read_only_space_size)
492         || in_range_p(addr, STATIC_SPACE_START, static_space_size)
493         || in_range_p(addr, DYNAMIC_0_SPACE_START, dynamic_space_size)
494 #ifndef GENCGC
495         || in_range_p(addr, DYNAMIC_1_SPACE_START, dynamic_space_size)
496 #endif
497         || in_range_p(addr, CONTROL_STACK_START, control_stack_size)
498         || in_range_p(addr, BINDING_STACK_START, binding_stack_size))
499         return TRUE;
500     return FALSE;
501 }
502 \f
503 static void
504 sigbus_handle_now(HANDLER_ARGS)
505 {
506     interrupt_handle_now(signal, code, context);
507 }
508
509 static void
510 sigbus_handler(HANDLER_ARGS)
511 {
512     os_context_t *os_context = (os_context_t *) context;
513 #if defined(GENCGC)
514     caddr_t fault_addr = code->si_addr;
515 #endif
516     
517 #ifdef RED_ZONE_HIT
518     if (os_control_stack_overflow((void *) fault_addr, os_context))
519        return;
520 #endif
521
522 #ifdef __ppc__
523     DPRINTF(0, (stderr, "sigbus:\n"));
524     DPRINTF(0, (stderr, " PC       = %p\n", SC_PC(os_context)));
525     DPRINTF(0, (stderr, " ALLOC-TN = %p\n", SC_REG(os_context, reg_ALLOC)));
526     DPRINTF(0, (stderr, " CODE-TN  = %p\n", SC_REG(os_context, reg_CODE)));
527     DPRINTF(0, (stderr, " LRA-TN   = %p\n", SC_REG(os_context, reg_LRA)));
528     DPRINTF(0, (stderr, " CFP-TN   = %p\n", SC_REG(os_context, reg_CFP)));
529     DPRINTF(0, (stderr, " FDEFN-TN = %p\n", SC_REG(os_context, reg_FDEFN)));
530     DPRINTF(0, (stderr, " foreign_function_call = %d\n", foreign_function_call_active));
531 #endif
532     
533 #if defined(GENCGC)
534 #if defined(SIGSEGV_VERBOSE)
535     fprintf(stderr, "Signal %d, fault_addr=%x, page_index=%d:\n",
536             signal, fault_addr, page_index);
537 #endif
538     if (gc_write_barrier(code->si_addr))
539          return;
540 #else
541     if (interrupt_maybe_gc(signal, code, os_context))
542         return;
543 #endif
544     /* a *real* protection fault */
545     fprintf(stderr, "sigbus_handler: Real protection violation at %p, PC = %p\n",
546             fault_addr, (void *) SC_PC(os_context));
547     sigbus_handle_now(signal, code, os_context);
548 #ifdef __ppc__
549     /* Work around G5 bug; fix courtesy gbyers via chandler */
550     sigreturn(os_context);
551 #endif
552 }
553
554 void
555 os_install_interrupt_handlers(void)
556 {
557     interrupt_install_low_level_handler(SIGBUS, sigbus_handler);
558 }
559
560 void *
561 os_dlsym(const char *sym_name, lispobj lib_list)
562 {
563     static void *program_handle;
564     void *sym_addr = 0;
565
566     if (!program_handle)
567         program_handle = dlopen((void *) 0, RTLD_LAZY | RTLD_GLOBAL);
568     if (lib_list != NIL) {
569         lispobj lib_list_head;
570
571         for (lib_list_head = lib_list;
572              lib_list_head != NIL; lib_list_head = (CONS(lib_list_head))->cdr) {
573             struct cons *lib_cons = CONS(CONS(lib_list_head)->car);
574             struct sap *dlhandle = (struct sap *) PTR(lib_cons->car);
575
576             sym_addr = dlsym((void *) dlhandle->pointer, sym_name);
577             if (sym_addr)
578                 return sym_addr;
579         }
580     }
581     sym_addr = dlsym(program_handle, sym_name);
582
583     return sym_addr;
584 }
585
586 #ifdef i386
587 boolean
588 os_support_sse2()
589 {
590     return TRUE;
591 }
592 #endif