a2e72b4a2d26506f82042e6e3d1574c4021b0b94
[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     /* For some reason, PPC Linux appears to default to not generating
46      * floating point exceptions.  PR_SET_FPEXC is a PPC-specific
47      * option new in kernel 2.4.21 and 2.5.32 that allows us to
48      * configure this.  Should we need to run on an older kenel, the
49      * equivalent trick is to get into a signal-handling context and
50      * modify the saved machine state register.
51      *
52      * PR_FP_EXC_PRECISE may be more accurate than we need,
53      * particularly if we move to the x86oid trick of inserting
54      * explicit synchronization for floating-point exception
55      * delivery.  If we wish to move to such a model, the other two
56      * exception delivery modes that we could use are PR_FP_EXC_ASYNC
57      * and PR_FP_EXC_NONRECOV, and exception delivery can be forced
58      * by any access to the FPSCR.  -- AB, 2010-May-23 */
59     prctl(PR_SET_FPEXC, PR_FP_EXC_PRECISE, 0, 0);
60
61     return 1;                   /* success */
62 }
63 int arch_os_thread_cleanup(struct thread *thread) {
64     return 1;                   /* success */
65 }
66
67 os_context_register_t   *
68 os_context_register_addr(os_context_t *context, int offset)
69 {
70 #if defined(GLIBC231_STYLE_UCONTEXT)
71     return &((context->uc_mcontext.regs)->gpr[offset]);
72 #elif defined(GLIBC232_STYLE_UCONTEXT)
73     return &((context->uc_mcontext.uc_regs->gregs)[offset]);
74 #endif
75 }
76
77 os_context_register_t *
78 os_context_pc_addr(os_context_t *context)
79 {
80 #if defined(GLIBC231_STYLE_UCONTEXT)
81     return &((context->uc_mcontext.regs)->nip);
82 #elif defined(GLIBC232_STYLE_UCONTEXT)
83     return &((context->uc_mcontext.uc_regs->gregs)[PT_NIP]);
84 #endif
85 }
86
87 os_context_register_t *
88 os_context_lr_addr(os_context_t *context)
89 {
90 #if defined(GLIBC231_STYLE_UCONTEXT)
91     return &((context->uc_mcontext.regs)->link);
92 #elif defined(GLIBC232_STYLE_UCONTEXT)
93     return &((context->uc_mcontext.uc_regs->gregs)[PT_LNK]);
94 #endif
95 }
96
97 os_context_register_t *
98 os_context_ctr_addr(os_context_t *context)
99 {
100     /* Like os_context_fp_control() and os_context_lr_addr(), this
101      * uses an index beyond the declared end of the array in order to
102      * find the correct register value in the context. */
103 #if defined(GLIBC231_STYLE_UCONTEXT)
104     /* FIXME: This probably should be ->ctr instead of ->gpr[PT_CTR]. */
105     return &((context->uc_mcontext.regs)->gpr[PT_CTR]);
106 #elif defined(GLIBC232_STYLE_UCONTEXT)
107     return &((context->uc_mcontext.uc_regs)->gregs[PT_CTR]);
108 #endif
109 }
110
111 os_context_register_t *
112 os_context_cr_addr(os_context_t *context)
113 {
114     /* Like os_context_fp_control() and os_context_lr_addr(), this
115      * uses an index beyond the declared end of the array in order to
116      * find the correct register value in the context. */
117 #if defined(GLIBC231_STYLE_UCONTEXT)
118     /* FIXME: This probably should be ->ccr instead of ->gpr[PT_CCR]. */
119     return &((context->uc_mcontext.regs)->gpr[PT_CCR]);
120 #elif defined(GLIBC232_STYLE_UCONTEXT)
121     return &((context->uc_mcontext.uc_regs)->gregs[PT_CCR]);
122 #endif
123 }
124
125 sigset_t *
126 os_context_sigmask_addr(os_context_t *context)
127 {
128 #if defined(GLIBC231_STYLE_UCONTEXT)
129     return &context->uc_sigmask;
130 #elif defined(GLIBC232_STYLE_UCONTEXT)
131     return &context->uc_sigmask;
132 #endif
133 }
134
135 unsigned long
136 os_context_fp_control(os_context_t *context)
137 {
138     /* So this may look like nice, well behaved code. However, closer
139        inspection reveals that gpr is simply the general purpose
140        registers, and PT_FPSCR is an offset that is larger than 32
141        (the number of ppc registers), but that happens to get the
142        right answer. -- CSR, 2002-07-11 */
143 #if defined(GLIBC231_STYLE_UCONTEXT)
144     return context->uc_mcontext.regs->gpr[PT_FPSCR];
145 #elif defined(GLIBC232_STYLE_UCONTEXT)
146     return context->uc_mcontext.uc_regs->gregs[PT_FPSCR];
147 #endif
148 }
149
150 void
151 os_restore_fp_control(os_context_t *context)
152 {
153     /* KLUDGE: mtfsf has to be run against a float register, so we
154      * construct the float we need to use as an integer, then cast
155      * a pointer to its storage to a double and load that.  For
156      * this to work, control must be the same width as a double,
157      * 64 bits.  And why aren't we using a union here, anyway? */
158     unsigned long long control;
159     double d;
160
161     /* FIXME: We are only preserving enabled traps and rounding
162      * mode here.  Do we also want to preserve "fast mode"? */
163     control = os_context_fp_control(context) &
164         (FLOAT_TRAPS_BYTE_MASK | FLOAT_ROUNDING_MODE_MASK);
165
166     d = *((double *) &control);
167     asm volatile ("mtfsf 0xff,%0" : : "f" (d));
168 }
169
170 void
171 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
172 {
173     /* see ppc-arch.c */
174     ppc_flush_icache(address,length);
175 }
176