]> git.pond.sub.org Git - empserver/blob - src/lib/lwp/arch.c
Update copyright notice.
[empserver] / src / lib / lwp / arch.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, 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 "prototypes.h"
36
37 #if defined(_EMPTH_LWP)
38
39 #if (!defined(AIX32))
40
41 #include "lwp.h"
42
43 #include "lwpint.h"
44
45 #if defined(hpc)
46
47 static struct lwpProc *tempcontext;
48 struct lwpProc *initcontext = NULL;
49 int startpoint;
50
51 static void
52 startcontext(void)
53 {
54     int space[10000];
55     int x;
56
57     startpoint = (void *)&x;
58     if (!setjmp(initcontext->context))
59         longjmp(tempcontext->context, 1);
60
61     if (!setjmp(tempcontext->context))
62         longjmp(LwpCurrent->context, 1);
63
64     lwpEntryPoint();
65 }
66
67 void
68 lwpInitContext(struct lwpProc *newp, void *sp)
69 {
70     struct lwpProc holder;
71     int endpoint;
72
73     if (initcontext == NULL) {
74         initcontext = (struct lwpProc *)malloc(sizeof(struct lwpProc));
75         tempcontext = &holder;
76         if (!setjmp(tempcontext->context))
77             startcontext();
78     }
79
80     tempcontext = newp;
81     endpoint = &endpoint;
82     if (endpoint < startpoint) {
83         if (!setjmp(LwpCurrent->context))
84             longjmp(initcontext->context, 1);
85     } else {
86         LwpCurrent->size = endpoint - startpoint;
87         LwpCurrent->sbtm = realloc(LwpCurrent->sbtm, LwpCurrent->size);
88         memcpy(LwpCurrent->sbtm, startpoint, LwpCurrent->size);
89         if (!setjmp(LwpCurrent->context))
90             longjmp(initcontext->context, 1);
91         memcpy(startpoint, LwpCurrent->sbtm, LwpCurrent->size);
92     }
93 }
94
95 #elif defined(hpux)
96
97 void
98 lwpInitContext(volatile struct lwpProc *volatile newp, void *sp)
99 {
100     static jmp_buf *cpp;
101
102     if (!lwpSave(LwpCurrent->context)) {
103         cpp = (jmp_buf *) & newp->context;
104         asm volatile ("ldw      %0, %%sp"::"o" (sp));
105         if (!lwpSave(*cpp))
106             lwpRestore(LwpCurrent->context);
107         lwpEntryPoint();
108     }
109 }
110
111 int
112 lwpSave(jmp_buf jb)
113 {
114     /* save stack pointer and return program counter */
115     asm("stw    %sp, 4(%arg0)");
116     asm("stw    %rp, 8(%arg0)");
117
118     /* save "callee save" registers */
119     asm("stw    %r3, 12(%arg0)");
120     asm("stw    %r4, 16(%arg0)");
121     asm("stw    %r5, 20(%arg0)");
122     asm("stw    %r6, 24(%arg0)");
123     asm("stw    %r7, 28(%arg0)");
124     asm("stw    %r8, 32(%arg0)");
125     asm("stw    %r9, 36(%arg0)");
126     asm("stw    %r10, 40(%arg0)");
127     asm("stw    %r11, 44(%arg0)");
128     asm("stw    %r12, 48(%arg0)");
129     asm("stw    %r13, 52(%arg0)");
130     asm("stw    %r14, 56(%arg0)");
131     asm("stw    %r15, 60(%arg0)");
132     asm("stw    %r16, 64(%arg0)");
133     asm("stw    %r17, 68(%arg0)");
134     asm("stw    %r18, 72(%arg0)");
135
136     /* save "callee save" space register */
137     asm volatile ("mfsp %sr3, %r1");
138     asm("stw    %r1, 0(%arg0)");
139
140     /* indicate "true return" from saved() */
141     asm("ldi    0, %ret0");
142
143     asm(".LABEL _comefrom_");
144 }
145
146 void
147 lwpRestore(jmp_buf jb)
148 {
149     /* restore stack pointer and program counter */
150     asm volatile ("ldw  4(%arg0), %sp");
151     asm volatile ("ldw  8(%arg0), %rp");
152
153     /* restore "callee save" space register */
154     asm volatile ("ldw  0(%arg0), %r1");
155     asm volatile ("mtsp %r1, %sr3");
156
157     /* restore "callee save" registers */
158     asm volatile ("ldw  12(%arg0), %r3");
159     asm volatile ("ldw  16(%arg0), %r4");
160     asm volatile ("ldw  20(%arg0), %r5");
161     asm volatile ("ldw  24(%arg0), %r6");
162     asm volatile ("ldw  28(%arg0), %r7");
163     asm volatile ("ldw  32(%arg0), %r8");
164     asm volatile ("ldw  36(%arg0), %r9");
165     asm volatile ("ldw  40(%arg0), %r10");
166     asm volatile ("ldw  44(%arg0), %r11");
167     asm volatile ("ldw  48(%arg0), %r12");
168     asm volatile ("ldw  52(%arg0), %r13");
169     asm volatile ("ldw  56(%arg0), %r14");
170     asm volatile ("ldw  60(%arg0), %r15");
171     asm volatile ("ldw  64(%arg0), %r16");
172     asm volatile ("ldw  68(%arg0), %r17");
173     asm volatile ("ldw  72(%arg0), %r18");
174
175     /* warp to saved() to unwind the frame correctly */
176     asm volatile ("bl   _comefrom_, %r0");
177     asm volatile ("ldi  1, %ret0");
178 }
179
180 #elif defined(BSD386)
181 void
182 lwpInitContext(struct lwpProc *newp, void *sp)
183 {
184     newp->context[2] = (int)sp;
185     newp->context[0] = (int)lwpEntryPoint;
186 }
187
188 #elif defined(FBSD)
189
190 void
191 lwpInitContext(struct lwpProc *newp, void *sp)
192 {
193     setjmp(newp->context);
194     newp->context->_jb[2] = (int)sp;
195     newp->context->_jb[3] = (int)sp;
196     newp->context->_jb[0] = (int)lwpEntryPoint;
197 }
198
199 #elif defined(__linux__)
200
201 void
202 lwpInitContext(struct lwpProc *newp, void *sp)
203 {
204 #if defined(__GLIBC__) && (__GLIBC__ >= 2)
205 #if defined(__PPC__)
206     newp->context->__jmpbuf[JB_GPR1] = (int)sp;
207     newp->context->__jmpbuf[JB_LR] = (int)lwpEntryPoint;
208 #else
209     newp->context->__jmpbuf[JB_SP] = (int)sp;
210     newp->context->__jmpbuf[JB_BP] = (int)sp;
211     newp->context->__jmpbuf[JB_PC] = (int)lwpEntryPoint;
212 #endif
213 #else
214     newp->context->__sp = sp;
215     newp->context->__bp = sp;
216     newp->context->__pc = (void *)lwpEntryPoint;
217 #endif
218 }
219
220 #elif defined(SUN3)
221
222 void
223 lwpInitContext(struct lwpProc *newp, void *sp)
224 {
225     newp->context[2] = (int)sp;
226     newp->context[3] = (int)lwpEntryPoint;
227 }
228
229 #elif defined(__vax)
230
231 #include <stdio.h>
232
233 void
234 lwpInitContext(struct lwpProc *newp, void *stack)
235 {
236     int *sp = (int *)stack;
237     int *fp = 0;
238
239     /* Build root frame on new stack for lwpEntryPoint */
240     *--sp = 0;                  /* pc */
241     *--sp = (int)fp;            /* fp */
242     *--sp = 0;                  /* ap */
243     *--sp = 0;                  /* psw  */
244     *--sp = 0;                  /* condition handler */
245     fp = sp;
246
247     /* Build stack frame to return from. */
248     *--sp = (int)lwpEntryPoint + 2;     /* pc */
249     *--sp = (int)fp;            /* fp */
250     *--sp = 0;                  /* ap */
251     *--sp = 0;                  /* psw  */
252     *--sp = 0;                  /* condition handler */
253     fp = sp;
254
255     /* Fill in the context */
256     /* Note: This is *not* how libc fills out jump buffers. */
257     newp->context[0] = 0;       /* r6 */
258     newp->context[1] = 0;
259     newp->context[2] = 0;
260     newp->context[3] = 0;
261     newp->context[4] = 0;
262     newp->context[5] = 0;       /* r11 */
263     newp->context[6] = 0;       /* ap */
264     newp->context[7] = (int)fp; /* fp */
265     return;
266 }
267
268 int
269 lwpSave(jmp_buf jb)
270 {
271     asm("movl 4(ap), r0");      /* r0 = &jb */
272     asm("movl r6, (r0)");       /* jb[0] = r6 */
273     asm("movl r7, 4(r0)");
274     asm("movl r8, 8(r0)");
275     asm("movl r9, 12(r0)");
276     asm("movl r10, 16(r0)");
277     asm("movl r11, 20(r0)");
278     asm("movl ap, 24(r0)");
279     asm("movl fp, 28(r0)");     /* jb[7] = fp */
280     return 0;
281 }
282
283 void
284 lwpRestore(jmp_buf jb)
285 {
286     asm("movl 4(ap), r0");      /* r0 = &jb */
287     asm("movl (r0), r6");       /* r6 = jb[0] */
288     asm("movl 4(r0), r7");
289     asm("movl 8(r0), r8");
290     asm("movl 12(r0), r9");
291     asm("movl 16(r0), r10");
292     asm("movl 20(r0), r11");
293     asm("movl 24(r0), ap");
294     asm("movl 28(r0), fp");     /* fp = jb[7] */
295     asm("movl $1, r0");         /* faked return 1 from lwpSave() */
296     asm("ret");
297     return;
298 }
299
300
301 #elif defined(SUN4)
302
303 void
304 lwpInitContext(struct lwpProc *newp, void *sp)
305 {
306     static jmp_buf *cpp;
307
308     memset(newp->context, 0, sizeof(newp->context));
309     newp->context[0] = (int)sp;
310     /* preserve cpp for new context */
311     cpp = (jmp_buf *) & newp->context;
312     if (!_setjmp(LwpCurrent->context)) {
313         /* create new context */
314         /* flush registers */
315         asm("ta 0x03");
316         /* %o0 <- newp */
317         asm("ld [%fp+0x44], %o0");
318         /* %o1 <- newp->context[0] */
319         asm("ld [%o0], %o1");
320         /* create min frame on new stack */
321         asm("save       %o1,-96, %sp");
322         if (!_setjmp(*cpp))
323             _longjmp(LwpCurrent->context, 1);
324         lwpEntryPoint();
325     }
326 }
327
328 #elif defined(__USLC__) && defined(i386)
329
330 /* USL/Unixware on an Intel 386/486/... processor.
331  * Tested on Unixware v1.1.2, based on SYSV R4.2
332  */
333
334 /* As per normal empire documentation, there is none.
335  *
336  * But, what we are attempting to do here is set up a longjump
337  * context buffer so that the lwpEntryPoint is called when
338  * the thread starts.
339  *
340  * I.E., what a setjmp/longjmp call set would do.
341  *
342  * How to figure this out?  Well, without the setjmp code, you
343  * need to reverse engineer it by printing out the context buffer
344  * and the processor registers, and mapping which ones need
345  * to be set.
346  *
347  * Alternatively, you can single instruction step through the longjmp
348  * function, and figure out the offsets that it uses.
349  *
350  * Using offsets in bytes,
351  * context + 0x04 [1] -> esi  (general purpose reg)
352  * context + 0x08 [2] -> edi  (general purpose reg)
353  * context + 0x0C [3] -> ebp  (general purpose or parameter passing)
354  * context + 0x10 [4] -> esp  (stack)
355  * context + 0x14 [5] -> jump location for return
356  */
357
358 void
359 lwpInitContext(struct lwpProc *newp, void *sp)
360 {
361     newp->context[4] = (int)sp;
362     newp->context[5] = (int)lwpEntryPoint;
363 }
364
365 #elif defined UCONTEXT
366
367 /*
368  * Alternate aproach using setcontext en getcontext in stead of setjmp and
369  * longjump. This should work on any SVr4 machine independant of
370  * architecture. Unfortunaltely some changes are still nessesary in lwp.c.
371  * Tested on IRIX 5.3
372  */
373
374 void
375 lwpInitContext(struct lwpProc *newp, stack_t *spp)
376 {
377     getcontext(&(newp->context));
378     newp->context.uc_stack.ss_sp = spp->ss_sp;
379     newp->context.uc_stack.ss_size = spp->ss_size;
380     makecontext(&(newp->context), lwpEntryPoint, 0);
381 }
382
383 #elif defined(ALPHA)
384
385 #include <c_asm.h>
386
387 void
388 lwpInitContext(struct lwpProc *newp, void *sp)
389 {
390     extern long *_gp;
391
392     /* register values obtained from setjmp.h */
393     _setjmp(newp->context);
394     newp->context[2] = (long)lwpEntryPoint;     /* program counter */
395     newp->context[30] = (long)lwpEntryPoint;    /* return address */
396     newp->context[31] = (long)lwpEntryPoint;    /* fake program value (!) */
397     newp->context[34] = (long)sp;       /* stack pointer */
398 }
399
400 int
401 lwpSave(jmp_buf jb)
402 {
403     return _setjmp(jb);
404 }
405
406 void
407 lwpRestore(jmp_buf jb)
408 {
409     /* resume, but get the pv from the jmp_buf */
410     asm("ldq    %pv, 248(%a0)");
411     asm("stq    %a0, 16(%sp)");
412     /* generates a warning, but functions just fine */
413     asm("bsr    %ra, __longjump_resume");
414 }
415
416 #endif
417
418 #endif
419
420 #endif