]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/alpha/alpha/swtch.s
- Heavyweight interrupt threads on the alpha for device I/O interrupts.
[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 #define _LOCORE
32 #include <machine/asm.h>
33 #include <machine/mutex.h>
34 #include "assym.s"
35
36 /**************************************************************************/
37
38 /*
39  * Perform actions necessary to switch to a new context.  The
40  * hwpcb should be in a0.
41  */
42 #define SWITCH_CONTEXT                                                  \
43         /* Make a note of the context we're running on. */              \
44         stq     a0, GD_CURPCB(globalp);                                 \
45                                                                         \
46         /* Swap in the new context. */                                  \
47         call_pal PAL_OSF1_swpctx
48         
49 /*
50  * savectx: save process context, i.e. callee-saved registers
51  *
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().)
56  *
57  * Arguments:
58  *      a0      'struct user *' of the process that needs its context saved
59  *
60  * Return:
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().)
64  */
65
66 LEAF(savectx, 1)
67         br      pv, Lsavectx1
68 Lsavectx1: LDGP(pv)
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 */
80
81         mov     zero, v0
82         RET
83         END(savectx)
84
85 /**************************************************************************/
86
87 IMPORT(want_resched, 4)
88 IMPORT(Lev1map, 8)
89 IMPORT(sched_lock, 72)
90
91 /*
92  * cpu_switch()
93  * Find the highest priority process and resume it.
94  */
95 LEAF(cpu_switch, 1)
96         LDGP(pv)
97         /* do an inline savectx(), to save old context */
98         ldq     a0, GD_CURPROC(globalp)
99         ldq     a1, P_ADDR(a0)
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 */
113
114         mov     a0, s0                          /* save old curproc */
115         mov     a1, s1                          /* save old U-area */
116
117 sw1:
118         br      pv, Lcs1
119 Lcs1:   LDGP(pv)
120         CALL(chooseproc)                        /* can't return NULL */
121         mov     v0, s2
122         ldq     s3, P_MD_PCBPADDR(s2)           /* save new pcbpaddr */
123
124         /*
125          * Check to see if we're switching to ourself.  If we are,
126          * don't bother loading the new context.
127          *
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.
133          */
134         cmpeq   s0, s2, t0                      /* oldproc == newproc? */
135         bne     t0, Lcs7                        /* Yes!  Skip! */
136
137         /*
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!
144          *
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.
150          */
151         beq     s0, Lcs6
152
153         mov     s0, a0                          /* pmap_deactivate(oldproc) */
154         CALL(pmap_deactivate)
155
156 Lcs6:
157         /*
158          * Activate the new process's address space and perform
159          * the actual context swap.
160          */
161
162         mov     s2, a0                          /* pmap_activate(p) */
163         CALL(pmap_activate)
164
165         mov     s3, a0                          /* swap the context */
166         SWITCH_CONTEXT
167
168 Lcs7:
169         
170         /*
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.
175          */
176         stq     s2, GD_CURPROC(globalp)         /* curproc = p */
177         stl     zero, want_resched              /* we've rescheduled */
178
179         /*
180          * Now running on the new u struct.
181          * Restore registers and return.
182          */
183         ldq     t0, P_ADDR(s2)
184
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
198
199         ldiq    v0, 1                           /* possible ret to savectx() */
200         RET
201         END(cpu_switch)
202
203
204 /*
205  * switch_trampoline()
206  *
207  * Arrange for a function to be invoked neatly, after a cpu_switch().
208  *
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.
212  */
213 LEAF(switch_trampoline, 0)
214         MTX_EXIT(sched_lock)
215         mov     s0, pv
216         mov     s1, ra
217         mov     s2, a0
218         jmp     zero, (pv)
219         END(switch_trampoline)
220
221         
222 /**************************************************************************/
223
224 /*
225  * exception_return: return from trap, exception, or syscall
226  */
227
228 IMPORT(astpending, 4)
229
230 LEAF(exception_return, 1)                       /* XXX should be NESTED */
231         br      pv, Ler1
232 Ler1:   LDGP(pv)
233
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 */
237
238         and     s1, ALPHA_PSL_USERMODE, t0      /* are we returning to user? */
239         beq     t0, Lrestoreregs                /* no: just return */
240
241         ldl     t2, GD_ASTPENDING(globalp)      /* AST pending? */
242         beq     t2, Lrestoreregs                /* no: return */
243
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 */
248         CALL(ast)
249
250 Lrestoreregs:
251         /* set the hae register if this process has specified a value */
252         ldq     t0, GD_CURPROC(globalp)
253         beq     t0, Lnohae
254         ldq     t1, P_MD_FLAGS(t0)
255         and     t1, MDP_HAEUSED
256         beq     t1, Lnohae
257         ldq     a0, P_MD_HAE(t0)
258         ldq     pv, chipset + CHIPSET_WRITE_HAE
259         CALL((pv))
260 Lnohae: 
261
262         /* restore the registers, and return */
263         bsr     ra, exception_restore_regs      /* jmp/CALL trashes pv/t12 */
264         ldq     ra,(FRAME_RA*8)(sp)
265         .set noat
266         ldq     at_reg,(FRAME_AT*8)(sp)
267
268         lda     sp,(FRAME_SW_SIZE*8)(sp)
269         call_pal PAL_OSF1_rti
270         .set at
271         END(exception_return)
272
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)
298         .set noat
299         lda     at_reg,(FRAME_SIZE*8)(sp)
300         stq     at_reg,(FRAME_SP*8)(sp)
301         .set at
302         RET
303         END(exception_save_regs)
304
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)
330         RET
331         END(exception_restore_regs)