win32-os.c: Split up handle_exception
[sbcl.git] / src / runtime / ppc-linux-os.c
1 /*
2  * This is the IBM/Motorola/Apple/whoever Linux incarnation of
3  * arch-dependent OS-dependent routines. See also "linux-os.c".  */
4
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
9  * This software is derived from the CMU CL system, which was
10  * written at Carnegie Mellon University and released into the
11  * public domain. The software is in the public domain and is
12  * provided with absolutely no warranty. See the COPYING and CREDITS
13  * files for more information.
14  */
15
16 /* These header files were lifted wholesale from linux-os.c, some may
17  * be redundant. -- Dan Barlow ca. 2001-05-01 */
18 #include <stdio.h>
19 #include <sys/param.h>
20 #include <sys/file.h>
21 #include "sbcl.h"
22 #include "./signal.h"
23 #include "os.h"
24 #include "arch.h"
25 #include "globals.h"
26 #include "interrupt.h"
27 #include "interr.h"
28 #include "lispregs.h"
29 #include <sys/socket.h>
30 #include <sys/utsname.h>
31
32 #include <sys/types.h>
33 #include <signal.h>
34 #include <sys/time.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <sys/prctl.h>
38
39 #include "validate.h"
40 #include "ppc-linux-mcontext.h"
41
42 size_t os_vm_page_size;
43
44 int arch_os_thread_init(struct thread *thread) {
45 #if defined(LISP_FEATURE_SB_THREAD)
46     pthread_setspecific(specials,thread);
47 #endif
48
49     /* For some reason, PPC Linux appears to default to not generating
50      * floating point exceptions.  PR_SET_FPEXC is a PPC-specific
51      * option new in kernel 2.4.21 and 2.5.32 that allows us to
52      * configure this.  Should we need to run on an older kenel, the
53      * equivalent trick is to get into a signal-handling context and
54      * modify the saved machine state register.
55      *
56      * PR_FP_EXC_PRECISE may be more accurate than we need,
57      * particularly if we move to the x86oid trick of inserting
58      * explicit synchronization for floating-point exception
59      * delivery.  If we wish to move to such a model, the other two
60      * exception delivery modes that we could use are PR_FP_EXC_ASYNC
61      * and PR_FP_EXC_NONRECOV, and exception delivery can be forced
62      * by any access to the FPSCR.  -- AB, 2010-May-23 */
63     prctl(PR_SET_FPEXC, PR_FP_EXC_PRECISE, 0, 0);
64
65     return 1;                   /* success */
66 }
67 int arch_os_thread_cleanup(struct thread *thread) {
68     return 1;                   /* success */
69 }
70
71 os_context_register_t   *
72 os_context_register_addr(os_context_t *context, int offset)
73 {
74 #if defined(GLIBC231_STYLE_UCONTEXT)
75     return &((context->uc_mcontext.regs)->gpr[offset]);
76 #elif defined(GLIBC232_STYLE_UCONTEXT)
77     return &((context->uc_mcontext.uc_regs->gregs)[offset]);
78 #endif
79 }
80
81 os_context_register_t *
82 os_context_pc_addr(os_context_t *context)
83 {
84 #if defined(GLIBC231_STYLE_UCONTEXT)
85     return &((context->uc_mcontext.regs)->nip);
86 #elif defined(GLIBC232_STYLE_UCONTEXT)
87     return &((context->uc_mcontext.uc_regs->gregs)[PT_NIP]);
88 #endif
89 }
90
91 os_context_register_t *
92 os_context_lr_addr(os_context_t *context)
93 {
94 #if defined(GLIBC231_STYLE_UCONTEXT)
95     return &((context->uc_mcontext.regs)->link);
96 #elif defined(GLIBC232_STYLE_UCONTEXT)
97     return &((context->uc_mcontext.uc_regs->gregs)[PT_LNK]);
98 #endif
99 }
100
101 os_context_register_t *
102 os_context_ctr_addr(os_context_t *context)
103 {
104     /* Like os_context_fp_control() and os_context_lr_addr(), this
105      * uses an index beyond the declared end of the array in order to
106      * find the correct register value in the context. */
107 #if defined(GLIBC231_STYLE_UCONTEXT)
108     /* FIXME: This probably should be ->ctr instead of ->gpr[PT_CTR]. */
109     return &((context->uc_mcontext.regs)->gpr[PT_CTR]);
110 #elif defined(GLIBC232_STYLE_UCONTEXT)
111     return &((context->uc_mcontext.uc_regs)->gregs[PT_CTR]);
112 #endif
113 }
114
115 os_context_register_t *
116 os_context_cr_addr(os_context_t *context)
117 {
118     /* Like os_context_fp_control() and os_context_lr_addr(), this
119      * uses an index beyond the declared end of the array in order to
120      * find the correct register value in the context. */
121 #if defined(GLIBC231_STYLE_UCONTEXT)
122     /* FIXME: This probably should be ->ccr instead of ->gpr[PT_CCR]. */
123     return &((context->uc_mcontext.regs)->gpr[PT_CCR]);
124 #elif defined(GLIBC232_STYLE_UCONTEXT)
125     return &((context->uc_mcontext.uc_regs)->gregs[PT_CCR]);
126 #endif
127 }
128
129 sigset_t *
130 os_context_sigmask_addr(os_context_t *context)
131 {
132 #if defined(GLIBC231_STYLE_UCONTEXT)
133     return &context->uc_sigmask;
134 #elif defined(GLIBC232_STYLE_UCONTEXT)
135     return &context->uc_sigmask;
136 #endif
137 }
138
139 unsigned long
140 os_context_fp_control(os_context_t *context)
141 {
142     /* So this may look like nice, well behaved code. However, closer
143        inspection reveals that gpr is simply the general purpose
144        registers, and PT_FPSCR is an offset that is larger than 32
145        (the number of ppc registers), but that happens to get the
146        right answer. -- CSR, 2002-07-11 */
147 #if defined(GLIBC231_STYLE_UCONTEXT)
148     return context->uc_mcontext.regs->gpr[PT_FPSCR];
149 #elif defined(GLIBC232_STYLE_UCONTEXT)
150     return context->uc_mcontext.uc_regs->gregs[PT_FPSCR];
151 #endif
152 }
153
154 void
155 os_restore_fp_control(os_context_t *context)
156 {
157     /* KLUDGE: mtfsf has to be run against a float register, so we
158      * construct the float we need to use as an integer, then cast
159      * a pointer to its storage to a double and load that.  For
160      * this to work, control must be the same width as a double,
161      * 64 bits.  And why aren't we using a union here, anyway? */
162     unsigned long long control;
163     double d;
164
165     /* FIXME: We are only preserving enabled traps and rounding
166      * mode here.  Do we also want to preserve "fast mode"? */
167     control = os_context_fp_control(context) &
168         (FLOAT_TRAPS_BYTE_MASK | FLOAT_ROUNDING_MODE_MASK);
169
170     d = *((double *) &control);
171     asm volatile ("mtfsf 0xff,%0" : : "f" (d));
172 }
173
174 void
175 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
176 {
177     /* see ppc-arch.c */
178     ppc_flush_icache(address,length);
179 }
180