2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure
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.
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.
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
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.
28 * arch.c: architecture-dependant process context code
30 * Known contributors to this file:
32 * Steve McClure, 1994-2000
35 #include "prototypes.h"
37 #if defined(_EMPTH_LWP)
47 static struct lwpProc *tempcontext;
48 struct lwpProc *initcontext=NULL;
56 startpoint = (void *) &x;
57 if (!setjmp(initcontext->context)) longjmp(tempcontext->context,1);
59 if (!setjmp(tempcontext->context)) longjmp(LwpCurrent->context,1);
64 void lwpInitContext(newp, sp)
68 struct lwpProc holder;
71 if (initcontext == NULL) {
72 initcontext = (struct lwpProc *) malloc (sizeof(struct lwpProc));
73 tempcontext = &holder;
74 if (!setjmp(tempcontext->context)) startcontext();
79 if (endpoint < startpoint) {
80 if (!setjmp(LwpCurrent->context)) longjmp(initcontext->context,1);
82 LwpCurrent->size = endpoint - startpoint;
83 LwpCurrent->sbtm = realloc(LwpCurrent->sbtm, LwpCurrent->size);
84 memcpy(LwpCurrent->sbtm, startpoint, LwpCurrent->size);
85 if (!setjmp(LwpCurrent->context)) longjmp(initcontext->context,1);
86 memcpy(startpoint, LwpCurrent->sbtm, LwpCurrent->size);
92 void lwpInitContext(newp, sp)
93 volatile struct lwpProc *volatile newp;
97 extern struct lwpProc *LwpCurrent;
99 if (!lwpSave(LwpCurrent->context)) {
100 cpp = (jmp_buf *)&newp->context;
101 asm volatile ("ldw %0, %%sp": : "o" (sp));
103 lwpRestore(LwpCurrent->context);
111 /* save stack pointer and return program counter */
112 asm ("stw %sp, 4(%arg0)");
113 asm ("stw %rp, 8(%arg0)");
115 /* save "callee save" registers */
116 asm ("stw %r3, 12(%arg0)");
117 asm ("stw %r4, 16(%arg0)");
118 asm ("stw %r5, 20(%arg0)");
119 asm ("stw %r6, 24(%arg0)");
120 asm ("stw %r7, 28(%arg0)");
121 asm ("stw %r8, 32(%arg0)");
122 asm ("stw %r9, 36(%arg0)");
123 asm ("stw %r10, 40(%arg0)");
124 asm ("stw %r11, 44(%arg0)");
125 asm ("stw %r12, 48(%arg0)");
126 asm ("stw %r13, 52(%arg0)");
127 asm ("stw %r14, 56(%arg0)");
128 asm ("stw %r15, 60(%arg0)");
129 asm ("stw %r16, 64(%arg0)");
130 asm ("stw %r17, 68(%arg0)");
131 asm ("stw %r18, 72(%arg0)");
133 /* save "callee save" space register */
134 asm volatile ("mfsp %sr3, %r1");
135 asm ("stw %r1, 0(%arg0)");
137 /* indicate "true return" from saved() */
138 asm ("ldi 0, %ret0");
140 asm (".LABEL _comefrom_");
147 /* restore stack pointer and program counter */
148 asm volatile ("ldw 4(%arg0), %sp");
149 asm volatile ("ldw 8(%arg0), %rp");
151 /* restore "callee save" space register */
152 asm volatile ("ldw 0(%arg0), %r1");
153 asm volatile ("mtsp %r1, %sr3");
155 /* restore "callee save" registers */
156 asm volatile ("ldw 12(%arg0), %r3");
157 asm volatile ("ldw 16(%arg0), %r4");
158 asm volatile ("ldw 20(%arg0), %r5");
159 asm volatile ("ldw 24(%arg0), %r6");
160 asm volatile ("ldw 28(%arg0), %r7");
161 asm volatile ("ldw 32(%arg0), %r8");
162 asm volatile ("ldw 36(%arg0), %r9");
163 asm volatile ("ldw 40(%arg0), %r10");
164 asm volatile ("ldw 44(%arg0), %r11");
165 asm volatile ("ldw 48(%arg0), %r12");
166 asm volatile ("ldw 52(%arg0), %r13");
167 asm volatile ("ldw 56(%arg0), %r14");
168 asm volatile ("ldw 60(%arg0), %r15");
169 asm volatile ("ldw 64(%arg0), %r16");
170 asm volatile ("ldw 68(%arg0), %r17");
171 asm volatile ("ldw 72(%arg0), %r18");
173 /* warp to saved() to unwind the frame correctly */
174 asm volatile ("bl _comefrom_, %r0");
175 asm volatile ("ldi 1, %ret0");
178 #elif defined(BSD386)
179 void lwpInitContext(newp, sp)
180 struct lwpProc *newp;
183 newp->context[2] = (int)sp;
184 newp->context[0] = (int)lwpEntryPoint;
189 void lwpInitContext(newp, sp)
190 struct lwpProc *newp;
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;
199 #elif defined(__linux__)
201 void lwpInitContext(newp, sp)
202 struct lwpProc *newp;
205 #if defined(__GLIBC__) && (__GLIBC__ >= 2)
207 newp->context->__jmpbuf[JB_GPR1] = (int) sp;
208 newp->context->__jmpbuf[JB_LR] = (int) lwpEntryPoint;
210 newp->context->__jmpbuf[JB_SP] = (int) sp;
211 newp->context->__jmpbuf[JB_BP] = (int) sp;
212 newp->context->__jmpbuf[JB_PC] = (int) lwpEntryPoint;
215 newp->context->__sp = sp;
216 newp->context->__bp = sp;
217 newp->context->__pc = (void *)lwpEntryPoint;
223 void lwpInitContext(newp, sp)
224 struct lwpProc *newp;
227 newp->context[2] = (int)sp;
228 newp->context[3] = (int)lwpEntryPoint;
235 void lwpInitContext(newp, stack)
236 struct lwpProc *newp;
239 int *sp = (int*)stack;
242 /* Build root frame on new stack for lwpEntryPoint */
244 *--sp = (int)fp; /* fp */
247 *--sp = 0; /* condition handler */
250 /* Build stack frame to return from. */
251 *--sp = (int)lwpEntryPoint+2;/* pc */
252 *--sp = (int)fp; /* fp */
255 *--sp = 0; /* condition handler */
258 /* Fill in the context */
259 /* Note: This is *not* how libc fills out jump buffers. */
260 newp->context[0] = 0; /* r6 */
261 newp->context[1] = 0;
262 newp->context[2] = 0;
263 newp->context[3] = 0;
264 newp->context[4] = 0;
265 newp->context[5] = 0; /* r11 */
266 newp->context[6] = 0; /* ap */
267 newp->context[7] = (int)fp; /* fp */
274 asm("movl 4(ap), r0"); /* r0 = &jb */
275 asm("movl r6, (r0)"); /* jb[0] = r6 */
276 asm("movl r7, 4(r0)");
277 asm("movl r8, 8(r0)");
278 asm("movl r9, 12(r0)");
279 asm("movl r10, 16(r0)");
280 asm("movl r11, 20(r0)");
281 asm("movl ap, 24(r0)");
282 asm("movl fp, 28(r0)"); /* jb[7] = fp */
289 asm("movl 4(ap), r0"); /* r0 = &jb */
290 asm("movl (r0), r6"); /* r6 = jb[0] */
291 asm("movl 4(r0), r7");
292 asm("movl 8(r0), r8");
293 asm("movl 12(r0), r9");
294 asm("movl 16(r0), r10");
295 asm("movl 20(r0), r11");
296 asm("movl 24(r0), ap");
297 asm("movl 28(r0), fp"); /* fp = jb[7] */
298 asm("movl $1, r0"); /* faked return 1 from lwpSave() */
306 void lwpInitContext(newp, sp)
307 struct lwpProc *newp;
311 extern struct lwpProc *LwpCurrent;
313 bzero(newp->context, sizeof(newp->context));
314 newp->context[0] = (int)sp;
315 /* preserve cpp for new context */
316 cpp = (jmp_buf *)&newp->context;
317 if (!_setjmp(LwpCurrent->context)) {
318 /* create new context */
319 /* flush registers */
322 asm ("ld [%fp+0x44], %o0");
323 /* %o1 <- newp->context[0] */
324 asm ("ld [%o0], %o1");
325 /* create min frame on new stack */
326 asm ("save %o1,-96, %sp");
328 _longjmp(LwpCurrent->context, 1);
333 #elif defined(__USLC__) && defined(i386)
335 /* USL/Unixware on an Intel 386/486/... processor.
336 * Tested on Unixware v1.1.2, based on SYSV R4.2
339 /* As per normal empire documentation, there is none.
341 * But, what we are attempting to do here is set up a longjump
342 * context buffer so that the lwpEntryPoint is called when
345 * I.E., what a setjmp/longjmp call set would do.
347 * How to figure this out? Well, without the setjmp code, you
348 * need to reverse engineer it by printing out the context buffer
349 * and the processor registers, and mapping which ones need
352 * Alternatively, you can single instruction step through the longjmp
353 * function, and figure out the offsets that it uses.
355 * Using offsets in bytes,
356 * context + 0x04 [1] -> esi (general purpose reg)
357 * context + 0x08 [2] -> edi (general purpose reg)
358 * context + 0x0C [3] -> ebp (general purpose or parameter passing)
359 * context + 0x10 [4] -> esp (stack)
360 * context + 0x14 [5] -> jump location for return
363 void lwpInitContext(newp, sp)
364 struct lwpProc *newp;
367 newp->context[4] = (int)sp;
368 newp->context[5] = (int)lwpEntryPoint;
371 #elif defined UCONTEXT
374 * Alternate aproach using setcontext en getcontext in stead of setjmp and
375 * longjump. This should work on any SVr4 machine independant of
376 * architecture. Unfortunaltely some changes are still nessesary in lwp.c.
380 void lwpInitContext(newp, spp)
381 struct lwpProc *newp;
384 getcontext (&(newp->context));
385 newp->context.uc_stack.ss_sp = spp->ss_sp;
386 newp->context.uc_stack.ss_size = spp->ss_size;
387 makecontext (&(newp->context), lwpEntryPoint, 0);
394 void lwpInitContext(newp, sp)
395 struct lwpProc *newp;
400 /* register values obtained from setjmp.h */
401 _setjmp(newp->context);
402 newp->context[2] = (long)lwpEntryPoint; /* program counter */
403 newp->context[30] = (long)lwpEntryPoint; /* return address */
404 newp->context[31] = (long)lwpEntryPoint; /* fake program value (!) */
405 newp->context[34] = (long)sp; /* stack pointer */
417 /* resume, but get the pv from the jmp_buf */
418 asm("ldq %pv, 248(%a0)");
419 asm("stq %a0, 16(%sp)");
420 /* generates a warning, but functions just fine */
421 asm("bsr %ra, __longjump_resume");