Linux-2.6.12-rc2
[pandora-kernel.git] / arch / frv / kernel / switch_to.S
1 ###############################################################################
2 #
3 # switch_to.S: context switch operation
4 #
5 # Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
6 # Written by David Howells (dhowells@redhat.com)
7 #
8 # This program is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU General Public License
10 # as published by the Free Software Foundation; either version
11 # 2 of the License, or (at your option) any later version.
12 #
13 ###############################################################################
14 #include <linux/config.h>
15 #include <linux/linkage.h>
16 #include <asm/thread_info.h>
17 #include <asm/processor.h>
18 #include <asm/registers.h>
19 #include <asm/spr-regs.h>
20
21 .macro LEDS val
22         setlos          #~\val,gr27
23         st              gr27,@(gr30,gr0)
24         membar
25         dcf             @(gr30,gr0)
26 .endm
27
28         .section        .sdata
29         .balign         8
30
31         # address of frame 0 (userspace) on current kernel stack
32         .globl          __kernel_frame0_ptr
33 __kernel_frame0_ptr:
34         .long           init_thread_union + THREAD_SIZE - USER_CONTEXT_SIZE
35
36         # address of current task
37         .globl          __kernel_current_task
38 __kernel_current_task:
39         .long           init_task
40
41         .section        .text
42         .balign         4
43
44 ###############################################################################
45 #
46 # struct task_struct *__switch_to(struct thread_struct *prev_thread,
47 #                                 struct thread_struct *next_thread,
48 #                                 struct task_struct *prev)
49 #
50 ###############################################################################
51         .globl          __switch_to
52 __switch_to:
53         # save outgoing process's context
54         sethi.p         %hi(__switch_back),gr13
55         setlo           %lo(__switch_back),gr13
56         movsg           lr,gr12
57
58         stdi            gr28,@(gr8,#__THREAD_FRAME)
59         sti             sp  ,@(gr8,#__THREAD_SP)
60         sti             fp  ,@(gr8,#__THREAD_FP)
61         stdi            gr12,@(gr8,#__THREAD_LR)
62         stdi            gr16,@(gr8,#__THREAD_GR(16))
63         stdi            gr18,@(gr8,#__THREAD_GR(18))
64         stdi            gr20,@(gr8,#__THREAD_GR(20))
65         stdi            gr22,@(gr8,#__THREAD_GR(22))
66         stdi            gr24,@(gr8,#__THREAD_GR(24))
67         stdi.p          gr26,@(gr8,#__THREAD_GR(26))
68
69         or              gr8,gr8,gr22
70         ldi.p           @(gr8,#__THREAD_USER),gr8
71         call            save_user_regs
72         or              gr22,gr22,gr8
73         
74         # retrieve the new context
75         sethi.p         %hi(__kernel_frame0_ptr),gr6
76         setlo           %lo(__kernel_frame0_ptr),gr6
77         movsg           psr,gr4
78
79         lddi.p          @(gr9,#__THREAD_FRAME),gr10
80         or              gr10,gr10,gr27          ; save prev for the return value
81
82         ldi             @(gr11,#4),gr19         ; get new_current->thread_info
83
84         lddi            @(gr9,#__THREAD_SP),gr12
85         ldi             @(gr9,#__THREAD_LR),gr14
86         ldi             @(gr9,#__THREAD_PC),gr18
87         ldi.p           @(gr9,#__THREAD_FRAME0),gr7
88
89         # actually switch kernel contexts with ordinary exceptions disabled
90         andi            gr4,#~PSR_ET,gr5
91         movgs           gr5,psr
92
93         or.p            gr10,gr0,gr28           ; set __frame
94         or              gr11,gr0,gr29           ; set __current
95         or.p            gr12,gr0,sp
96         or              gr13,gr0,fp
97         or              gr19,gr0,gr15           ; set __current_thread_info
98
99         sti             gr7,@(gr6,#0)           ; set __kernel_frame0_ptr
100         sti             gr29,@(gr6,#4)          ; set __kernel_current_task
101
102         movgs           gr14,lr
103         bar
104
105         srli            gr15,#28,gr5
106         subicc          gr5,#0xc,gr0,icc0
107         beq             icc0,#0,111f
108         break
109         nop
110 111:
111
112         # jump to __switch_back or ret_from_fork as appropriate
113         # - move prev to GR8
114         movgs           gr4,psr
115         jmpl.p          @(gr18,gr0)
116         or              gr27,gr27,gr8
117
118 ###############################################################################
119 #
120 # restore incoming process's context
121 # - on entry:
122 #   - SP, FP, LR, GR15, GR28 and GR29 will have been set up appropriately
123 #   - GR8 will point to the outgoing task_struct
124 #   - GR9 will point to the incoming thread_struct
125 #
126 ###############################################################################
127 __switch_back:
128         lddi            @(gr9,#__THREAD_GR(16)),gr16
129         lddi            @(gr9,#__THREAD_GR(18)),gr18
130         lddi            @(gr9,#__THREAD_GR(20)),gr20
131         lddi            @(gr9,#__THREAD_GR(22)),gr22
132         lddi            @(gr9,#__THREAD_GR(24)),gr24
133         lddi            @(gr9,#__THREAD_GR(26)),gr26
134
135         # fall through into restore_user_regs()
136         ldi.p           @(gr9,#__THREAD_USER),gr8
137         or              gr8,gr8,gr9
138
139 ###############################################################################
140 #
141 # restore extra general regs and FP/Media regs
142 # - void *restore_user_regs(const struct user_context *target, void *retval)
143 # - on entry:
144 #   - GR8 will point to the user context to swap in
145 #   - GR9 will contain the value to be returned in GR8 (prev task on context switch)
146 #
147 ###############################################################################
148         .globl          restore_user_regs
149 restore_user_regs:
150         movsg           hsr0,gr6
151         ori             gr6,#HSR0_GRHE|HSR0_FRLE|HSR0_FRHE,gr6
152         movgs           gr6,hsr0
153         movsg           hsr0,gr6
154
155         movsg           psr,gr7
156         ori             gr7,#PSR_EF|PSR_EM,gr7
157         movgs           gr7,psr
158         movsg           psr,gr7
159         srli            gr7,#24,gr7
160         bar
161
162         lddi            @(gr8,#__FPMEDIA_MSR(0)),gr4
163
164         movgs           gr4,msr0
165         movgs           gr5,msr1
166
167         lddfi           @(gr8,#__FPMEDIA_ACC(0)),fr16
168         lddfi           @(gr8,#__FPMEDIA_ACC(2)),fr18
169         ldbfi           @(gr8,#__FPMEDIA_ACCG(0)),fr20
170         ldbfi           @(gr8,#__FPMEDIA_ACCG(1)),fr21
171         ldbfi           @(gr8,#__FPMEDIA_ACCG(2)),fr22
172         ldbfi           @(gr8,#__FPMEDIA_ACCG(3)),fr23
173
174         mwtacc          fr16,acc0
175         mwtacc          fr17,acc1
176         mwtacc          fr18,acc2
177         mwtacc          fr19,acc3
178         mwtaccg         fr20,accg0
179         mwtaccg         fr21,accg1
180         mwtaccg         fr22,accg2
181         mwtaccg         fr23,accg3
182
183         # some CPUs have extra ACCx and ACCGx regs and maybe FSRx regs
184         subicc.p        gr7,#0x50,gr0,icc0
185         subicc          gr7,#0x31,gr0,icc1
186         beq             icc0,#0,__restore_acc_fr451
187         beq             icc1,#0,__restore_acc_fr555
188 __restore_acc_cont:
189
190         # some CPU's have GR32-GR63
191         setlos          #HSR0_FRHE,gr4
192         andcc           gr6,gr4,gr0,icc0
193         beq             icc0,#1,__restore_skip_gr32_gr63
194
195         lddi            @(gr8,#__INT_GR(32)),gr32
196         lddi            @(gr8,#__INT_GR(34)),gr34
197         lddi            @(gr8,#__INT_GR(36)),gr36
198         lddi            @(gr8,#__INT_GR(38)),gr38
199         lddi            @(gr8,#__INT_GR(40)),gr40
200         lddi            @(gr8,#__INT_GR(42)),gr42
201         lddi            @(gr8,#__INT_GR(44)),gr44
202         lddi            @(gr8,#__INT_GR(46)),gr46
203         lddi            @(gr8,#__INT_GR(48)),gr48
204         lddi            @(gr8,#__INT_GR(50)),gr50
205         lddi            @(gr8,#__INT_GR(52)),gr52
206         lddi            @(gr8,#__INT_GR(54)),gr54
207         lddi            @(gr8,#__INT_GR(56)),gr56
208         lddi            @(gr8,#__INT_GR(58)),gr58
209         lddi            @(gr8,#__INT_GR(60)),gr60
210         lddi            @(gr8,#__INT_GR(62)),gr62
211 __restore_skip_gr32_gr63:
212
213         # all CPU's have FR0-FR31
214         lddfi           @(gr8,#__FPMEDIA_FR( 0)),fr0
215         lddfi           @(gr8,#__FPMEDIA_FR( 2)),fr2
216         lddfi           @(gr8,#__FPMEDIA_FR( 4)),fr4
217         lddfi           @(gr8,#__FPMEDIA_FR( 6)),fr6
218         lddfi           @(gr8,#__FPMEDIA_FR( 8)),fr8
219         lddfi           @(gr8,#__FPMEDIA_FR(10)),fr10
220         lddfi           @(gr8,#__FPMEDIA_FR(12)),fr12
221         lddfi           @(gr8,#__FPMEDIA_FR(14)),fr14
222         lddfi           @(gr8,#__FPMEDIA_FR(16)),fr16
223         lddfi           @(gr8,#__FPMEDIA_FR(18)),fr18
224         lddfi           @(gr8,#__FPMEDIA_FR(20)),fr20
225         lddfi           @(gr8,#__FPMEDIA_FR(22)),fr22
226         lddfi           @(gr8,#__FPMEDIA_FR(24)),fr24
227         lddfi           @(gr8,#__FPMEDIA_FR(26)),fr26
228         lddfi           @(gr8,#__FPMEDIA_FR(28)),fr28
229         lddfi.p         @(gr8,#__FPMEDIA_FR(30)),fr30
230
231         # some CPU's have FR32-FR63
232         setlos          #HSR0_FRHE,gr4
233         andcc           gr6,gr4,gr0,icc0
234         beq             icc0,#1,__restore_skip_fr32_fr63
235
236         lddfi           @(gr8,#__FPMEDIA_FR(32)),fr32
237         lddfi           @(gr8,#__FPMEDIA_FR(34)),fr34
238         lddfi           @(gr8,#__FPMEDIA_FR(36)),fr36
239         lddfi           @(gr8,#__FPMEDIA_FR(38)),fr38
240         lddfi           @(gr8,#__FPMEDIA_FR(40)),fr40
241         lddfi           @(gr8,#__FPMEDIA_FR(42)),fr42
242         lddfi           @(gr8,#__FPMEDIA_FR(44)),fr44
243         lddfi           @(gr8,#__FPMEDIA_FR(46)),fr46
244         lddfi           @(gr8,#__FPMEDIA_FR(48)),fr48
245         lddfi           @(gr8,#__FPMEDIA_FR(50)),fr50
246         lddfi           @(gr8,#__FPMEDIA_FR(52)),fr52
247         lddfi           @(gr8,#__FPMEDIA_FR(54)),fr54
248         lddfi           @(gr8,#__FPMEDIA_FR(56)),fr56
249         lddfi           @(gr8,#__FPMEDIA_FR(58)),fr58
250         lddfi           @(gr8,#__FPMEDIA_FR(60)),fr60
251         lddfi           @(gr8,#__FPMEDIA_FR(62)),fr62
252 __restore_skip_fr32_fr63:
253
254         lddi            @(gr8,#__FPMEDIA_FNER(0)),gr4
255         movsg           fner0,gr4
256         movsg           fner1,gr5
257         or.p            gr9,gr9,gr8
258         bralr
259
260         # the FR451 also has ACC8-11/ACCG8-11 regs (but not 4-7...)
261 __restore_acc_fr451:
262         lddfi           @(gr8,#__FPMEDIA_ACC(4)),fr16
263         lddfi           @(gr8,#__FPMEDIA_ACC(6)),fr18
264         ldbfi           @(gr8,#__FPMEDIA_ACCG(4)),fr20
265         ldbfi           @(gr8,#__FPMEDIA_ACCG(5)),fr21
266         ldbfi           @(gr8,#__FPMEDIA_ACCG(6)),fr22
267         ldbfi           @(gr8,#__FPMEDIA_ACCG(7)),fr23
268
269         mwtacc          fr16,acc8
270         mwtacc          fr17,acc9
271         mwtacc          fr18,acc10
272         mwtacc          fr19,acc11
273         mwtaccg         fr20,accg8
274         mwtaccg         fr21,accg9
275         mwtaccg         fr22,accg10
276         mwtaccg         fr23,accg11
277         bra             __restore_acc_cont
278
279         # the FR555 also has ACC4-7/ACCG4-7 regs and an FSR0 reg
280 __restore_acc_fr555:
281         lddfi           @(gr8,#__FPMEDIA_ACC(4)),fr16
282         lddfi           @(gr8,#__FPMEDIA_ACC(6)),fr18
283         ldbfi           @(gr8,#__FPMEDIA_ACCG(4)),fr20
284         ldbfi           @(gr8,#__FPMEDIA_ACCG(5)),fr21
285         ldbfi           @(gr8,#__FPMEDIA_ACCG(6)),fr22
286         ldbfi           @(gr8,#__FPMEDIA_ACCG(7)),fr23
287
288         mnop.p
289         mwtacc          fr16,acc4
290         mnop.p
291         mwtacc          fr17,acc5
292         mnop.p
293         mwtacc          fr18,acc6
294         mnop.p
295         mwtacc          fr19,acc7
296         mnop.p
297         mwtaccg         fr20,accg4
298         mnop.p
299         mwtaccg         fr21,accg5
300         mnop.p
301         mwtaccg         fr22,accg6
302         mnop.p
303         mwtaccg         fr23,accg7
304
305         ldi             @(gr8,#__FPMEDIA_FSR(0)),gr4
306         movgs           gr4,fsr0
307
308         bra             __restore_acc_cont
309
310
311 ###############################################################################
312 #
313 # save extra general regs and FP/Media regs
314 # - void save_user_regs(struct user_context *target)
315 #
316 ###############################################################################
317         .globl          save_user_regs
318 save_user_regs:
319         movsg           hsr0,gr6
320         ori             gr6,#HSR0_GRHE|HSR0_FRLE|HSR0_FRHE,gr6
321         movgs           gr6,hsr0
322         movsg           hsr0,gr6
323
324         movsg           psr,gr7
325         ori             gr7,#PSR_EF|PSR_EM,gr7
326         movgs           gr7,psr
327         movsg           psr,gr7
328         srli            gr7,#24,gr7
329         bar
330
331         movsg           fner0,gr4
332         movsg           fner1,gr5
333         stdi.p          gr4,@(gr8,#__FPMEDIA_FNER(0))
334
335         # some CPU's have GR32-GR63
336         setlos          #HSR0_GRHE,gr4
337         andcc           gr6,gr4,gr0,icc0
338         beq             icc0,#1,__save_skip_gr32_gr63
339
340         stdi            gr32,@(gr8,#__INT_GR(32))
341         stdi            gr34,@(gr8,#__INT_GR(34))
342         stdi            gr36,@(gr8,#__INT_GR(36))
343         stdi            gr38,@(gr8,#__INT_GR(38))
344         stdi            gr40,@(gr8,#__INT_GR(40))
345         stdi            gr42,@(gr8,#__INT_GR(42))
346         stdi            gr44,@(gr8,#__INT_GR(44))
347         stdi            gr46,@(gr8,#__INT_GR(46))
348         stdi            gr48,@(gr8,#__INT_GR(48))
349         stdi            gr50,@(gr8,#__INT_GR(50))
350         stdi            gr52,@(gr8,#__INT_GR(52))
351         stdi            gr54,@(gr8,#__INT_GR(54))
352         stdi            gr56,@(gr8,#__INT_GR(56))
353         stdi            gr58,@(gr8,#__INT_GR(58))
354         stdi            gr60,@(gr8,#__INT_GR(60))
355         stdi            gr62,@(gr8,#__INT_GR(62))
356 __save_skip_gr32_gr63:
357
358         # all CPU's have FR0-FR31
359         stdfi           fr0 ,@(gr8,#__FPMEDIA_FR( 0))
360         stdfi           fr2 ,@(gr8,#__FPMEDIA_FR( 2))
361         stdfi           fr4 ,@(gr8,#__FPMEDIA_FR( 4))
362         stdfi           fr6 ,@(gr8,#__FPMEDIA_FR( 6))
363         stdfi           fr8 ,@(gr8,#__FPMEDIA_FR( 8))
364         stdfi           fr10,@(gr8,#__FPMEDIA_FR(10))
365         stdfi           fr12,@(gr8,#__FPMEDIA_FR(12))
366         stdfi           fr14,@(gr8,#__FPMEDIA_FR(14))
367         stdfi           fr16,@(gr8,#__FPMEDIA_FR(16))
368         stdfi           fr18,@(gr8,#__FPMEDIA_FR(18))
369         stdfi           fr20,@(gr8,#__FPMEDIA_FR(20))
370         stdfi           fr22,@(gr8,#__FPMEDIA_FR(22))
371         stdfi           fr24,@(gr8,#__FPMEDIA_FR(24))
372         stdfi           fr26,@(gr8,#__FPMEDIA_FR(26))
373         stdfi           fr28,@(gr8,#__FPMEDIA_FR(28))
374         stdfi.p         fr30,@(gr8,#__FPMEDIA_FR(30))
375
376         # some CPU's have FR32-FR63
377         setlos          #HSR0_FRHE,gr4
378         andcc           gr6,gr4,gr0,icc0
379         beq             icc0,#1,__save_skip_fr32_fr63
380
381         stdfi           fr32,@(gr8,#__FPMEDIA_FR(32))
382         stdfi           fr34,@(gr8,#__FPMEDIA_FR(34))
383         stdfi           fr36,@(gr8,#__FPMEDIA_FR(36))
384         stdfi           fr38,@(gr8,#__FPMEDIA_FR(38))
385         stdfi           fr40,@(gr8,#__FPMEDIA_FR(40))
386         stdfi           fr42,@(gr8,#__FPMEDIA_FR(42))
387         stdfi           fr44,@(gr8,#__FPMEDIA_FR(44))
388         stdfi           fr46,@(gr8,#__FPMEDIA_FR(46))
389         stdfi           fr48,@(gr8,#__FPMEDIA_FR(48))
390         stdfi           fr50,@(gr8,#__FPMEDIA_FR(50))
391         stdfi           fr52,@(gr8,#__FPMEDIA_FR(52))
392         stdfi           fr54,@(gr8,#__FPMEDIA_FR(54))
393         stdfi           fr56,@(gr8,#__FPMEDIA_FR(56))
394         stdfi           fr58,@(gr8,#__FPMEDIA_FR(58))
395         stdfi           fr60,@(gr8,#__FPMEDIA_FR(60))
396         stdfi           fr62,@(gr8,#__FPMEDIA_FR(62))
397 __save_skip_fr32_fr63:
398
399         mrdacc          acc0 ,fr4
400         mrdacc          acc1 ,fr5
401
402         stdfi.p         fr4 ,@(gr8,#__FPMEDIA_ACC(0))
403
404         mrdacc          acc2 ,fr6
405         mrdacc          acc3 ,fr7
406
407         stdfi.p         fr6 ,@(gr8,#__FPMEDIA_ACC(2))
408
409         mrdaccg         accg0,fr4
410         stbfi.p         fr4 ,@(gr8,#__FPMEDIA_ACCG(0))
411
412         mrdaccg         accg1,fr5
413         stbfi.p         fr5 ,@(gr8,#__FPMEDIA_ACCG(1))
414
415         mrdaccg         accg2,fr6
416         stbfi.p         fr6 ,@(gr8,#__FPMEDIA_ACCG(2))
417
418         mrdaccg         accg3,fr7
419         stbfi           fr7 ,@(gr8,#__FPMEDIA_ACCG(3))
420
421         movsg           msr0 ,gr4
422         movsg           msr1 ,gr5
423
424         stdi            gr4 ,@(gr8,#__FPMEDIA_MSR(0))
425
426         # some CPUs have extra ACCx and ACCGx regs and maybe FSRx regs
427         subicc.p        gr7,#0x50,gr0,icc0
428         subicc          gr7,#0x31,gr0,icc1
429         beq             icc0,#0,__save_acc_fr451
430         beq             icc1,#0,__save_acc_fr555
431 __save_acc_cont:
432
433         lddfi           @(gr8,#__FPMEDIA_FR(4)),fr4
434         lddfi.p         @(gr8,#__FPMEDIA_FR(6)),fr6
435         bralr
436
437         # the FR451 also has ACC8-11/ACCG8-11 regs (but not 4-7...)
438 __save_acc_fr451:
439         mrdacc          acc8 ,fr4
440         mrdacc          acc9 ,fr5
441
442         stdfi.p         fr4 ,@(gr8,#__FPMEDIA_ACC(4))
443
444         mrdacc          acc10,fr6
445         mrdacc          acc11,fr7
446
447         stdfi.p         fr6 ,@(gr8,#__FPMEDIA_ACC(6))
448
449         mrdaccg         accg8,fr4
450         stbfi.p         fr4 ,@(gr8,#__FPMEDIA_ACCG(4))
451
452         mrdaccg         accg9,fr5
453         stbfi.p         fr5 ,@(gr8,#__FPMEDIA_ACCG(5))
454
455         mrdaccg         accg10,fr6
456         stbfi.p         fr6 ,@(gr8,#__FPMEDIA_ACCG(6))
457
458         mrdaccg         accg11,fr7
459         stbfi           fr7 ,@(gr8,#__FPMEDIA_ACCG(7))
460         bra             __save_acc_cont
461
462         # the FR555 also has ACC4-7/ACCG4-7 regs and an FSR0 reg
463 __save_acc_fr555:
464         mnop.p
465         mrdacc          acc4 ,fr4
466         mnop.p
467         mrdacc          acc5 ,fr5
468
469         stdfi           fr4 ,@(gr8,#__FPMEDIA_ACC(4))
470
471         mnop.p
472         mrdacc          acc6 ,fr6
473         mnop.p
474         mrdacc          acc7 ,fr7
475
476         stdfi           fr6 ,@(gr8,#__FPMEDIA_ACC(6))
477
478         mnop.p
479         mrdaccg         accg4,fr4
480         stbfi           fr4 ,@(gr8,#__FPMEDIA_ACCG(4))
481
482         mnop.p
483         mrdaccg         accg5,fr5
484         stbfi           fr5 ,@(gr8,#__FPMEDIA_ACCG(5))
485
486         mnop.p
487         mrdaccg         accg6,fr6
488         stbfi           fr6 ,@(gr8,#__FPMEDIA_ACCG(6))
489
490         mnop.p
491         mrdaccg         accg7,fr7
492         stbfi           fr7 ,@(gr8,#__FPMEDIA_ACCG(7))
493
494         movsg           fsr0 ,gr4
495         sti             gr4 ,@(gr8,#__FPMEDIA_FSR(0))
496         bra             __save_acc_cont