2 /* $NetBSD: locore.s,v 1.47 1998/03/22 07:26:32 thorpej Exp $ */
5 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
8 * Author: Chris G. Demetriou
10 * Permission to use, copy, modify and distribute this software and
11 * its documentation is hereby granted, provided that both the copyright
12 * notice and this permission notice appear in all copies of the
13 * software, derivative works or modified versions, and any portions
14 * thereof, and that both notices appear in supporting documentation.
16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
18 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
20 * Carnegie Mellon requests users of this software to return to
22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
23 * School of Computer Science
24 * Carnegie Mellon University
25 * Pittsburgh PA 15213-3890
27 * any improvements or extensions that they make and grant Carnegie the
28 * rights to redistribute these changes.
32 #include <machine/asm.h>
33 #include <machine/mutex.h>
36 /**************************************************************************/
39 * Perform actions necessary to switch to a new context. The
40 * hwpcb should be in a0.
42 #define SWITCH_CONTEXT \
43 /* Make a note of the context we're running on. */ \
44 stq a0, GD_CURPCB(globalp); \
46 /* Swap in the new context. */ \
47 call_pal PAL_OSF1_swpctx
50 * savectx: save process context, i.e. callee-saved registers
52 * Note that savectx() only works for processes other than curproc,
53 * since cpu_switch will copy over the info saved here. (It _can_
54 * sanely be used for curproc iff cpu_switch won't be called again, e.g.
55 * from if called from boot().)
58 * a0 'struct user *' of the process that needs its context saved
61 * v0 0. (note that for child processes, it seems
62 * like savectx() returns 1, because the return address
63 * in the PCB is set to the return address from savectx().)
69 stq sp, U_PCB_HWPCB_KSP(a0) /* store sp */
70 stq s0, U_PCB_CONTEXT+(0 * 8)(a0) /* store s0 - s6 */
71 stq s1, U_PCB_CONTEXT+(1 * 8)(a0)
72 stq s2, U_PCB_CONTEXT+(2 * 8)(a0)
73 stq s3, U_PCB_CONTEXT+(3 * 8)(a0)
74 stq s4, U_PCB_CONTEXT+(4 * 8)(a0)
75 stq s5, U_PCB_CONTEXT+(5 * 8)(a0)
76 stq s6, U_PCB_CONTEXT+(6 * 8)(a0)
77 stq ra, U_PCB_CONTEXT+(7 * 8)(a0) /* store ra */
78 call_pal PAL_OSF1_rdps /* NOTE: doesn't kill a0 */
79 stq v0, U_PCB_CONTEXT+(8 * 8)(a0) /* store ps, for ipl */
85 /**************************************************************************/
87 IMPORT(want_resched, 4)
89 IMPORT(sched_lock, 72)
93 * Find the highest priority process and resume it.
97 /* do an inline savectx(), to save old context */
98 ldq a0, GD_CURPROC(globalp)
100 ldl t0, sched_lock+MTX_RECURSE /* save sched_lock state */
101 stl t0, U_PCB_SCHEDNEST(a1)
102 /* NOTE: ksp is stored by the swpctx */
103 stq s0, U_PCB_CONTEXT+(0 * 8)(a1) /* store s0 - s6 */
104 stq s1, U_PCB_CONTEXT+(1 * 8)(a1)
105 stq s2, U_PCB_CONTEXT+(2 * 8)(a1)
106 stq s3, U_PCB_CONTEXT+(3 * 8)(a1)
107 stq s4, U_PCB_CONTEXT+(4 * 8)(a1)
108 stq s5, U_PCB_CONTEXT+(5 * 8)(a1)
109 stq s6, U_PCB_CONTEXT+(6 * 8)(a1)
110 stq ra, U_PCB_CONTEXT+(7 * 8)(a1) /* store ra */
111 call_pal PAL_OSF1_rdps /* NOTE: doesn't kill a0 */
112 stq v0, U_PCB_CONTEXT+(8 * 8)(a1) /* store ps, for ipl */
114 mov a0, s0 /* save old curproc */
115 mov a1, s1 /* save old U-area */
120 CALL(chooseproc) /* can't return NULL */
122 ldq s3, P_MD_PCBPADDR(s2) /* save new pcbpaddr */
125 * Check to see if we're switching to ourself. If we are,
126 * don't bother loading the new context.
128 * Note that even if we re-enter cpu_switch() from idle(),
129 * s0 will still contain the old curproc value because any
130 * users of that register between then and now must have
131 * saved it. Also note that switch_exit() ensures that
132 * s0 is clear before jumping here to find a new process.
134 cmpeq s0, s2, t0 /* oldproc == newproc? */
135 bne t0, Lcs7 /* Yes! Skip! */
138 * Deactivate the old address space before activating the
139 * new one. We need to do this before activating the
140 * new process's address space in the event that new
141 * process is using the same vmspace as the old. If we
142 * do this after we activate, then we might end up
143 * incorrectly marking the pmap inactive!
145 * We don't deactivate if we came here from switch_exit
146 * (old pmap no longer exists; vmspace has been freed).
147 * oldproc will be NULL in this case. We have actually
148 * taken care of calling pmap_deactivate() in cpu_exit(),
149 * before the vmspace went away.
153 mov s0, a0 /* pmap_deactivate(oldproc) */
154 CALL(pmap_deactivate)
158 * Activate the new process's address space and perform
159 * the actual context swap.
162 mov s2, a0 /* pmap_activate(p) */
165 mov s3, a0 /* swap the context */
171 * Now that the switch is done, update curproc and other
172 * globals. We must do this even if switching to ourselves
173 * because we might have re-entered cpu_switch() from idle(),
174 * in which case curproc would be NULL.
176 stq s2, GD_CURPROC(globalp) /* curproc = p */
177 stl zero, want_resched /* we've rescheduled */
180 * Now running on the new u struct.
181 * Restore registers and return.
185 /* NOTE: ksp is restored by the swpctx */
186 ldq s0, U_PCB_CONTEXT+(0 * 8)(t0) /* restore s0 - s6 */
187 ldq s1, U_PCB_CONTEXT+(1 * 8)(t0)
188 ldq s2, U_PCB_CONTEXT+(2 * 8)(t0)
189 ldq s3, U_PCB_CONTEXT+(3 * 8)(t0)
190 ldq s4, U_PCB_CONTEXT+(4 * 8)(t0)
191 ldq s5, U_PCB_CONTEXT+(5 * 8)(t0)
192 ldq s6, U_PCB_CONTEXT+(6 * 8)(t0)
193 ldq ra, U_PCB_CONTEXT+(7 * 8)(t0) /* restore ra */
194 ldl t1, U_PCB_SCHEDNEST(t0)
195 stl t1, sched_lock+MTX_RECURSE /* restore lock */
196 ldq t1, GD_CURPROC(globalp)
197 stq t1, sched_lock+MTX_LOCK
199 ldiq v0, 1 /* possible ret to savectx() */
205 * switch_trampoline()
207 * Arrange for a function to be invoked neatly, after a cpu_switch().
209 * Invokes the function specified by the s0 register with the return
210 * address specified by the s1 register and with one argument, a
211 * pointer to the executing process's proc structure.
213 LEAF(switch_trampoline, 0)
219 END(switch_trampoline)
222 /**************************************************************************/
225 * exception_return: return from trap, exception, or syscall
228 IMPORT(astpending, 4)
230 LEAF(exception_return, 1) /* XXX should be NESTED */
234 ldq s1, (FRAME_PS * 8)(sp) /* get the saved PS */
235 and s1, ALPHA_PSL_IPL_MASK, t0 /* look at the saved IPL */
236 bne t0, Lrestoreregs /* != 0: can't do AST or SIR */
238 and s1, ALPHA_PSL_USERMODE, t0 /* are we returning to user? */
239 beq t0, Lrestoreregs /* no: just return */
241 ldl t2, GD_ASTPENDING(globalp) /* AST pending? */
242 beq t2, Lrestoreregs /* no: return */
244 /* We've got an AST. Handle it. */
245 ldiq a0, ALPHA_PSL_IPL_0 /* drop IPL to zero */
246 call_pal PAL_OSF1_swpipl
247 mov sp, a0 /* only arg is frame */
251 /* set the hae register if this process has specified a value */
252 ldq t0, GD_CURPROC(globalp)
254 ldq t1, P_MD_FLAGS(t0)
258 ldq pv, chipset + CHIPSET_WRITE_HAE
262 /* restore the registers, and return */
263 bsr ra, exception_restore_regs /* jmp/CALL trashes pv/t12 */
264 ldq ra,(FRAME_RA*8)(sp)
266 ldq at_reg,(FRAME_AT*8)(sp)
268 lda sp,(FRAME_SW_SIZE*8)(sp)
269 call_pal PAL_OSF1_rti
271 END(exception_return)
273 LEAF(exception_save_regs, 0)
274 stq v0,(FRAME_V0*8)(sp)
275 stq a3,(FRAME_A3*8)(sp)
276 stq a4,(FRAME_A4*8)(sp)
277 stq a5,(FRAME_A5*8)(sp)
278 stq s0,(FRAME_S0*8)(sp)
279 stq s1,(FRAME_S1*8)(sp)
280 stq s2,(FRAME_S2*8)(sp)
281 stq s3,(FRAME_S3*8)(sp)
282 stq s4,(FRAME_S4*8)(sp)
283 stq s5,(FRAME_S5*8)(sp)
284 stq s6,(FRAME_S6*8)(sp)
285 stq t0,(FRAME_T0*8)(sp)
286 stq t1,(FRAME_T1*8)(sp)
287 stq t2,(FRAME_T2*8)(sp)
288 stq t3,(FRAME_T3*8)(sp)
289 stq t4,(FRAME_T4*8)(sp)
290 stq t5,(FRAME_T5*8)(sp)
291 stq t6,(FRAME_T6*8)(sp)
292 stq t7,(FRAME_T7*8)(sp)
293 stq t8,(FRAME_T8*8)(sp)
294 stq t9,(FRAME_T9*8)(sp)
295 stq t10,(FRAME_T10*8)(sp)
296 stq t11,(FRAME_T11*8)(sp)
297 stq t12,(FRAME_T12*8)(sp)
299 lda at_reg,(FRAME_SIZE*8)(sp)
300 stq at_reg,(FRAME_SP*8)(sp)
303 END(exception_save_regs)
305 LEAF(exception_restore_regs, 0)
306 ldq v0,(FRAME_V0*8)(sp)
307 ldq a3,(FRAME_A3*8)(sp)
308 ldq a4,(FRAME_A4*8)(sp)
309 ldq a5,(FRAME_A5*8)(sp)
310 ldq s0,(FRAME_S0*8)(sp)
311 ldq s1,(FRAME_S1*8)(sp)
312 ldq s2,(FRAME_S2*8)(sp)
313 ldq s3,(FRAME_S3*8)(sp)
314 ldq s4,(FRAME_S4*8)(sp)
315 ldq s5,(FRAME_S5*8)(sp)
316 ldq s6,(FRAME_S6*8)(sp)
317 ldq t0,(FRAME_T0*8)(sp)
318 ldq t1,(FRAME_T1*8)(sp)
319 ldq t2,(FRAME_T2*8)(sp)
320 ldq t3,(FRAME_T3*8)(sp)
321 ldq t4,(FRAME_T4*8)(sp)
322 ldq t5,(FRAME_T5*8)(sp)
323 ldq t6,(FRAME_T6*8)(sp)
324 ldq t7,(FRAME_T7*8)(sp)
325 ldq t8,(FRAME_T8*8)(sp)
326 ldq t9,(FRAME_T9*8)(sp)
327 ldq t10,(FRAME_T10*8)(sp)
328 ldq t11,(FRAME_T11*8)(sp)
329 ldq t12,(FRAME_T12*8)(sp)
331 END(exception_restore_regs)