]> git.pond.sub.org Git - empserver/blob - src/lib/lwp/arch.c
6a67c16063367a2fced85fa71d7dde8c941d43c6
[empserver] / src / lib / lwp / arch.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2006, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  arch.c: architecture-dependant process context code
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1994
32  *     Steve McClure, 1994-2000
33  */
34
35 #include <config.h>
36
37 #include <stdlib.h>
38 #include "lwp.h"
39 #include "lwpint.h"
40
41 /*
42  * Implement machine-dependent functions lwpNewContext(),
43  * lwpSwitchContext().
44  */
45
46
47 #if defined UCONTEXT
48
49 /*
50  * Alternate aproach using setcontext and getcontext instead of setjmp
51  * and longjump.  This should work on any SVr4 machine independant of
52  * architecture.
53  */
54
55 int
56 lwpNewContext(struct lwpProc *newp, int stacksz)
57 {
58     char *s;
59     int size, redsize;
60
61     /* Make size a multiple of sizeof(long) to keep things aligned */
62     stacksz = (stacksz + sizeof(long) - 1) & -sizeof(long);
63     /* Add a red zone on each side of the stack for LWP_STACKCHECK */
64     redsize = newp->flags & LWP_STACKCHECK ? LWP_REDZONE : 0;
65     size = stacksz + 2 * redsize;
66
67     s = malloc(size);
68     if (!s)
69         return -1;
70
71     newp->sbtm = s;
72     newp->size = size;
73     newp->ustack = s + redsize;
74     newp->usize = stacksz;
75
76     if (getcontext(&newp->context) < 0) {
77         free(s);
78         return -1;
79     }
80 #ifdef MAKECONTEXT_SP_HIGH
81     /*
82      * Known systems that are broken that way: Solaris prior to 10,
83      * IRIX.
84      */
85     newp->context.uc_stack.ss_sp = newp->ustack + stacksz - 8;
86 #else
87     newp->context.uc_stack.ss_sp = newp->ustack;
88 #endif
89     newp->context.uc_stack.ss_size = newp->usize;
90     newp->context.uc_stack.ss_flags = 0;
91     newp->context.uc_link = NULL;
92     makecontext(&newp->context, lwpEntryPoint, 0);
93     return 0;
94 }
95
96 void
97 lwpSwitchContext(struct lwpProc *oldp, struct lwpProc *nextp)
98 {
99     if (!oldp) {
100         setcontext(&nextp->context);
101         abort();
102     } else {
103         if (swapcontext(&oldp->context, &nextp->context) < 0)
104             abort();
105     }
106 }
107
108 #else  /* !UCONTEXT */
109
110 /*
111  * If lwpSave() and lwpRestore() are #def'd to setjmp() and longjmp(),
112  * then lwpInitContext() needs to set up the jmp_buf for a longjmp(),
113  * similar to setjmp().  To figure that out for another machine, check
114  * their source or reverse engineer.
115  */
116
117 #if defined(hpc)
118
119 #define STKALIGN 64
120
121 static struct lwpProc *tempcontext;
122 static struct lwpProc *initcontext = NULL;
123 static int startpoint;
124
125 static void
126 startcontext(void)
127 {
128     int space[10000];
129     int x;
130
131     startpoint = (void *)&x;
132     if (!setjmp(initcontext->context))
133         longjmp(tempcontext->context, 1);
134
135     if (!setjmp(tempcontext->context))
136         longjmp(LwpCurrent->context, 1);
137
138     lwpEntryPoint();
139 }
140
141 static void
142 lwpInitContext(struct lwpProc *newp, void *sp)
143 {
144     struct lwpProc holder;
145     int endpoint;
146
147     if (initcontext == NULL) {
148         initcontext = malloc(sizeof(struct lwpProc));
149         tempcontext = &holder;
150         if (!setjmp(tempcontext->context))
151             startcontext();
152     }
153
154     tempcontext = newp;
155     endpoint = &endpoint;
156     if (endpoint < startpoint) {
157         if (!setjmp(LwpCurrent->context))
158             longjmp(initcontext->context, 1);
159     } else {
160         LwpCurrent->size = endpoint - startpoint;
161         LwpCurrent->sbtm = realloc(LwpCurrent->sbtm, LwpCurrent->size);
162         memcpy(LwpCurrent->sbtm, startpoint, LwpCurrent->size);
163         if (!setjmp(LwpCurrent->context))
164             longjmp(initcontext->context, 1);
165         memcpy(startpoint, LwpCurrent->sbtm, LwpCurrent->size);
166     }
167 }
168
169 static int
170 lwpSave(jmp_buf jb)
171 {
172     int endpoint;
173
174     endpoint = &endpoint;
175     if (initcontext == NULL || endpoint < startpoint)
176         return setjmp(jb, 1);
177
178     LwpCurrent->size = endpoint - startpoint;
179     LwpCurrent->sbtm = realloc(LwpCurrent->sbtm, LwpCurrent->size);
180     memcpy(LwpCurrent->sbtm, startpoint, LwpCurrent->size);
181     if (setjmp(jb, 1)) {
182         memcpy(startpoint, LwpCurrent->sbtm, LwpCurrent->size);
183         return 1;
184     }
185     return 0;
186 }
187
188 #elif defined(hpux)
189
190 #define STKALIGN 64
191
192 static void
193 lwpInitContext(volatile struct lwpProc *volatile newp, void *sp)
194 {
195     static jmp_buf *cpp;
196
197     if (!lwpSave(LwpCurrent->context)) {
198         cpp = (jmp_buf *)&newp->context;
199         asm volatile ("ldw      %0, %%sp"::"o" (sp));
200         if (!lwpSave(*cpp))
201             lwpRestore(LwpCurrent->context);
202         lwpEntryPoint();
203     }
204 }
205
206 static int
207 lwpSave(jmp_buf jb)
208 {
209     /* save stack pointer and return program counter */
210     asm("stw    %sp, 4(%arg0)");
211     asm("stw    %rp, 8(%arg0)");
212
213     /* save "callee save" registers */
214     asm("stw    %r3, 12(%arg0)");
215     asm("stw    %r4, 16(%arg0)");
216     asm("stw    %r5, 20(%arg0)");
217     asm("stw    %r6, 24(%arg0)");
218     asm("stw    %r7, 28(%arg0)");
219     asm("stw    %r8, 32(%arg0)");
220     asm("stw    %r9, 36(%arg0)");
221     asm("stw    %r10, 40(%arg0)");
222     asm("stw    %r11, 44(%arg0)");
223     asm("stw    %r12, 48(%arg0)");
224     asm("stw    %r13, 52(%arg0)");
225     asm("stw    %r14, 56(%arg0)");
226     asm("stw    %r15, 60(%arg0)");
227     asm("stw    %r16, 64(%arg0)");
228     asm("stw    %r17, 68(%arg0)");
229     asm("stw    %r18, 72(%arg0)");
230
231     /* save "callee save" space register */
232     asm volatile ("mfsp %sr3, %r1");
233     asm("stw    %r1, 0(%arg0)");
234
235     /* indicate "true return" from saved() */
236     asm("ldi    0, %ret0");
237
238     asm(".LABEL _comefrom_");
239 }
240
241 static void
242 lwpRestore(jmp_buf jb)
243 {
244     /* restore stack pointer and program counter */
245     asm volatile ("ldw  4(%arg0), %sp");
246     asm volatile ("ldw  8(%arg0), %rp");
247
248     /* restore "callee save" space register */
249     asm volatile ("ldw  0(%arg0), %r1");
250     asm volatile ("mtsp %r1, %sr3");
251
252     /* restore "callee save" registers */
253     asm volatile ("ldw  12(%arg0), %r3");
254     asm volatile ("ldw  16(%arg0), %r4");
255     asm volatile ("ldw  20(%arg0), %r5");
256     asm volatile ("ldw  24(%arg0), %r6");
257     asm volatile ("ldw  28(%arg0), %r7");
258     asm volatile ("ldw  32(%arg0), %r8");
259     asm volatile ("ldw  36(%arg0), %r9");
260     asm volatile ("ldw  40(%arg0), %r10");
261     asm volatile ("ldw  44(%arg0), %r11");
262     asm volatile ("ldw  48(%arg0), %r12");
263     asm volatile ("ldw  52(%arg0), %r13");
264     asm volatile ("ldw  56(%arg0), %r14");
265     asm volatile ("ldw  60(%arg0), %r15");
266     asm volatile ("ldw  64(%arg0), %r16");
267     asm volatile ("ldw  68(%arg0), %r17");
268     asm volatile ("ldw  72(%arg0), %r18");
269
270     /* warp to saved() to unwind the frame correctly */
271     asm volatile ("bl   _comefrom_, %r0");
272     asm volatile ("ldi  1, %ret0");
273 }
274
275 #elif defined(FBSD)
276
277 static void
278 lwpInitContext(struct lwpProc *newp, void *sp)
279 {
280     setjmp(newp->context);
281     newp->context->_jb[2] = (int)sp;
282     newp->context->_jb[3] = (int)sp;
283     newp->context->_jb[0] = (int)lwpEntryPoint;
284 }
285
286 #elif defined(__linux__)
287
288 static void
289 lwpInitContext(struct lwpProc *newp, void *sp)
290 {
291 #if defined(__GLIBC__) && (__GLIBC__ >= 2)
292 #if defined(__PPC__)
293     newp->context->__jmpbuf[JB_GPR1] = (int)sp;
294     newp->context->__jmpbuf[JB_LR] = (int)lwpEntryPoint;
295 #else
296     newp->context->__jmpbuf[JB_SP] = (int)sp;
297     newp->context->__jmpbuf[JB_BP] = (int)sp;
298     newp->context->__jmpbuf[JB_PC] = (int)lwpEntryPoint;
299 #endif
300 #else
301     newp->context->__sp = sp;
302     newp->context->__bp = sp;
303     newp->context->__pc = (void *)lwpEntryPoint;
304 #endif
305 }
306
307 #elif defined(SUN3)
308
309 static void
310 lwpInitContext(struct lwpProc *newp, void *sp)
311 {
312     newp->context[2] = (int)sp;
313     newp->context[3] = (int)lwpEntryPoint;
314 }
315
316 #elif defined(SUN4)
317
318 static void
319 lwpInitContext(struct lwpProc *newp, void *sp)
320 {
321     static jmp_buf *cpp;
322
323     memset(newp->context, 0, sizeof(newp->context));
324     newp->context[0] = (int)sp;
325     /* preserve cpp for new context */
326     cpp = (jmp_buf *) & newp->context;
327     if (!_setjmp(LwpCurrent->context)) {
328         /* create new context */
329         /* flush registers */
330         asm("ta 0x03");
331         /* %o0 <- newp */
332         asm("ld [%fp+0x44], %o0");
333         /* %o1 <- newp->context[0] */
334         asm("ld [%o0], %o1");
335         /* create min frame on new stack */
336         asm("save       %o1,-96, %sp");
337         if (!_setjmp(*cpp))
338             _longjmp(LwpCurrent->context, 1);
339         lwpEntryPoint();
340     }
341 }
342
343 #define lwpSave(x)      _setjmp(x)
344 #define lwpRestore(x)   _longjmp(x, 1)
345
346 #elif defined(ALPHA)
347
348 #include <c_asm.h>
349
350 static void
351 lwpInitContext(struct lwpProc *newp, void *sp)
352 {
353     extern long *_gp;
354
355     /* register values obtained from setjmp.h */
356     _setjmp(newp->context);
357     newp->context[2] = (long)lwpEntryPoint;     /* program counter */
358     newp->context[30] = (long)lwpEntryPoint;    /* return address */
359     newp->context[31] = (long)lwpEntryPoint;    /* fake program value (!) */
360     newp->context[34] = (long)sp;       /* stack pointer */
361 }
362
363 static int
364 lwpSave(jmp_buf jb)
365 {
366     return _setjmp(jb);
367 }
368
369 static void
370 lwpRestore(jmp_buf jb)
371 {
372     /* resume, but get the pv from the jmp_buf */
373     asm("ldq    %pv, 248(%a0)");
374     asm("stq    %a0, 16(%sp)");
375     /* generates a warning, but functions just fine */
376     asm("bsr    %ra, __longjump_resume");
377 }
378
379 #elif defined(AIX32)
380
381 #define LWP_EXTRASTACK 12
382
383 /* Code is in .s files, as compiler doesn't grok asm */
384 extern int lwpSave(jmp_buf);
385 extern void lwpRestore(jmp_buf);
386 extern void lwpInitContext(struct lwpProc *);
387
388 #endif
389
390 #ifndef LWP_EXTRASTACK
391 #define LWP_EXTRASTACK 0
392 #endif
393 #ifndef STKALIGN
394 #define STKALIGN sizeof(double)
395 #endif
396 #ifndef lwpSave
397 #define lwpSave(x)      setjmp(x)
398 #endif
399 #ifndef lwpRestore
400 #define lwpRestore(x)   longjmp(x, 1)
401 #endif
402
403 int
404 lwpNewContext(struct lwpProc *newp, int stacksz)
405 {
406     char *s, *sp;
407     int size, redsize;
408
409     if (CANT_HAPPEN(STKALIGN == 0|| (STKALIGN & (STKALIGN - 1))))
410         return -1;              /* STKALIGN not power of 2 */
411
412     /* Make size a multiple of sizeof(long) to keep things aligned */
413     stacksz = (stacksz + sizeof(long) - 1) & -sizeof(long);
414     /* Add a red zone on each side of the stack for LWP_STACKCHECK */
415     redsize = newp->flags & LWP_STACKCHECK ? LWP_REDZONE : 0;
416     size = stacksz + 2 * redsize + LWP_EXTRASTACK + STKALIGN - 1;
417
418     s = malloc(size);
419     if (!s)
420         return -1;
421
422     if (LwpStackGrowsDown) {
423         /*
424          * Stack layout for stack growing downward:
425          *     ptr        block      size
426          *     --------------------------------------
427          *                red zone   LWP_REDZONE
428          *     sp      -> extra      LWP_EXTRASTACK
429          *     ustack  -> stack      stacksz
430          *                red zone   LWP_REDZONE
431          *                waste      STKALIGN - 1 - x
432          * sp is aligned to a multiple of STKALIGN.
433          */
434         sp = s + redsize + stacksz;
435         sp = (char *)0 + (((sp + STKALIGN - 1) - (char *)0) & -STKALIGN);
436         newp->ustack = sp - stacksz;
437     } else {
438         /*
439          * Stack layout for stack growing upward:
440          *     ptr        block      size
441          *     --------------------------------------
442          *                waste      x
443          *                red zone   LWP_REDZONE
444          *     sp      -> stack      stacksz
445          *     ustack  -> extra      LWP_EXTRASTACK
446          *                red zone   LWP_REDZONE
447          *                waste      STKALIGN - 1 - x
448          * sp is aligned to a multiple of STKALIGN.
449          */
450         sp = s + redsize + LWP_EXTRASTACK;
451         sp = (char *)0 + (((sp + STKALIGN - 1) - (char *)0) & -STKALIGN);
452         newp->ustack = sp - LWP_EXTRASTACK;
453     }
454     newp->sbtm = s;
455     newp->size = size;
456     newp->usize = stacksz + LWP_EXTRASTACK;
457     lwpInitContext(newp, sp);
458     return 0;
459 }
460
461 void
462 lwpSwitchContext(struct lwpProc *oldp, struct lwpProc *nextp)
463 {
464     if (!(oldp && lwpSave(oldp->context)))
465         lwpRestore(nextp->context);
466 }
467
468 #endif /* !UCONTEXT */