NetBSD-5.0.2/lib/libpthread/arch/sh3/_context_u.S

Compare this file to the similar file:
Show the results in this format:

/*	$NetBSD: _context_u.S,v 1.6 2008/06/01 23:07:20 uwe Exp $ */

/*
 * 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"


/*
 * Enter debugger or die with SIGTRAP if "notreached" code is reached
 */
#define NOTREACHED	trapa #0xc3


/*
 * 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) */			  \
									  \
	stc	gbr, r0							; \
	mov.l	r0,  @((_REG_GBR * 4), r1)				; \
									  \
	/* 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(!) */	; \
	bt	1f							; \
									  \
	/* 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) */			  \
									  \
	mov.l	@((_REG_GBR * 4), r1), r0				; \
	ldc	r0, gbr							; \
									  \
	/* 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						; \
	NOTREACHED							; \
									  \
1:	/* not a _UC_USER context, pass to setcontext(2) */		  \
	CALL_SETCONTEXT(uc)						  \
	/* NOTREACHED */

#ifdef PIC

/*
 * For PIC code we need a per-call offset to the setcontext.
 * Fortunately, since setcontext(2) does not return, we can
 * put the offset right after the call.  We also don't need to
 * save/restore r12.
 */
#define CALL_SETCONTEXT(uc)						  \
	mov.l	2f, r12							; \
	mov.l	3f, r1							; \
	mova	2f, r0							; \
.ifnc "uc","r4"								; \
	mov	uc, r4							; \
.endif									; \
1:	bsrf	r1							; \
	 add	r0, r12							; \
	NOTREACHED							; \
	.align 2							; \
2:	.long	_GLOBAL_OFFSET_TABLE_					; \
3:	CALL_DATUM(_C_LABEL(setcontext), 1b)

#else /* !PIC */

/*
 * For static code all calls to setcontext can share single location
 * with the address of setcontext (see below).
 */
#define CALL_SETCONTEXT(uc)						  \
	mov.l	.L_setcontext, r1					; \
	jsr	@r1							; \
.ifnc "uc","r4"								; \
	 mov	uc, r4							; \
.else									; \
	 nop								; \
.endif									; \
	NOTREACHED

#endif



/*
 * 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 */

	.align	2
.L_uc_gregs_offset:	.long	UC_REGS
.L_uc_flags:		.long	_UC_USER | _UC_CPU
.L_uc_user:		.long	_UC_USER
#ifndef PIC
.L_setcontext:		.long	_C_LABEL(setcontext)
#endif