2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1994-2006, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure
5 * Copyright (C) 1991-3 Stephen Crane
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
24 * related information and legal notices. It is expected that any future
25 * projects/authors will amend these files as needed.
29 * arch.c: architecture-dependant process context code
31 * Known contributors to this file:
33 * Steve McClure, 1994-2000
34 * Markus Armbruster, 2004-2006
44 * Implement machine-dependent functions lwpNewContext(),
52 * Alternate aproach using setcontext and getcontext instead of setjmp
53 * and longjump. This should work on any SVr4 machine independant of
58 lwpNewContext(struct lwpProc *newp, int stacksz)
63 /* Make size a multiple of sizeof(long) to keep things aligned */
64 stacksz = (stacksz + sizeof(long) - 1) & -sizeof(long);
65 /* Add a red zone on each side of the stack for LWP_STACKCHECK */
66 redsize = newp->flags & LWP_STACKCHECK ? LWP_REDZONE : 0;
67 size = stacksz + 2 * redsize;
75 newp->ustack = s + redsize;
76 newp->usize = stacksz;
78 if (getcontext(&newp->context) < 0) {
82 #ifdef MAKECONTEXT_SP_HIGH
84 * Known systems that are broken that way: Solaris prior to 10,
87 newp->context.uc_stack.ss_sp = newp->ustack + stacksz - 8;
89 newp->context.uc_stack.ss_sp = newp->ustack;
91 newp->context.uc_stack.ss_size = newp->usize;
92 newp->context.uc_stack.ss_flags = 0;
93 newp->context.uc_link = NULL;
94 makecontext(&newp->context, lwpEntryPoint, 0);
99 lwpSwitchContext(struct lwpProc *oldp, struct lwpProc *nextp)
102 setcontext(&nextp->context);
105 if (swapcontext(&oldp->context, &nextp->context) < 0)
110 #else /* !UCONTEXT */
113 * If lwpSave() and lwpRestore() are #def'd to setjmp() and longjmp(),
114 * then lwpInitContext() needs to set up the jmp_buf for a longjmp(),
115 * similar to setjmp(). To figure that out for another machine, check
116 * their source or reverse engineer.
123 static struct lwpProc *tempcontext;
124 static struct lwpProc *initcontext = NULL;
125 static int startpoint;
133 startpoint = (void *)&x;
134 if (!setjmp(initcontext->context))
135 longjmp(tempcontext->context, 1);
137 if (!setjmp(tempcontext->context))
138 longjmp(LwpCurrent->context, 1);
144 lwpInitContext(struct lwpProc *newp, void *sp)
146 struct lwpProc holder;
149 if (initcontext == NULL) {
150 initcontext = malloc(sizeof(struct lwpProc));
151 tempcontext = &holder;
152 if (!setjmp(tempcontext->context))
157 endpoint = &endpoint;
158 if (endpoint < startpoint) {
159 if (!setjmp(LwpCurrent->context))
160 longjmp(initcontext->context, 1);
162 LwpCurrent->size = endpoint - startpoint;
163 LwpCurrent->sbtm = realloc(LwpCurrent->sbtm, LwpCurrent->size);
164 memcpy(LwpCurrent->sbtm, startpoint, LwpCurrent->size);
165 if (!setjmp(LwpCurrent->context))
166 longjmp(initcontext->context, 1);
167 memcpy(startpoint, LwpCurrent->sbtm, LwpCurrent->size);
176 endpoint = &endpoint;
177 if (initcontext == NULL || endpoint < startpoint)
178 return setjmp(jb, 1);
180 LwpCurrent->size = endpoint - startpoint;
181 LwpCurrent->sbtm = realloc(LwpCurrent->sbtm, LwpCurrent->size);
182 memcpy(LwpCurrent->sbtm, startpoint, LwpCurrent->size);
184 memcpy(startpoint, LwpCurrent->sbtm, LwpCurrent->size);
195 lwpInitContext(volatile struct lwpProc *volatile newp, void *sp)
199 if (!lwpSave(LwpCurrent->context)) {
200 cpp = (jmp_buf *)&newp->context;
201 asm volatile ("ldw %0, %%sp"::"o" (sp));
203 lwpRestore(LwpCurrent->context);
211 /* save stack pointer and return program counter */
212 asm("stw %sp, 4(%arg0)");
213 asm("stw %rp, 8(%arg0)");
215 /* save "callee save" registers */
216 asm("stw %r3, 12(%arg0)");
217 asm("stw %r4, 16(%arg0)");
218 asm("stw %r5, 20(%arg0)");
219 asm("stw %r6, 24(%arg0)");
220 asm("stw %r7, 28(%arg0)");
221 asm("stw %r8, 32(%arg0)");
222 asm("stw %r9, 36(%arg0)");
223 asm("stw %r10, 40(%arg0)");
224 asm("stw %r11, 44(%arg0)");
225 asm("stw %r12, 48(%arg0)");
226 asm("stw %r13, 52(%arg0)");
227 asm("stw %r14, 56(%arg0)");
228 asm("stw %r15, 60(%arg0)");
229 asm("stw %r16, 64(%arg0)");
230 asm("stw %r17, 68(%arg0)");
231 asm("stw %r18, 72(%arg0)");
233 /* save "callee save" space register */
234 asm volatile ("mfsp %sr3, %r1");
235 asm("stw %r1, 0(%arg0)");
237 /* indicate "true return" from saved() */
240 asm(".LABEL _comefrom_");
244 lwpRestore(jmp_buf jb)
246 /* restore stack pointer and program counter */
247 asm volatile ("ldw 4(%arg0), %sp");
248 asm volatile ("ldw 8(%arg0), %rp");
250 /* restore "callee save" space register */
251 asm volatile ("ldw 0(%arg0), %r1");
252 asm volatile ("mtsp %r1, %sr3");
254 /* restore "callee save" registers */
255 asm volatile ("ldw 12(%arg0), %r3");
256 asm volatile ("ldw 16(%arg0), %r4");
257 asm volatile ("ldw 20(%arg0), %r5");
258 asm volatile ("ldw 24(%arg0), %r6");
259 asm volatile ("ldw 28(%arg0), %r7");
260 asm volatile ("ldw 32(%arg0), %r8");
261 asm volatile ("ldw 36(%arg0), %r9");
262 asm volatile ("ldw 40(%arg0), %r10");
263 asm volatile ("ldw 44(%arg0), %r11");
264 asm volatile ("ldw 48(%arg0), %r12");
265 asm volatile ("ldw 52(%arg0), %r13");
266 asm volatile ("ldw 56(%arg0), %r14");
267 asm volatile ("ldw 60(%arg0), %r15");
268 asm volatile ("ldw 64(%arg0), %r16");
269 asm volatile ("ldw 68(%arg0), %r17");
270 asm volatile ("ldw 72(%arg0), %r18");
272 /* warp to saved() to unwind the frame correctly */
273 asm volatile ("bl _comefrom_, %r0");
274 asm volatile ("ldi 1, %ret0");
280 lwpInitContext(struct lwpProc *newp, void *sp)
282 setjmp(newp->context);
283 newp->context->_jb[2] = (int)sp;
284 newp->context->_jb[3] = (int)sp;
285 newp->context->_jb[0] = (int)lwpEntryPoint;
288 #elif defined(__linux__)
291 lwpInitContext(struct lwpProc *newp, void *sp)
293 #if defined(__GLIBC__) && (__GLIBC__ >= 2)
295 newp->context->__jmpbuf[JB_GPR1] = (int)sp;
296 newp->context->__jmpbuf[JB_LR] = (int)lwpEntryPoint;
298 newp->context->__jmpbuf[JB_SP] = (int)sp;
299 newp->context->__jmpbuf[JB_BP] = (int)sp;
300 newp->context->__jmpbuf[JB_PC] = (int)lwpEntryPoint;
303 newp->context->__sp = sp;
304 newp->context->__bp = sp;
305 newp->context->__pc = (void *)lwpEntryPoint;
312 lwpInitContext(struct lwpProc *newp, void *sp)
314 newp->context[2] = (int)sp;
315 newp->context[3] = (int)lwpEntryPoint;
321 lwpInitContext(struct lwpProc *newp, void *sp)
325 memset(newp->context, 0, sizeof(newp->context));
326 newp->context[0] = (int)sp;
327 /* preserve cpp for new context */
328 cpp = (jmp_buf *) & newp->context;
329 if (!_setjmp(LwpCurrent->context)) {
330 /* create new context */
331 /* flush registers */
334 asm("ld [%fp+0x44], %o0");
335 /* %o1 <- newp->context[0] */
336 asm("ld [%o0], %o1");
337 /* create min frame on new stack */
338 asm("save %o1,-96, %sp");
340 _longjmp(LwpCurrent->context, 1);
345 #define lwpSave(x) _setjmp(x)
346 #define lwpRestore(x) _longjmp(x, 1)
353 lwpInitContext(struct lwpProc *newp, void *sp)
357 /* register values obtained from setjmp.h */
358 _setjmp(newp->context);
359 newp->context[2] = (long)lwpEntryPoint; /* program counter */
360 newp->context[30] = (long)lwpEntryPoint; /* return address */
361 newp->context[31] = (long)lwpEntryPoint; /* fake program value (!) */
362 newp->context[34] = (long)sp; /* stack pointer */
372 lwpRestore(jmp_buf jb)
374 /* resume, but get the pv from the jmp_buf */
375 asm("ldq %pv, 248(%a0)");
376 asm("stq %a0, 16(%sp)");
377 /* generates a warning, but functions just fine */
378 asm("bsr %ra, __longjump_resume");
383 #define LWP_EXTRASTACK 12
385 /* Code is in .s files, as compiler doesn't grok asm */
386 extern int lwpSave(jmp_buf);
387 extern void lwpRestore(jmp_buf);
388 extern void lwpInitContext(struct lwpProc *);
392 #ifndef LWP_EXTRASTACK
393 #define LWP_EXTRASTACK 0
396 #define STKALIGN sizeof(double)
399 #define lwpSave(x) setjmp(x)
402 #define lwpRestore(x) longjmp(x, 1)
406 lwpNewContext(struct lwpProc *newp, int stacksz)
411 if (CANT_HAPPEN(STKALIGN == 0|| (STKALIGN & (STKALIGN - 1))))
412 return -1; /* STKALIGN not power of 2 */
414 /* Make size a multiple of sizeof(long) to keep things aligned */
415 stacksz = (stacksz + sizeof(long) - 1) & -sizeof(long);
416 /* Add a red zone on each side of the stack for LWP_STACKCHECK */
417 redsize = newp->flags & LWP_STACKCHECK ? LWP_REDZONE : 0;
418 size = stacksz + 2 * redsize + LWP_EXTRASTACK + STKALIGN - 1;
424 if (LwpStackGrowsDown) {
426 * Stack layout for stack growing downward:
428 * --------------------------------------
429 * red zone LWP_REDZONE
430 * sp -> extra LWP_EXTRASTACK
431 * ustack -> stack stacksz
432 * red zone LWP_REDZONE
433 * waste STKALIGN - 1 - x
434 * sp is aligned to a multiple of STKALIGN.
436 sp = s + redsize + stacksz;
437 sp = (char *)0 + (((sp + STKALIGN - 1) - (char *)0) & -STKALIGN);
438 newp->ustack = sp - stacksz;
441 * Stack layout for stack growing upward:
443 * --------------------------------------
445 * red zone LWP_REDZONE
446 * sp -> stack stacksz
447 * ustack -> extra LWP_EXTRASTACK
448 * red zone LWP_REDZONE
449 * waste STKALIGN - 1 - x
450 * sp is aligned to a multiple of STKALIGN.
452 sp = s + redsize + LWP_EXTRASTACK;
453 sp = (char *)0 + (((sp + STKALIGN - 1) - (char *)0) & -STKALIGN);
454 newp->ustack = sp - LWP_EXTRASTACK;
458 newp->usize = stacksz + LWP_EXTRASTACK;
459 lwpInitContext(newp, sp);
464 lwpSwitchContext(struct lwpProc *oldp, struct lwpProc *nextp)
466 if (!(oldp && lwpSave(oldp->context)))
467 lwpRestore(nextp->context);
470 #endif /* !UCONTEXT */