1251392Sandrew/*	$NetBSD: _setjmp.S,v 1.12 2013/04/19 13:45:45 matt Exp $	*/
2129202Scognet
3129202Scognet/*
4129202Scognet * Copyright (c) 1997 Mark Brinicombe
5129202Scognet * All rights reserved.
6129202Scognet *
7129202Scognet * Redistribution and use in source and binary forms, with or without
8129202Scognet * modification, are permitted provided that the following conditions
9129202Scognet * are met:
10129202Scognet * 1. Redistributions of source code must retain the above copyright
11129202Scognet *    notice, this list of conditions and the following disclaimer.
12129202Scognet * 2. Redistributions in binary form must reproduce the above copyright
13129202Scognet *    notice, this list of conditions and the following disclaimer in the
14129202Scognet *    documentation and/or other materials provided with the distribution.
15129202Scognet * 3. All advertising materials mentioning features or use of this software
16129202Scognet *    must display the following acknowledgement:
17129202Scognet *	This product includes software developed by Mark Brinicombe
18129202Scognet * 4. Neither the name of the University nor the names of its contributors
19129202Scognet *    may be used to endorse or promote products derived from this software
20129202Scognet *    without specific prior written permission.
21129202Scognet *
22129202Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23129202Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24129202Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25129202Scognet * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26129202Scognet * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27129202Scognet * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28129202Scognet * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29129202Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30129202Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31129202Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32129202Scognet * SUCH DAMAGE.
33129202Scognet */
34129202Scognet
35251392Sandrew#if !defined(__SOFTFP__) && !defined(__VFP_FP__) && !defined(__ARM_PCS)
36251392Sandrew#error FPA is not supported anymore
37251392Sandrew#endif
38251392Sandrew
39251514Sandrew#if defined(__ARM_EABI__) && !defined(_STANDALONE)
40251392Sandrew	.fpu	vfp
41251392Sandrew#endif
42251392Sandrew
43129202Scognet#include <machine/asm.h>
44251392Sandrew#include <machine/setjmp.h>
45251392Sandrew
46129202Scognet__FBSDID("$FreeBSD: releng/10.2/lib/libc/arm/gen/_setjmp.S 271337 2014-09-09 22:24:01Z ian $");
47137287Scognet
48129202Scognet/*
49129202Scognet * C library -- _setjmp, _longjmp
50129202Scognet *
51129202Scognet *	_longjmp(a,v)
52129202Scognet * will generate a "return(v)" from the last call to
53129202Scognet *	_setjmp(a)
54129202Scognet * by restoring registers from the stack.
55129202Scognet * The previous signal state is NOT restored.
56129202Scognet *
57129202Scognet * Note: r0 is the return value
58251392Sandrew *       r1-r3,ip are scratch registers in functions
59129202Scognet */
60129202Scognet
61129202ScognetENTRY(_setjmp)
62129202Scognet	ldr	r1, .L_setjmp_magic
63251392Sandrew
64251514Sandrew#if defined(__ARM_EABI__) && !defined(_STANDALONE)
65251514Sandrew	ldr	r2, .Lfpu_present
66251514Sandrew#ifdef PIC
67251514Sandrew	GOT_INIT(r3, .L_setjmp_got, .L_setjmp_gotinit)
68251514Sandrew	ldr	r2, [r2, r3]
69251514Sandrew#else
70251514Sandrew	ldr	r2, [r2]
71251514Sandrew#endif
72251514Sandrew	teq	r2, #0		/* do we have a FPU? */
73251514Sandrew	beq	1f		/*   no, don't save VFP registers */
74251514Sandrew
75251514Sandrew	orr	r1, r1, #(_JB_MAGIC__SETJMP ^ _JB_MAGIC__SETJMP_VFP)
76251514Sandrew				/* change magic to VFP magic */
77251514Sandrew	add	r2, r0, #(_JB_REG_D8 * 4)
78251514Sandrew	vstmia	r2, {d8-d15}
79251514Sandrew	vmrs	r2, fpscr
80251514Sandrew	str	r2, [r0, #(_JB_REG_FPSCR * 4)]
81251514Sandrew1:
82251514Sandrew#endif /* __ARM_EABI__ */
83251514Sandrew
84251392Sandrew	str	r1, [r0]
85251392Sandrew
86251392Sandrew	add	r0, r0, #(_JB_REG_R4 * 4)
87129202Scognet	/* Store integer registers */
88129202Scognet        stmia	r0, {r4-r14}
89129202Scognet
90129202Scognet        mov	r0, #0x00000000
91137464Scognet	RET
92271337SianEND(_setjmp)
93129202Scognet
94129202Scognet.L_setjmp_magic:
95129202Scognet	.word	_JB_MAGIC__SETJMP
96251514Sandrew#if defined(__ARM_EABI__) && !defined(_STANDALONE)
97251514Sandrew	GOT_INITSYM(.L_setjmp_got, .L_setjmp_gotinit)
98251514Sandrew.Lfpu_present:
99251514Sandrew	.word	PIC_SYM(_libc_arm_fpu_present, GOTOFF)
100251514Sandrew#endif /* __ARM_EABI__ */
101129202Scognet
102137464ScognetWEAK_ALIAS(___longjmp, _longjmp)
103129202ScognetENTRY(_longjmp)
104251392Sandrew	ldr	r2, [r0]			/* get magic from jmp_buf */
105251514Sandrew	bic	r3, r2, #(_JB_MAGIC__SETJMP ^ _JB_MAGIC__SETJMP_VFP)
106251514Sandrew						/* ignore VFP-ness of magic */
107251392Sandrew	ldr	ip, .L_setjmp_magic		/* load magic */
108251514Sandrew	teq	ip, r3				/* magic correct? */
109251392Sandrew	bne	botch				/*   no, botch */
110129202Scognet
111251514Sandrew#if defined(__ARM_EABI__) && !defined(_STANDALONE)
112251514Sandrew	teq	r3, r2				/* did magic change? */
113251514Sandrew	beq	1f				/*   no, don't restore VFP */
114251514Sandrew	add	ip, r0, #(_JB_REG_D8 * 4)
115251514Sandrew	vldmia	ip, {d8-d15}
116251514Sandrew	ldr	ip, [r0, #(_JB_REG_FPSCR * 4)]
117251514Sandrew	vmsr	fpscr, ip
118251514Sandrew1:
119251514Sandrew#endif /* __ARM_EABI__ */
120251514Sandrew
121251392Sandrew	add	r0, r0, #(_JB_REG_R4 * 4)
122129202Scognet       	/* Restore integer registers */
123129202Scognet        ldmia	r0, {r4-r14}
124129202Scognet
125129202Scognet	/* Validate sp and r14 */
126129202Scognet	teq	sp, #0
127129202Scognet	teqne	r14, #0
128129202Scognet	beq	botch
129129202Scognet
130129202Scognet	/* Set return value */
131251392Sandrew	movs	r0, r1
132129202Scognet	moveq	r0, #0x00000001
133137464Scognet	RET
134129202Scognet
135129202Scognet	/* validation failed, die die die. */
136129202Scognetbotch:
137183876Sraj#if !defined(_STANDALONE)
138129202Scognet	bl	PIC_SYM(_C_LABEL(longjmperror), PLT)
139129202Scognet	bl	PIC_SYM(_C_LABEL(abort), PLT)
140129202Scognet	b	. - 8		/* Cannot get here */
141183876Sraj#else
142183876Sraj	b	.
143183876Sraj#endif
144271337SianEND(_longjmp)
145