2006-01-04 20:44:53 +03:00
|
|
|
/* $NetBSD: _context_u.S,v 1.5 2006/01/04 17:44:53 uwe Exp $ */
|
2003-06-23 23:34:43 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2003 Christian P. Groessler
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
|
|
* derived from this software without specific prior written permission
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <machine/asm.h>
|
|
|
|
#include "assym.h"
|
|
|
|
|
|
|
|
|
2003-11-18 01:38:11 +03:00
|
|
|
/*
|
|
|
|
* Enter debugger or die with SIGTRAP if "notreached" code is reached
|
|
|
|
*/
|
|
|
|
#define NOTREACHED trapa #0xc3
|
|
|
|
|
|
|
|
|
2003-06-23 23:34:43 +04:00
|
|
|
/*
|
|
|
|
* Only save/restore registers that are callee saved, i.e for which
|
|
|
|
* gcc has call_used_regs[reg] == 0.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define GETC(uc) \
|
|
|
|
mov.l .L_uc_gregs_offset, r1 ; \
|
|
|
|
sts pr, r0 ; \
|
|
|
|
add uc, r1 /* uc->uc_mcontext.__gregs */ ; \
|
|
|
|
mov.l r0, @((_REG_PC * 4), r1) ; \
|
|
|
|
mov.l r0, @((_REG_PR * 4), r1) ; \
|
|
|
|
\
|
|
|
|
mov.l r8, @((_REG_R8 * 4), r1) ; \
|
|
|
|
mov.l r9, @((_REG_R9 * 4), r1) ; \
|
|
|
|
mov.l r10, @((_REG_R10 * 4), r1) ; \
|
|
|
|
mov.l r11, @((_REG_R11 * 4), r1) ; \
|
|
|
|
mov.l r12, @((_REG_R12 * 4), r1) ; \
|
|
|
|
mov.l r13, @((_REG_R13 * 4), r1) ; \
|
|
|
|
mov.l r14, @((_REG_R14 * 4), r1) ; \
|
|
|
|
/* _REG_R15 is too far to use @(disp, Rn) */ \
|
|
|
|
\
|
|
|
|
/* in Hitachi calling convention mac regs are callee saved */ \
|
|
|
|
sts mach, r0 ; \
|
|
|
|
mov.l r0, @((_REG_MACH * 4), r1) ; \
|
|
|
|
sts macl, r0 ; \
|
|
|
|
mov.l r0, @((_REG_MACL * 4), r1) ; \
|
|
|
|
\
|
|
|
|
mov.l .L_uc_flags, r0 ; \
|
|
|
|
\
|
|
|
|
add #(_REG_R15 * 4), r1 ; \
|
|
|
|
mov.l r15, @r1 ; \
|
|
|
|
\
|
|
|
|
/* XXX: FP registers fr12..fr15? */ \
|
|
|
|
\
|
|
|
|
mov.l r0, @(UC_FLAGS, uc)
|
|
|
|
|
|
|
|
|
|
|
|
#define SETC(uc) \
|
|
|
|
mov.l @(UC_FLAGS, uc), r1 ; \
|
|
|
|
mov.l .L_uc_user, r0 ; \
|
|
|
|
tst r0, r1 /* ands and sets T if zero(!) */ ; \
|
2003-07-06 02:50:09 +04:00
|
|
|
bt 1f ; \
|
2003-06-23 23:34:43 +04:00
|
|
|
\
|
|
|
|
/* a _UC_USER context */ \
|
|
|
|
mov.l .L_uc_gregs_offset, r1 ; \
|
|
|
|
add uc, r1 /* uc->uc_mcontext.__gregs */ ; \
|
|
|
|
\
|
|
|
|
mov.l @((_REG_R8 * 4), r1), r8 ; \
|
|
|
|
mov.l @((_REG_R9 * 4), r1), r9 ; \
|
|
|
|
mov.l @((_REG_R10 * 4), r1), r10 ; \
|
|
|
|
mov.l @((_REG_R11 * 4), r1), r11 ; \
|
|
|
|
mov.l @((_REG_R12 * 4), r1), r12 ; \
|
|
|
|
mov.l @((_REG_R13 * 4), r1), r13 ; \
|
|
|
|
mov.l @((_REG_R14 * 4), r1), r14 ; \
|
|
|
|
/* _REG_R15 is too far to use @(disp, Rn) */ \
|
|
|
|
\
|
|
|
|
/* in Hitachi calling convention mac regs are callee saved */ \
|
|
|
|
mov.l @((_REG_MACH * 4), r1), r0 ; \
|
|
|
|
mov.l @((_REG_MACL * 4), r1), r2 ; \
|
|
|
|
lds r0, mach ; \
|
|
|
|
lds r2, macl ; \
|
|
|
|
\
|
|
|
|
/* XXX: FP registers fr12..fr15? */ \
|
|
|
|
\
|
|
|
|
mov.l @((_REG_PR * 4), r1), r0 ; \
|
|
|
|
mov.l @((_REG_PC * 4), r1), r2 ; \
|
|
|
|
lds r0, pr ; \
|
|
|
|
add #(_REG_R15 * 4), r1 ; \
|
|
|
|
jmp @r2 ; \
|
|
|
|
mov.l @r1, r15 ; \
|
2003-11-18 01:38:11 +03:00
|
|
|
NOTREACHED ; \
|
2003-06-23 23:34:43 +04:00
|
|
|
\
|
|
|
|
1: /* not a _UC_USER context, pass to setcontext(2) */ \
|
2003-07-06 02:50:09 +04:00
|
|
|
CALL_SETCONTEXT(uc) \
|
|
|
|
/* NOTREACHED */
|
|
|
|
|
|
|
|
#ifdef PIC
|
2006-01-04 20:44:53 +03:00
|
|
|
|
2003-07-06 02:50:09 +04:00
|
|
|
/*
|
|
|
|
* For PIC code we need a per-call offset to the setcontext.
|
|
|
|
* Fortunately, since setcontext(2) does not return, we can
|
2006-01-04 20:44:53 +03:00
|
|
|
* put the offset right after the call. We also don't need to
|
|
|
|
* save/restore r12.
|
2003-07-06 02:50:09 +04:00
|
|
|
*/
|
|
|
|
#define CALL_SETCONTEXT(uc) \
|
2006-01-04 20:44:53 +03:00
|
|
|
mov.l 2f, r12 ; \
|
|
|
|
mov.l 3f, r1 ; \
|
|
|
|
mova 2f, r0 ; \
|
|
|
|
.ifnc "uc","r4" ; \
|
|
|
|
mov uc, r4 ; \
|
|
|
|
.endif ; \
|
2003-07-06 02:50:09 +04:00
|
|
|
1: bsrf r1 ; \
|
2006-01-04 20:44:53 +03:00
|
|
|
add r0, r12 ; \
|
2003-11-18 01:38:11 +03:00
|
|
|
NOTREACHED ; \
|
2003-07-06 02:50:09 +04:00
|
|
|
.align 2 ; \
|
2006-01-04 20:44:53 +03:00
|
|
|
2: .long _GLOBAL_OFFSET_TABLE_ ; \
|
|
|
|
3: CALL_DATUM(_C_LABEL(setcontext), 1b)
|
|
|
|
|
2003-07-06 02:50:09 +04:00
|
|
|
#else /* !PIC */
|
2006-01-04 20:44:53 +03:00
|
|
|
|
2003-07-06 02:50:09 +04:00
|
|
|
/*
|
2006-01-04 20:44:53 +03:00
|
|
|
* For static code all calls to setcontext can share single location
|
2003-07-06 02:50:09 +04:00
|
|
|
* with the address of setcontext (see below).
|
|
|
|
*/
|
|
|
|
#define CALL_SETCONTEXT(uc) \
|
2003-06-23 23:34:43 +04:00
|
|
|
mov.l .L_setcontext, r1 ; \
|
|
|
|
jsr @r1 ; \
|
2006-01-04 20:44:53 +03:00
|
|
|
.ifnc "uc","r4" ; \
|
|
|
|
mov uc, r4 ; \
|
|
|
|
.else ; \
|
|
|
|
nop ; \
|
|
|
|
.endif ; \
|
2003-11-18 01:38:11 +03:00
|
|
|
NOTREACHED
|
2003-07-06 02:50:09 +04:00
|
|
|
|
2006-01-04 20:44:53 +03:00
|
|
|
#endif
|
2003-07-06 02:50:09 +04:00
|
|
|
|
2003-06-23 23:34:43 +04:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* int _getcontext_u(ucontext_t *ctx)
|
|
|
|
* Store the current context in the provided ctx structure.
|
|
|
|
*/
|
|
|
|
NENTRY(_getcontext_u)
|
|
|
|
GETC(r4) /* r4 - ctx */
|
|
|
|
rts
|
|
|
|
mov #0, r0
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* int _swapcontext_u(ucontext_t *from, const ucontext_t *to)
|
|
|
|
* Save the current context in `from' before switching to the
|
|
|
|
* new context in `to'.
|
|
|
|
*/
|
|
|
|
NENTRY(_swapcontext_u)
|
|
|
|
GETC(r4) /* r4 - from */
|
|
|
|
mov r5, r4 /* r5 - to */
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* int _setcontext_u(const ucontext_t *ctx)
|
|
|
|
* Make the context stored in ctx current.
|
|
|
|
*/
|
|
|
|
NENTRY(_setcontext_u)
|
|
|
|
SETC(r4) /* r4 - ctx */
|
|
|
|
/* NOTREACHED */
|
|
|
|
|
2003-07-06 02:50:09 +04:00
|
|
|
.align 2
|
2003-06-23 23:34:43 +04:00
|
|
|
.L_uc_gregs_offset: .long UC_REGS
|
|
|
|
.L_uc_flags: .long _UC_USER | _UC_CPU
|
|
|
|
.L_uc_user: .long _UC_USER
|
2003-07-06 02:50:09 +04:00
|
|
|
#ifndef PIC
|
2003-06-23 23:34:43 +04:00
|
|
|
.L_setcontext: .long _C_LABEL(setcontext)
|
2003-07-06 02:50:09 +04:00
|
|
|
#endif
|