FBSD: Set KERNBUILDDIR for --with-bsd-kernel-build
[openafs.git] / src / lwp / process.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* process.c - manage lwp context switches be means of setjmp/longjmp. */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
15 #include <roken.h>
16
17 #include <assert.h>
18
19 #include "lwp.h"
20
21 #if defined(AFS_S390_LINUX20_ENV)
22 extern int PRE_Block;           /* used in lwp.c and process.s */
23 #else
24 extern char PRE_Block;          /* used in lwp.c and process.s */
25 #endif
26
27 #if defined(USE_UCONTEXT) && defined(HAVE_UCONTEXT_H)
28
29 afs_int32
30 savecontext(void (*ep) (void), struct lwp_context *savearea, char *newsp)
31 {
32 #if defined(AFS_LINUX20_ENV)
33     /* getcontext does not export stack info */
34     int stackvar;
35 #endif
36
37     PRE_Block = 1;
38
39     savearea->state = 0;
40     getcontext(&savearea->ucontext);
41 #if defined(AFS_LINUX20_ENV)
42     savearea->topstack = (char *)&stackvar;
43 #else
44     savearea->topstack = savearea->ucontext.uc_stack.ss_sp;
45 #endif
46     switch (savearea->state) {
47     case 0:
48         if (newsp) {
49             ucontext_t thread;
50
51             getcontext(&thread);
52             thread.uc_stack.ss_sp =
53                 newsp - AFS_LWP_MINSTACKSIZE + sizeof(void *) +
54                 sizeof(void *);
55             thread.uc_stack.ss_size = AFS_LWP_MINSTACKSIZE - sizeof(void *);
56             makecontext(&thread, ep, 0);
57             setcontext(&thread);
58         } else
59             (*ep) ();
60         break;
61     case 2:
62         break;
63     }
64     return 0;
65 }
66
67 void
68 returnto(struct lwp_context *savearea)
69 {
70     PRE_Block = 0;
71
72     savearea->state = 2;
73     setcontext(&savearea->ucontext);
74 }
75
76 #else
77
78 /*
79  * Magic stack pointer
80  */
81 #if     defined(AFS_SGI64_ENV)
82 # ifdef _BSD_COMPAT
83 #  define LWP_SP 34
84 # else
85 #  define LWP_SP JB_SP
86 # endif
87 #elif   defined(AFS_HPUX_ENV) || defined(AFS_PARISC_LINUX24_ENV)
88 #define LWP_SP  1
89 #elif   defined(AFS_LINUX20_ENV)
90 #if defined(AFS_PPC_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
91 #define LWP_SP 0
92 #elif   defined(AFS_I386_LINUX20_ENV)
93 #define LWP_SP 4
94 #elif   defined(AFS_S390_LINUX20_ENV)
95 #define LWP_SP 9
96 #define LWP_FP 5
97 #elif   defined(AFS_SPARC_LINUX20_ENV)
98 #define LWP_SP 0
99 #define LWP_FP 1
100 #elif   defined(AFS_SPARC64_LINUX20_ENV) && defined(AFS_32BIT_USR_ENV)
101 #define LWP_SP 0
102 #define LWP_FP 1
103 #elif defined(AFS_ALPHA_LINUX20_ENV)
104 #define LWP_SP 8
105 #define LWP_FP 7
106 #elif defined(AFS_PARISC_LINUX24_ENV)
107 #define LWP_SP 19
108 #else
109 #error Unsupported linux LWP system type.
110 #endif
111 #elif   defined(AFS_X86_FBSD_ENV)
112 #define LWP_SP 4
113 #elif   defined(AFS_DARWIN_ENV)
114 #define LWP_SP 16
115 #else
116 Need offset to SP in jmp_buf for this platform.
117 #endif
118 /**
119   * On SGIs the type of the elements of the array passed to setjmp
120   * differs based on the ISA chosen. It is int for mips1 and mips2 and
121   * __uint64_t for mips3 and mips4
122   */
123 #ifdef AFS_SGI64_ENV
124 #if (_MIPS_ISA == _MIPS_ISA_MIPS3 || _MIPS_ISA == _MIPS_ISA_MIPS4)
125 typedef __uint64_t jmp_buf_type;
126 #endif
127 #else
128 #if defined(AFS_ALPHA_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
129 typedef long jmp_buf_type;
130 #else
131 typedef int jmp_buf_type;
132 #endif /*AFS_ALPHA_LINUX20_ENV */
133 #endif /*SGI*/
134
135     static jmp_buf jmp_tmp;
136 static void (*EP) (void);
137 static int rc;
138 static jmp_buf_type *jmpBuffer;
139
140 /** Starting with Glibc 2.4 pointers in jmp_buf are mangled (XOR) for "protection".
141   * On Sparc ucontext functions are not implemented.
142   */
143 #define ptr_mangle(x) (x)
144 #ifdef AFS_LINUX20_ENV
145
146 #ifdef __GLIBC__
147 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 3)
148
149 #if defined(AFS_SPARC64_LINUX24_ENV) || defined(AFS_SPARC_LINUX24_ENV)
150 /* technically we should use POINTER_GUARD
151  * ( == offsetof (tcbhead_t, pointer_guard) )
152  * instead of 0x18
153  */
154 #undef ptr_mangle
155 static int ptr_mangle(int p)
156 {
157     register char *tls_ptr __asm__("%g7");
158     return p ^ *(int*)(tls_ptr + 0x18);
159 }
160 #else
161 #error need ptr_mangle support or use UCONTEXT
162 #endif
163
164 #endif
165 #endif
166 #endif
167
168
169 afs_int32
170 savecontext(void (*ep)(void), struct lwp_context *savearea, char *sp)
171 {
172     int code;
173
174     PRE_Block = 1;
175     EP = ep;
176
177     code = setjmp(savearea->setjmp_buffer);
178     jmpBuffer = (jmp_buf_type *) savearea->setjmp_buffer;
179     savearea->topstack = (char *) ptr_mangle(jmpBuffer[LWP_SP]);
180
181 #if     defined(DEBUG)
182     {
183         int i, *ptr = (int *)savearea->setjmp_buffer;
184         printf("savecontext\n");
185         for (i = 0; i < 5; i++)
186             printf("(%d) 0x%x   ", i, ptr[i]);
187         printf("\n");
188         for (i = 5; i < 10; i++)
189             printf("(%d) 0x%x   ", i, ptr[i]);
190         printf("\n");
191     }
192 #endif
193     switch (code) {
194     case 0:
195         if (!sp)
196             (*EP) ();
197         else {
198             rc = setjmp(jmp_tmp);
199             switch (rc) {
200             case 0:
201                 jmpBuffer = (jmp_buf_type *) jmp_tmp;
202                 jmpBuffer[LWP_SP] = ptr_mangle((jmp_buf_type) sp);
203 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV) || (defined(AFS_SPARC64_LINUX20_ENV) && defined(AFS_32BIT_USR_ENV))
204                 jmpBuffer[LWP_FP] = ptr_mangle((jmp_buf_type) sp);
205 #endif
206                 longjmp(jmp_tmp, 1);
207                 break;
208             case 1:
209                 (*EP) ();
210                 assert(0);      /* never returns */
211                 break;
212             default:
213                 perror("Error in setjmp1\n");
214                 exit(2);
215             }
216         }
217         break;
218     case 2:                     /* restoring frame */
219         break;
220
221     default:
222         perror("Error in setjmp2 : restoring\n");
223         exit(3);
224     }
225     return 0;
226 }
227
228 void
229 returnto(struct lwp_context * savearea)
230 {
231 #if     defined(DEBUG)
232     int i, *ptr = savearea->setjmp_buffer;
233
234     printf("Returning to \n");
235     for (i = 0; i < 5; i++)
236         printf("(%d) 0x%x   ", i, ptr[i]);
237     printf("\n");
238     for (i = 5; i < 10; i++)
239         printf("(%d) 0x%x   ", i, ptr[i]);
240     printf("\n");
241 #endif
242     PRE_Block = 0;
243     longjmp(savearea->setjmp_buffer, 2);
244     return;
245 }
246
247 #endif