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.
31 #include <machine/asm.h>
34 /**************************************************************************/
37 * Perform actions necessary to switch to a new context. The
38 * hwpcb should be in a0.
40 #define SWITCH_CONTEXT \
41 /* Make a note of the context we're running on. */ \
44 /* Swap in the new context. */ \
45 call_pal PAL_OSF1_swpctx
48 * savectx: save process context, i.e. callee-saved registers
50 * Note that savectx() only works for processes other than curproc,
51 * since cpu_switch will copy over the info saved here. (It _can_
52 * sanely be used for curproc iff cpu_switch won't be called again, e.g.
53 * from if called from boot().)
56 * a0 'struct user *' of the process that needs its context saved
59 * v0 0. (note that for child processes, it seems
60 * like savectx() returns 1, because the return address
61 * in the PCB is set to the return address from savectx().)
67 stq sp, U_PCB_HWPCB_KSP(a0) /* store sp */
68 stq s0, U_PCB_CONTEXT+(0 * 8)(a0) /* store s0 - s6 */
69 stq s1, U_PCB_CONTEXT+(1 * 8)(a0)
70 stq s2, U_PCB_CONTEXT+(2 * 8)(a0)
71 stq s3, U_PCB_CONTEXT+(3 * 8)(a0)
72 stq s4, U_PCB_CONTEXT+(4 * 8)(a0)
73 stq s5, U_PCB_CONTEXT+(5 * 8)(a0)
74 stq s6, U_PCB_CONTEXT+(6 * 8)(a0)
75 stq ra, U_PCB_CONTEXT+(7 * 8)(a0) /* store ra */
76 call_pal PAL_OSF1_rdps /* NOTE: doesn't kill a0 */
77 stq v0, U_PCB_CONTEXT+(8 * 8)(a0) /* store ps, for ipl */
83 /**************************************************************************/
85 IMPORT(want_resched, 4)
89 * When no processes are on the runq, cpu_switch branches to idle
90 * to wait for something to come ready.
91 * Note: this is really a part of cpu_switch() but defined here for kernel
97 stq zero, switchtime /* zero switchtime.tv_sec */
98 stq zero, curproc /* curproc <- NULL for stats */
99 mov zero, a0 /* enable all interrupts */
100 call_pal PAL_OSF1_swpipl
104 ldiq a0, ALPHA_PSL_IPL_HIGH /* disable all interrupts */
105 call_pal PAL_OSF1_swpipl
106 jmp zero, sw1 /* jump back into the fray */
111 * Find the highest priority process and resume it.
115 /* do an inline savectx(), to save old context */
117 /* NOTE: ksp is stored by the swpctx */
118 stq s0, U_PCB_CONTEXT+(0 * 8)(a1) /* store s0 - s6 */
119 stq s1, U_PCB_CONTEXT+(1 * 8)(a1)
120 stq s2, U_PCB_CONTEXT+(2 * 8)(a1)
121 stq s3, U_PCB_CONTEXT+(3 * 8)(a1)
122 stq s4, U_PCB_CONTEXT+(4 * 8)(a1)
123 stq s5, U_PCB_CONTEXT+(5 * 8)(a1)
124 stq s6, U_PCB_CONTEXT+(6 * 8)(a1)
125 stq ra, U_PCB_CONTEXT+(7 * 8)(a1) /* store ra */
126 call_pal PAL_OSF1_rdps /* NOTE: doesn't kill a0 */
127 stq v0, U_PCB_CONTEXT+(8 * 8)(a1) /* store ps, for ipl */
129 mov a0, s0 /* save old curproc */
130 mov a1, s1 /* save old U-area */
132 CALL(procrunnable) /* anything to run? */
133 beq v0, idle /* and if none, go idle */
135 ldiq a0, ALPHA_PSL_IPL_HIGH /* disable all interrupts */
136 call_pal PAL_OSF1_swpipl
143 ldq s3, P_MD_PCBPADDR(s2) /* save new pcbpaddr */
146 * Check to see if we're switching to ourself. If we are,
147 * don't bother loading the new context.
149 * Note that even if we re-enter cpu_switch() from idle(),
150 * s0 will still contain the old curproc value because any
151 * users of that register between then and now must have
152 * saved it. Also note that switch_exit() ensures that
153 * s0 is clear before jumping here to find a new process.
155 cmpeq s0, s2, t0 /* oldproc == newproc? */
156 bne t0, Lcs7 /* Yes! Skip! */
159 * Deactivate the old address space before activating the
160 * new one. We need to do this before activating the
161 * new process's address space in the event that new
162 * process is using the same vmspace as the old. If we
163 * do this after we activate, then we might end up
164 * incorrectly marking the pmap inactive!
166 * We don't deactivate if we came here from switch_exit
167 * (old pmap no longer exists; vmspace has been freed).
168 * oldproc will be NULL in this case. We have actually
169 * taken care of calling pmap_deactivate() in cpu_exit(),
170 * before the vmspace went away.
174 mov s0, a0 /* pmap_deactivate(oldproc) */
175 CALL(pmap_deactivate)
179 * Activate the new process's address space and perform
180 * the actual context swap.
183 mov s2, a0 /* pmap_activate(p) */
186 mov s3, a0 /* swap the context */
192 * Now that the switch is done, update curproc and other
193 * globals. We must do this even if switching to ourselves
194 * because we might have re-entered cpu_switch() from idle(),
195 * in which case curproc would be NULL.
197 stq s2, curproc /* curproc = p */
198 stl zero, want_resched /* we've rescheduled */
201 * Now running on the new u struct.
202 * Restore registers and return.
206 /* NOTE: ksp is restored by the swpctx */
207 ldq s0, U_PCB_CONTEXT+(0 * 8)(t0) /* restore s0 - s6 */
208 ldq s1, U_PCB_CONTEXT+(1 * 8)(t0)
209 ldq s2, U_PCB_CONTEXT+(2 * 8)(t0)
210 ldq s3, U_PCB_CONTEXT+(3 * 8)(t0)
211 ldq s4, U_PCB_CONTEXT+(4 * 8)(t0)
212 ldq s5, U_PCB_CONTEXT+(5 * 8)(t0)
213 ldq s6, U_PCB_CONTEXT+(6 * 8)(t0)
214 ldq ra, U_PCB_CONTEXT+(7 * 8)(t0) /* restore ra */
215 ldq a0, U_PCB_CONTEXT+(8 * 8)(t0) /* restore ipl */
216 and a0, ALPHA_PSL_IPL_MASK, a0
217 call_pal PAL_OSF1_swpipl
219 ldiq v0, 1 /* possible ret to savectx() */
225 * switch_trampoline()
227 * Arrange for a function to be invoked neatly, after a cpu_switch().
229 * Invokes the function specified by the s0 register with the return
230 * address specified by the s1 register and with one argument, a
231 * pointer to the executing process's proc structure.
233 LEAF(switch_trampoline, 0)
238 END(switch_trampoline)
241 /**************************************************************************/
244 * exception_return: return from trap, exception, or syscall
248 IMPORT(astpending, 4)
250 LEAF(exception_return, 1) /* XXX should be NESTED */
254 ldq s1, (FRAME_PS * 8)(sp) /* get the saved PS */
255 and s1, ALPHA_PSL_IPL_MASK, t0 /* look at the saved IPL */
256 bne t0, Lrestoreregs /* != 0: can't do AST or SIR */
258 /* see if we can do an SIR */
259 ldl t1, ipending /* SIR pending? */
260 beq t1, Lchkast /* no, try an AST*/
262 /* We've got a SIR. */
263 CALL(do_sir) /* do the SIR; lowers IPL */
266 and s1, ALPHA_PSL_USERMODE, t0 /* are we returning to user? */
267 beq t0, Lrestoreregs /* no: just return */
269 ldl t2, astpending /* AST pending? */
270 beq t2, Lrestoreregs /* no: return */
272 /* We've got an AST. Handle it. */
273 ldiq a0, ALPHA_PSL_IPL_0 /* drop IPL to zero */
274 call_pal PAL_OSF1_swpipl
275 mov sp, a0 /* only arg is frame */
279 /* set the hae register if this process has specified a value */
282 ldq t1, P_MD_FLAGS(t0)
286 ldq pv, chipset + CHIPSET_WRITE_HAE
290 /* restore the registers, and return */
291 bsr ra, exception_restore_regs /* jmp/CALL trashes pv/t12 */
292 ldq ra,(FRAME_RA*8)(sp)
294 ldq at_reg,(FRAME_AT*8)(sp)
296 lda sp,(FRAME_SW_SIZE*8)(sp)
297 call_pal PAL_OSF1_rti
299 END(exception_return)
301 LEAF(exception_save_regs, 0)
302 stq v0,(FRAME_V0*8)(sp)
303 stq a3,(FRAME_A3*8)(sp)
304 stq a4,(FRAME_A4*8)(sp)
305 stq a5,(FRAME_A5*8)(sp)
306 stq s0,(FRAME_S0*8)(sp)
307 stq s1,(FRAME_S1*8)(sp)
308 stq s2,(FRAME_S2*8)(sp)
309 stq s3,(FRAME_S3*8)(sp)
310 stq s4,(FRAME_S4*8)(sp)
311 stq s5,(FRAME_S5*8)(sp)
312 stq s6,(FRAME_S6*8)(sp)
313 stq t0,(FRAME_T0*8)(sp)
314 stq t1,(FRAME_T1*8)(sp)
315 stq t2,(FRAME_T2*8)(sp)
316 stq t3,(FRAME_T3*8)(sp)
317 stq t4,(FRAME_T4*8)(sp)
318 stq t5,(FRAME_T5*8)(sp)
319 stq t6,(FRAME_T6*8)(sp)
320 stq t7,(FRAME_T7*8)(sp)
321 stq t8,(FRAME_T8*8)(sp)
322 stq t9,(FRAME_T9*8)(sp)
323 stq t10,(FRAME_T10*8)(sp)
324 stq t11,(FRAME_T11*8)(sp)
325 stq t12,(FRAME_T12*8)(sp)
327 lda at_reg,(FRAME_SIZE*8)(sp)
328 stq at_reg,(FRAME_SP*8)(sp)
331 END(exception_save_regs)
333 LEAF(exception_restore_regs, 0)
334 ldq v0,(FRAME_V0*8)(sp)
335 ldq a3,(FRAME_A3*8)(sp)
336 ldq a4,(FRAME_A4*8)(sp)
337 ldq a5,(FRAME_A5*8)(sp)
338 ldq s0,(FRAME_S0*8)(sp)
339 ldq s1,(FRAME_S1*8)(sp)
340 ldq s2,(FRAME_S2*8)(sp)
341 ldq s3,(FRAME_S3*8)(sp)
342 ldq s4,(FRAME_S4*8)(sp)
343 ldq s5,(FRAME_S5*8)(sp)
344 ldq s6,(FRAME_S6*8)(sp)
345 ldq t0,(FRAME_T0*8)(sp)
346 ldq t1,(FRAME_T1*8)(sp)
347 ldq t2,(FRAME_T2*8)(sp)
348 ldq t3,(FRAME_T3*8)(sp)
349 ldq t4,(FRAME_T4*8)(sp)
350 ldq t5,(FRAME_T5*8)(sp)
351 ldq t6,(FRAME_T6*8)(sp)
352 ldq t7,(FRAME_T7*8)(sp)
353 ldq t8,(FRAME_T8*8)(sp)
354 ldq t9,(FRAME_T9*8)(sp)
355 ldq t10,(FRAME_T10*8)(sp)
356 ldq t11,(FRAME_T11*8)(sp)
357 ldq t12,(FRAME_T12*8)(sp)
359 END(exception_restore_regs)