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
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 - FRV_FRAME0_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	# jump to __switch_back or ret_from_fork as appropriate
106	# - move prev to GR8
107	movgs		gr4,psr
108	jmpl.p		@(gr18,gr0)
109	or		gr27,gr27,gr8
110
111###############################################################################
112#
113# restore incoming process's context
114# - on entry:
115#   - SP, FP, LR, GR15, GR28 and GR29 will have been set up appropriately
116#   - GR8 will point to the outgoing task_struct
117#   - GR9 will point to the incoming thread_struct
118#
119###############################################################################
120__switch_back:
121	lddi		@(gr9,#__THREAD_GR(16)),gr16
122	lddi		@(gr9,#__THREAD_GR(18)),gr18
123	lddi		@(gr9,#__THREAD_GR(20)),gr20
124	lddi		@(gr9,#__THREAD_GR(22)),gr22
125	lddi		@(gr9,#__THREAD_GR(24)),gr24
126	lddi		@(gr9,#__THREAD_GR(26)),gr26
127
128	# fall through into restore_user_regs()
129	ldi.p		@(gr9,#__THREAD_USER),gr8
130	or		gr8,gr8,gr9
131
132###############################################################################
133#
134# restore extra general regs and FP/Media regs
135# - void *restore_user_regs(const struct user_context *target, void *retval)
136# - on entry:
137#   - GR8 will point to the user context to swap in
138#   - GR9 will contain the value to be returned in GR8 (prev task on context switch)
139#
140###############################################################################
141	.globl		restore_user_regs
142restore_user_regs:
143	movsg		hsr0,gr6
144	ori		gr6,#HSR0_GRHE|HSR0_FRLE|HSR0_FRHE,gr6
145	movgs		gr6,hsr0
146	movsg		hsr0,gr6
147
148	movsg		psr,gr7
149	ori		gr7,#PSR_EF|PSR_EM,gr7
150	movgs		gr7,psr
151	movsg		psr,gr7
152	srli		gr7,#24,gr7
153	bar
154
155	lddi		@(gr8,#__FPMEDIA_MSR(0)),gr4
156
157	movgs		gr4,msr0
158	movgs		gr5,msr1
159
160	lddfi		@(gr8,#__FPMEDIA_ACC(0)),fr16
161	lddfi		@(gr8,#__FPMEDIA_ACC(2)),fr18
162	ldbfi		@(gr8,#__FPMEDIA_ACCG(0)),fr20
163	ldbfi		@(gr8,#__FPMEDIA_ACCG(1)),fr21
164	ldbfi		@(gr8,#__FPMEDIA_ACCG(2)),fr22
165	ldbfi		@(gr8,#__FPMEDIA_ACCG(3)),fr23
166
167	mwtacc		fr16,acc0
168	mwtacc		fr17,acc1
169	mwtacc		fr18,acc2
170	mwtacc		fr19,acc3
171	mwtaccg		fr20,accg0
172	mwtaccg		fr21,accg1
173	mwtaccg		fr22,accg2
174	mwtaccg		fr23,accg3
175
176	# some CPUs have extra ACCx and ACCGx regs and maybe FSRx regs
177	subicc.p	gr7,#0x50,gr0,icc0
178	subicc		gr7,#0x31,gr0,icc1
179	beq		icc0,#0,__restore_acc_fr451
180	beq		icc1,#0,__restore_acc_fr555
181__restore_acc_cont:
182
183	# some CPU's have GR32-GR63
184	setlos		#HSR0_FRHE,gr4
185	andcc		gr6,gr4,gr0,icc0
186	beq		icc0,#1,__restore_skip_gr32_gr63
187
188	lddi		@(gr8,#__INT_GR(32)),gr32
189	lddi		@(gr8,#__INT_GR(34)),gr34
190	lddi		@(gr8,#__INT_GR(36)),gr36
191	lddi		@(gr8,#__INT_GR(38)),gr38
192	lddi		@(gr8,#__INT_GR(40)),gr40
193	lddi		@(gr8,#__INT_GR(42)),gr42
194	lddi		@(gr8,#__INT_GR(44)),gr44
195	lddi		@(gr8,#__INT_GR(46)),gr46
196	lddi		@(gr8,#__INT_GR(48)),gr48
197	lddi		@(gr8,#__INT_GR(50)),gr50
198	lddi		@(gr8,#__INT_GR(52)),gr52
199	lddi		@(gr8,#__INT_GR(54)),gr54
200	lddi		@(gr8,#__INT_GR(56)),gr56
201	lddi		@(gr8,#__INT_GR(58)),gr58
202	lddi		@(gr8,#__INT_GR(60)),gr60
203	lddi		@(gr8,#__INT_GR(62)),gr62
204__restore_skip_gr32_gr63:
205
206	# all CPU's have FR0-FR31
207	lddfi		@(gr8,#__FPMEDIA_FR( 0)),fr0
208	lddfi		@(gr8,#__FPMEDIA_FR( 2)),fr2
209	lddfi		@(gr8,#__FPMEDIA_FR( 4)),fr4
210	lddfi		@(gr8,#__FPMEDIA_FR( 6)),fr6
211	lddfi		@(gr8,#__FPMEDIA_FR( 8)),fr8
212	lddfi		@(gr8,#__FPMEDIA_FR(10)),fr10
213	lddfi		@(gr8,#__FPMEDIA_FR(12)),fr12
214	lddfi		@(gr8,#__FPMEDIA_FR(14)),fr14
215	lddfi		@(gr8,#__FPMEDIA_FR(16)),fr16
216	lddfi		@(gr8,#__FPMEDIA_FR(18)),fr18
217	lddfi		@(gr8,#__FPMEDIA_FR(20)),fr20
218	lddfi		@(gr8,#__FPMEDIA_FR(22)),fr22
219	lddfi		@(gr8,#__FPMEDIA_FR(24)),fr24
220	lddfi		@(gr8,#__FPMEDIA_FR(26)),fr26
221	lddfi		@(gr8,#__FPMEDIA_FR(28)),fr28
222	lddfi.p		@(gr8,#__FPMEDIA_FR(30)),fr30
223
224	# some CPU's have FR32-FR63
225	setlos		#HSR0_FRHE,gr4
226	andcc		gr6,gr4,gr0,icc0
227	beq		icc0,#1,__restore_skip_fr32_fr63
228
229	lddfi		@(gr8,#__FPMEDIA_FR(32)),fr32
230	lddfi		@(gr8,#__FPMEDIA_FR(34)),fr34
231	lddfi		@(gr8,#__FPMEDIA_FR(36)),fr36
232	lddfi		@(gr8,#__FPMEDIA_FR(38)),fr38
233	lddfi		@(gr8,#__FPMEDIA_FR(40)),fr40
234	lddfi		@(gr8,#__FPMEDIA_FR(42)),fr42
235	lddfi		@(gr8,#__FPMEDIA_FR(44)),fr44
236	lddfi		@(gr8,#__FPMEDIA_FR(46)),fr46
237	lddfi		@(gr8,#__FPMEDIA_FR(48)),fr48
238	lddfi		@(gr8,#__FPMEDIA_FR(50)),fr50
239	lddfi		@(gr8,#__FPMEDIA_FR(52)),fr52
240	lddfi		@(gr8,#__FPMEDIA_FR(54)),fr54
241	lddfi		@(gr8,#__FPMEDIA_FR(56)),fr56
242	lddfi		@(gr8,#__FPMEDIA_FR(58)),fr58
243	lddfi		@(gr8,#__FPMEDIA_FR(60)),fr60
244	lddfi		@(gr8,#__FPMEDIA_FR(62)),fr62
245__restore_skip_fr32_fr63:
246
247	lddi		@(gr8,#__FPMEDIA_FNER(0)),gr4
248	movsg		fner0,gr4
249	movsg		fner1,gr5
250	or.p		gr9,gr9,gr8
251	bralr
252
253	# the FR451 also has ACC8-11/ACCG8-11 regs (but not 4-7...)
254__restore_acc_fr451:
255	lddfi		@(gr8,#__FPMEDIA_ACC(4)),fr16
256	lddfi		@(gr8,#__FPMEDIA_ACC(6)),fr18
257	ldbfi		@(gr8,#__FPMEDIA_ACCG(4)),fr20
258	ldbfi		@(gr8,#__FPMEDIA_ACCG(5)),fr21
259	ldbfi		@(gr8,#__FPMEDIA_ACCG(6)),fr22
260	ldbfi		@(gr8,#__FPMEDIA_ACCG(7)),fr23
261
262	mwtacc		fr16,acc8
263	mwtacc		fr17,acc9
264	mwtacc		fr18,acc10
265	mwtacc		fr19,acc11
266	mwtaccg		fr20,accg8
267	mwtaccg		fr21,accg9
268	mwtaccg		fr22,accg10
269	mwtaccg		fr23,accg11
270	bra		__restore_acc_cont
271
272	# the FR555 also has ACC4-7/ACCG4-7 regs and an FSR0 reg
273__restore_acc_fr555:
274	lddfi		@(gr8,#__FPMEDIA_ACC(4)),fr16
275	lddfi		@(gr8,#__FPMEDIA_ACC(6)),fr18
276	ldbfi		@(gr8,#__FPMEDIA_ACCG(4)),fr20
277	ldbfi		@(gr8,#__FPMEDIA_ACCG(5)),fr21
278	ldbfi		@(gr8,#__FPMEDIA_ACCG(6)),fr22
279	ldbfi		@(gr8,#__FPMEDIA_ACCG(7)),fr23
280
281	mnop.p
282	mwtacc		fr16,acc4
283	mnop.p
284	mwtacc		fr17,acc5
285	mnop.p
286	mwtacc		fr18,acc6
287	mnop.p
288	mwtacc		fr19,acc7
289	mnop.p
290	mwtaccg		fr20,accg4
291	mnop.p
292	mwtaccg		fr21,accg5
293	mnop.p
294	mwtaccg		fr22,accg6
295	mnop.p
296	mwtaccg		fr23,accg7
297
298	ldi		@(gr8,#__FPMEDIA_FSR(0)),gr4
299	movgs		gr4,fsr0
300
301	bra		__restore_acc_cont
302
303
304###############################################################################
305#
306# save extra general regs and FP/Media regs
307# - void save_user_regs(struct user_context *target)
308#
309###############################################################################
310	.globl		save_user_regs
311save_user_regs:
312	movsg		hsr0,gr6
313	ori		gr6,#HSR0_GRHE|HSR0_FRLE|HSR0_FRHE,gr6
314	movgs		gr6,hsr0
315	movsg		hsr0,gr6
316
317	movsg		psr,gr7
318	ori		gr7,#PSR_EF|PSR_EM,gr7
319	movgs		gr7,psr
320	movsg		psr,gr7
321	srli		gr7,#24,gr7
322	bar
323
324	movsg		fner0,gr4
325	movsg		fner1,gr5
326	stdi.p		gr4,@(gr8,#__FPMEDIA_FNER(0))
327
328	# some CPU's have GR32-GR63
329	setlos		#HSR0_GRHE,gr4
330	andcc		gr6,gr4,gr0,icc0
331	beq		icc0,#1,__save_skip_gr32_gr63
332
333	stdi		gr32,@(gr8,#__INT_GR(32))
334	stdi		gr34,@(gr8,#__INT_GR(34))
335	stdi		gr36,@(gr8,#__INT_GR(36))
336	stdi		gr38,@(gr8,#__INT_GR(38))
337	stdi		gr40,@(gr8,#__INT_GR(40))
338	stdi		gr42,@(gr8,#__INT_GR(42))
339	stdi		gr44,@(gr8,#__INT_GR(44))
340	stdi		gr46,@(gr8,#__INT_GR(46))
341	stdi		gr48,@(gr8,#__INT_GR(48))
342	stdi		gr50,@(gr8,#__INT_GR(50))
343	stdi		gr52,@(gr8,#__INT_GR(52))
344	stdi		gr54,@(gr8,#__INT_GR(54))
345	stdi		gr56,@(gr8,#__INT_GR(56))
346	stdi		gr58,@(gr8,#__INT_GR(58))
347	stdi		gr60,@(gr8,#__INT_GR(60))
348	stdi		gr62,@(gr8,#__INT_GR(62))
349__save_skip_gr32_gr63:
350
351	# all CPU's have FR0-FR31
352	stdfi		fr0 ,@(gr8,#__FPMEDIA_FR( 0))
353	stdfi		fr2 ,@(gr8,#__FPMEDIA_FR( 2))
354	stdfi		fr4 ,@(gr8,#__FPMEDIA_FR( 4))
355	stdfi		fr6 ,@(gr8,#__FPMEDIA_FR( 6))
356	stdfi		fr8 ,@(gr8,#__FPMEDIA_FR( 8))
357	stdfi		fr10,@(gr8,#__FPMEDIA_FR(10))
358	stdfi		fr12,@(gr8,#__FPMEDIA_FR(12))
359	stdfi		fr14,@(gr8,#__FPMEDIA_FR(14))
360	stdfi		fr16,@(gr8,#__FPMEDIA_FR(16))
361	stdfi		fr18,@(gr8,#__FPMEDIA_FR(18))
362	stdfi		fr20,@(gr8,#__FPMEDIA_FR(20))
363	stdfi		fr22,@(gr8,#__FPMEDIA_FR(22))
364	stdfi		fr24,@(gr8,#__FPMEDIA_FR(24))
365	stdfi		fr26,@(gr8,#__FPMEDIA_FR(26))
366	stdfi		fr28,@(gr8,#__FPMEDIA_FR(28))
367	stdfi.p		fr30,@(gr8,#__FPMEDIA_FR(30))
368
369	# some CPU's have FR32-FR63
370	setlos		#HSR0_FRHE,gr4
371	andcc		gr6,gr4,gr0,icc0
372	beq		icc0,#1,__save_skip_fr32_fr63
373
374	stdfi		fr32,@(gr8,#__FPMEDIA_FR(32))
375	stdfi		fr34,@(gr8,#__FPMEDIA_FR(34))
376	stdfi		fr36,@(gr8,#__FPMEDIA_FR(36))
377	stdfi		fr38,@(gr8,#__FPMEDIA_FR(38))
378	stdfi		fr40,@(gr8,#__FPMEDIA_FR(40))
379	stdfi		fr42,@(gr8,#__FPMEDIA_FR(42))
380	stdfi		fr44,@(gr8,#__FPMEDIA_FR(44))
381	stdfi		fr46,@(gr8,#__FPMEDIA_FR(46))
382	stdfi		fr48,@(gr8,#__FPMEDIA_FR(48))
383	stdfi		fr50,@(gr8,#__FPMEDIA_FR(50))
384	stdfi		fr52,@(gr8,#__FPMEDIA_FR(52))
385	stdfi		fr54,@(gr8,#__FPMEDIA_FR(54))
386	stdfi		fr56,@(gr8,#__FPMEDIA_FR(56))
387	stdfi		fr58,@(gr8,#__FPMEDIA_FR(58))
388	stdfi		fr60,@(gr8,#__FPMEDIA_FR(60))
389	stdfi		fr62,@(gr8,#__FPMEDIA_FR(62))
390__save_skip_fr32_fr63:
391
392	mrdacc		acc0 ,fr4
393	mrdacc		acc1 ,fr5
394
395	stdfi.p		fr4 ,@(gr8,#__FPMEDIA_ACC(0))
396
397	mrdacc		acc2 ,fr6
398	mrdacc		acc3 ,fr7
399
400	stdfi.p		fr6 ,@(gr8,#__FPMEDIA_ACC(2))
401
402	mrdaccg		accg0,fr4
403	stbfi.p		fr4 ,@(gr8,#__FPMEDIA_ACCG(0))
404
405	mrdaccg		accg1,fr5
406	stbfi.p		fr5 ,@(gr8,#__FPMEDIA_ACCG(1))
407
408	mrdaccg		accg2,fr6
409	stbfi.p		fr6 ,@(gr8,#__FPMEDIA_ACCG(2))
410
411	mrdaccg		accg3,fr7
412	stbfi		fr7 ,@(gr8,#__FPMEDIA_ACCG(3))
413
414	movsg		msr0 ,gr4
415	movsg		msr1 ,gr5
416
417	stdi		gr4 ,@(gr8,#__FPMEDIA_MSR(0))
418
419	# some CPUs have extra ACCx and ACCGx regs and maybe FSRx regs
420	subicc.p	gr7,#0x50,gr0,icc0
421	subicc		gr7,#0x31,gr0,icc1
422	beq		icc0,#0,__save_acc_fr451
423	beq		icc1,#0,__save_acc_fr555
424__save_acc_cont:
425
426	lddfi		@(gr8,#__FPMEDIA_FR(4)),fr4
427	lddfi.p		@(gr8,#__FPMEDIA_FR(6)),fr6
428	bralr
429
430	# the FR451 also has ACC8-11/ACCG8-11 regs (but not 4-7...)
431__save_acc_fr451:
432	mrdacc		acc8 ,fr4
433	mrdacc		acc9 ,fr5
434
435	stdfi.p		fr4 ,@(gr8,#__FPMEDIA_ACC(4))
436
437	mrdacc		acc10,fr6
438	mrdacc		acc11,fr7
439
440	stdfi.p		fr6 ,@(gr8,#__FPMEDIA_ACC(6))
441
442	mrdaccg		accg8,fr4
443	stbfi.p		fr4 ,@(gr8,#__FPMEDIA_ACCG(4))
444
445	mrdaccg		accg9,fr5
446	stbfi.p		fr5 ,@(gr8,#__FPMEDIA_ACCG(5))
447
448	mrdaccg		accg10,fr6
449	stbfi.p		fr6 ,@(gr8,#__FPMEDIA_ACCG(6))
450
451	mrdaccg		accg11,fr7
452	stbfi		fr7 ,@(gr8,#__FPMEDIA_ACCG(7))
453	bra		__save_acc_cont
454
455	# the FR555 also has ACC4-7/ACCG4-7 regs and an FSR0 reg
456__save_acc_fr555:
457	mnop.p
458	mrdacc		acc4 ,fr4
459	mnop.p
460	mrdacc		acc5 ,fr5
461
462	stdfi		fr4 ,@(gr8,#__FPMEDIA_ACC(4))
463
464	mnop.p
465	mrdacc		acc6 ,fr6
466	mnop.p
467	mrdacc		acc7 ,fr7
468
469	stdfi		fr6 ,@(gr8,#__FPMEDIA_ACC(6))
470
471	mnop.p
472	mrdaccg		accg4,fr4
473	stbfi		fr4 ,@(gr8,#__FPMEDIA_ACCG(4))
474
475	mnop.p
476	mrdaccg		accg5,fr5
477	stbfi		fr5 ,@(gr8,#__FPMEDIA_ACCG(5))
478
479	mnop.p
480	mrdaccg		accg6,fr6
481	stbfi		fr6 ,@(gr8,#__FPMEDIA_ACCG(6))
482
483	mnop.p
484	mrdaccg		accg7,fr7
485	stbfi		fr7 ,@(gr8,#__FPMEDIA_ACCG(7))
486
487	movsg		fsr0 ,gr4
488	sti		gr4 ,@(gr8,#__FPMEDIA_FSR(0))
489	bra		__save_acc_cont
490