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	srli		gr15,#28,gr5
106	subicc		gr5,#0xc,gr0,icc0
107	beq		icc0,#0,111f
108	break
109	nop
110111:
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
149restore_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
318save_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
497