1132400Sgrehan/*
2132400Sgrehan * Copyright (c) 2004 Peter Grehan.
3132400Sgrehan * All rights reserved.
4132400Sgrehan *
5132400Sgrehan * Redistribution and use in source and binary forms, with or without
6132400Sgrehan * modification, are permitted provided that the following conditions
7132400Sgrehan * are met:
8132400Sgrehan * 1. Redistributions of source code must retain the above copyright
9132400Sgrehan *    notice, this list of conditions and the following disclaimer.
10132400Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
11132400Sgrehan *    notice, this list of conditions and the following disclaimer in the
12132400Sgrehan *    documentation and/or other materials provided with the distribution.
13132400Sgrehan *
14132400Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15132400Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16132400Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17132400Sgrehan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18132400Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19132400Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20132400Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21132400Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22132400Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23132400Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24132400Sgrehan * SUCH DAMAGE.
25132400Sgrehan */
26132400Sgrehan
27132400Sgrehan#include <machine/asm.h>
28132400Sgrehan__FBSDID("$FreeBSD$");
29132400Sgrehan
30132400Sgrehan#include "assym.s"
31132400Sgrehan
32132400Sgrehan/*
33132400Sgrehan * int _ppc32_getcontext(mcontext_t *mcp)
34132400Sgrehan *
35132400Sgrehan *   Save register state from a voluntary context switch.
36132400Sgrehan * Only volatile registers, and those needed to complete
37132400Sgrehan * a setcontext call, need to be saved.
38132400Sgrehan *
39132400Sgrehan *	r1
40132400Sgrehan *	r14-31
41132400Sgrehan *	f14-31		XXX
42132400Sgrehan *	lr
43132400Sgrehan *
44132400Sgrehan *  Return 0 for this call, and set up the context so it will return
45132400Sgrehan * 1 when restored with _ppc32_setcontext().
46132400Sgrehan *
47132400Sgrehan * XXX XXX
48132400Sgrehan *  Floating-point is a big issue. Since there's no way to determine
49132400Sgrehan * if the caller has used FP, all volatile register need to be saved.
50132400Sgrehan * If FP hasn't been used, this results in a lazy FP exception in
51132400Sgrehan * the kernel and from that point on FP is always switched in/out
52132400Sgrehan * for the thread, which may be a big performance drag for the system.
53132400Sgrehan *  An alternative is to use a system call to get the context, which
54132400Sgrehan * will do the right thing for floating point, but will save all
55132400Sgrehan * registers rather than the caller-saved subset, and has the overhead
56132400Sgrehan * of a syscall.
57132400Sgrehan *  Maybe another option would be to give a light-weight way for a
58132400Sgrehan * thread to determine if FP is in used: perhaps a syscall that
59132400Sgrehan * returns in the asm traphandler, or an OSX-style read-only page
60132400Sgrehan * with a flag to indicate FP state.
61132400Sgrehan *
62132400Sgrehan * For now, punt the issue ala Alpha 1:1 model and fix in the future.
63132400Sgrehan */
64132400SgrehanENTRY(_ppc32_getcontext)
65132400Sgrehan	stw	%r1,  _MC_R1(%r3)
66132400Sgrehan	stw	%r13, _MC_R13(%r3)
67132400Sgrehan	stw	%r14, _MC_R14(%r3)
68132400Sgrehan	stw	%r15, _MC_R15(%r3)
69132400Sgrehan	stw	%r16, _MC_R16(%r3)
70132400Sgrehan	stw	%r17, _MC_R17(%r3)
71132400Sgrehan	stw	%r18, _MC_R18(%r3)
72132400Sgrehan	stw	%r19, _MC_R19(%r3)
73132400Sgrehan	stw	%r20, _MC_R20(%r3)
74132400Sgrehan	stw	%r21, _MC_R21(%r3)
75132400Sgrehan	stw	%r22, _MC_R22(%r3)
76132400Sgrehan	stw	%r23, _MC_R23(%r3)
77132400Sgrehan	stw	%r24, _MC_R24(%r3)
78132400Sgrehan	stw	%r25, _MC_R25(%r3)
79132400Sgrehan	stw	%r26, _MC_R26(%r3)
80132400Sgrehan	stw	%r27, _MC_R27(%r3)
81132400Sgrehan	stw	%r28, _MC_R28(%r3)
82132400Sgrehan	stw	%r29, _MC_R28(%r3)
83132400Sgrehan	stw	%r30, _MC_R30(%r3)
84132400Sgrehan	stw	%r31, _MC_R31(%r3)
85132400Sgrehan	mflr	%r4
86132400Sgrehan	stw	%r4,  _MC_LR(%r3)
87132400Sgrehan	mfcr	%r4
88132400Sgrehan	stw	%r4,  _MC_CR(%r3)
89132400Sgrehan
90132400Sgrehan	/* XXX f14-31 ? */
91132400Sgrehan
92132400Sgrehan	li	%r4, _MC_VERSION_KSE	/* partial ucontext version */
93132400Sgrehan	stw	%r4, _MC_VERS(%r3)
94132400Sgrehan
95132400Sgrehan	/* Return 0 */
96132400Sgrehan	li	%r3, 0
97132400Sgrehan	blr
98132400Sgrehan
99132400Sgrehan/*
100132400Sgrehan *	int _ppc32_setcontext(const mcontext_t *mcp, intptr_t val,
101132400Sgrehan *	    intptr_t *loc);
102132400Sgrehan *
103132400Sgrehan *  Should only be called for partial KSE contexts. The full context
104132400Sgrehan * case is handled by kse_switchin() in _thread_switch()
105132400Sgrehan *
106132400Sgrehan *  Returns -1 on error and 1 for return from a saved context
107132400Sgrehan */
108132400Sgrehan
109132400SgrehanENTRY(_ppc32_setcontext)
110132400Sgrehan	lwz	%r6, _MC_VERS(%r3)
111132400Sgrehan	cmpwi	%r6, _MC_VERSION_KSE	/* KSE partial context ? */
112132400Sgrehan	beq	1f
113132400Sgrehan	li	%r3, -1			/* invalid context type, return -1 */
114132400Sgrehan	blr
115132400Sgrehan
116132400Sgrehan1:	/* partial format, callee-saved regs assumed */
117132400Sgrehan	lwz	%r1,  _MC_R1(%r3)
118132400Sgrehan	lwz	%r13, _MC_R13(%r3)
119132400Sgrehan	lwz	%r14, _MC_R14(%r3)
120132400Sgrehan	lwz	%r15, _MC_R15(%r3)
121132400Sgrehan	lwz	%r16, _MC_R16(%r3)
122132400Sgrehan	lwz	%r17, _MC_R17(%r3)
123132400Sgrehan	lwz	%r18, _MC_R18(%r3)
124132400Sgrehan	lwz	%r19, _MC_R19(%r3)
125132400Sgrehan	lwz	%r20, _MC_R20(%r3)
126132400Sgrehan	lwz	%r21, _MC_R21(%r3)
127132400Sgrehan	lwz	%r22, _MC_R22(%r3)
128132400Sgrehan	lwz	%r23, _MC_R23(%r3)
129132400Sgrehan	lwz	%r24, _MC_R24(%r3)
130132400Sgrehan	lwz	%r25, _MC_R25(%r3)
131132400Sgrehan	lwz	%r26, _MC_R26(%r3)
132132400Sgrehan	lwz	%r27, _MC_R27(%r3)
133132400Sgrehan	lwz	%r28, _MC_R28(%r3)
134132400Sgrehan	lwz	%r29, _MC_R28(%r3)
135132400Sgrehan	lwz	%r30, _MC_R30(%r3)
136132400Sgrehan	lwz	%r31, _MC_R31(%r3)
137132400Sgrehan	lwz	%r6,  _MC_LR(%r3)
138132400Sgrehan	mtlr	%r6
139132400Sgrehan	lwz	%r6,  _MC_CR(%r3)
140132400Sgrehan	mtcr	%r6
141132400Sgrehan
142132400Sgrehan	/*  XXX f14-31 ? */
143132400Sgrehan
144132400Sgrehan	/* if (loc != NULL) *loc = val */
145132400Sgrehan	cmpwi	%r5, 0
146132400Sgrehan	beq	2f
147132400Sgrehan	stw	%r4, 0(%r5)
148132400Sgrehan
149132400Sgrehan	/* Return 1 */
150132400Sgrehan2:	li	%r3, 1
151132400Sgrehan	blr
152