]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/alpha/alpha/swtch.s
This commit was generated by cvs2svn to compensate for changes in r57419,
[FreeBSD/FreeBSD.git] / sys / alpha / alpha / swtch.s
1 /* $FreeBSD$ */
2 /* $NetBSD: locore.s,v 1.47 1998/03/22 07:26:32 thorpej Exp $ */
3
4 /*
5  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
6  * All rights reserved.
7  *
8  * Author: Chris G. Demetriou
9  *
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.
15  *
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.
19  *
20  * Carnegie Mellon requests users of this software to return to
21  *
22  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
23  *  School of Computer Science
24  *  Carnegie Mellon University
25  *  Pittsburgh PA 15213-3890
26  *
27  * any improvements or extensions that they make and grant Carnegie the
28  * rights to redistribute these changes.
29  */
30
31 #include <machine/asm.h>
32 #include "assym.s"
33
34 /**************************************************************************/
35
36 /*
37  * Perform actions necessary to switch to a new context.  The
38  * hwpcb should be in a0.
39  */
40 #define SWITCH_CONTEXT                                                  \
41         /* Make a note of the context we're running on. */              \
42         stq     a0, curpcb;                                             \
43                                                                         \
44         /* Swap in the new context. */                                  \
45         call_pal PAL_OSF1_swpctx
46         
47 /*
48  * savectx: save process context, i.e. callee-saved registers
49  *
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().)
54  *
55  * Arguments:
56  *      a0      'struct user *' of the process that needs its context saved
57  *
58  * Return:
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().)
62  */
63
64 LEAF(savectx, 1)
65         br      pv, Lsavectx1
66 Lsavectx1: LDGP(pv)
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 */
78
79         mov     zero, v0
80         RET
81         END(savectx)
82
83 /**************************************************************************/
84
85 IMPORT(want_resched, 4)
86 IMPORT(Lev1map, 8)
87
88 /*
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
92  * profiling.
93  */
94 LEAF(idle, 0)
95         br      pv, Lidle1
96 Lidle1: LDGP(pv)
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
101 Lidle2:
102         CALL(procrunnable)
103         beq     v0, Lidle2
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 */
107         END(idle)
108
109 /*
110  * cpu_switch()
111  * Find the highest priority process and resume it.
112  */
113 LEAF(cpu_switch, 1)
114         LDGP(pv)
115         /* do an inline savectx(), to save old context */
116         ldq     a1, P_ADDR(a0)
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 */
128
129         mov     a0, s0                          /* save old curproc */
130         mov     a1, s1                          /* save old U-area */
131
132         CALL(procrunnable)                      /* anything to run? */
133         beq     v0, idle                        /* and if none, go idle */
134
135         ldiq    a0, ALPHA_PSL_IPL_HIGH          /* disable all interrupts */
136         call_pal PAL_OSF1_swpipl
137 sw1:
138         br      pv, Lcs1
139 Lcs1:   LDGP(pv)
140         CALL(chooseproc)
141         beq     v0, idle
142         mov     v0, s2
143         ldq     s3, P_MD_PCBPADDR(s2)           /* save new pcbpaddr */
144
145         /*
146          * Check to see if we're switching to ourself.  If we are,
147          * don't bother loading the new context.
148          *
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.
154          */
155         cmpeq   s0, s2, t0                      /* oldproc == newproc? */
156         bne     t0, Lcs7                        /* Yes!  Skip! */
157
158         /*
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!
165          *
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.
171          */
172         beq     s0, Lcs6
173
174         mov     s0, a0                          /* pmap_deactivate(oldproc) */
175         CALL(pmap_deactivate)
176
177 Lcs6:
178         /*
179          * Activate the new process's address space and perform
180          * the actual context swap.
181          */
182
183         mov     s2, a0                          /* pmap_activate(p) */
184         CALL(pmap_activate)
185
186         mov     s3, a0                          /* swap the context */
187         SWITCH_CONTEXT
188
189 Lcs7:
190         
191         /*
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.
196          */
197         stq     s2, curproc                     /* curproc = p */
198         stl     zero, want_resched              /* we've rescheduled */
199
200         /*
201          * Now running on the new u struct.
202          * Restore registers and return.
203          */
204         ldq     t0, P_ADDR(s2)
205
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
218
219         ldiq    v0, 1                           /* possible ret to savectx() */
220         RET
221         END(cpu_switch)
222
223
224 /*
225  * switch_trampoline()
226  *
227  * Arrange for a function to be invoked neatly, after a cpu_switch().
228  *
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.
232  */
233 LEAF(switch_trampoline, 0)
234         mov     s0, pv
235         mov     s1, ra
236         mov     s2, a0
237         jmp     zero, (pv)
238         END(switch_trampoline)
239
240         
241 /**************************************************************************/
242
243 /*
244  * exception_return: return from trap, exception, or syscall
245  */
246
247 IMPORT(ipending, 4)
248 IMPORT(astpending, 4)
249
250 LEAF(exception_return, 1)                       /* XXX should be NESTED */
251         br      pv, Ler1
252 Ler1:   LDGP(pv)
253
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 */
257
258         /* see if we can do an SIR */
259         ldl     t1, ipending                    /* SIR pending? */
260         beq     t1, Lchkast                     /* no, try an AST*/
261
262         /* We've got a SIR. */
263         CALL(do_sir)                            /* do the SIR; lowers IPL */
264
265 Lchkast:
266         and     s1, ALPHA_PSL_USERMODE, t0      /* are we returning to user? */
267         beq     t0, Lrestoreregs                /* no: just return */
268
269         ldl     t2, astpending                  /* AST pending? */
270         beq     t2, Lrestoreregs                /* no: return */
271
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 */
276         CALL(ast)
277
278 Lrestoreregs:
279         /* set the hae register if this process has specified a value */
280         ldq     t0, curproc
281         beq     t0, Lnohae
282         ldq     t1, P_MD_FLAGS(t0)
283         and     t1, MDP_HAEUSED
284         beq     t1, Lnohae
285         ldq     a0, P_MD_HAE(t0)
286         ldq     pv, chipset + CHIPSET_WRITE_HAE
287         CALL((pv))
288 Lnohae: 
289
290         /* restore the registers, and return */
291         bsr     ra, exception_restore_regs      /* jmp/CALL trashes pv/t12 */
292         ldq     ra,(FRAME_RA*8)(sp)
293         .set noat
294         ldq     at_reg,(FRAME_AT*8)(sp)
295
296         lda     sp,(FRAME_SW_SIZE*8)(sp)
297         call_pal PAL_OSF1_rti
298         .set at
299         END(exception_return)
300
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)
326         .set noat
327         lda     at_reg,(FRAME_SIZE*8)(sp)
328         stq     at_reg,(FRAME_SP*8)(sp)
329         .set at
330         RET
331         END(exception_save_regs)
332
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)
358         RET
359         END(exception_restore_regs)