aboutsummaryrefslogblamecommitdiffstats
path: root/arch/frv/kernel/switch_to.S
blob: 9e5a583991a3ace7e1dcf74ada8ece2f1ef1264f (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495












                                                                               

































































































































































































































































































































































































































































































                                                                                    
###############################################################################
#
# switch_to.S: context switch operation
#
# Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
# Written by David Howells (dhowells@redhat.com)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version
# 2 of the License, or (at your option) any later version.
#
###############################################################################
#include <linux/linkage.h>
#include <asm/thread_info.h>
#include <asm/processor.h>
#include <asm/registers.h>
#include <asm/spr-regs.h>

.macro LEDS val
	setlos		#~\val,gr27
	st		gr27,@(gr30,gr0)
	membar
	dcf		@(gr30,gr0)
.endm

	.section	.sdata
	.balign		8

	# address of frame 0 (userspace) on current kernel stack
	.globl		__kernel_frame0_ptr
__kernel_frame0_ptr:
	.long		init_thread_union + THREAD_SIZE - USER_CONTEXT_SIZE

	# address of current task
	.globl		__kernel_current_task
__kernel_current_task:
	.long		init_task

	.section	.text
	.balign		4

###############################################################################
#
# struct task_struct *__switch_to(struct thread_struct *prev_thread,
#				  struct thread_struct *next_thread,
#				  struct task_struct *prev)
#
###############################################################################
	.globl		__switch_to
__switch_to:
	# save outgoing process's context
	sethi.p		%hi(__switch_back),gr13
	setlo		%lo(__switch_back),gr13
	movsg		lr,gr12

	stdi		gr28,@(gr8,#__THREAD_FRAME)
	sti		sp  ,@(gr8,#__THREAD_SP)
	sti		fp  ,@(gr8,#__THREAD_FP)
	stdi		gr12,@(gr8,#__THREAD_LR)
	stdi		gr16,@(gr8,#__THREAD_GR(16))
	stdi		gr18,@(gr8,#__THREAD_GR(18))
	stdi		gr20,@(gr8,#__THREAD_GR(20))
	stdi		gr22,@(gr8,#__THREAD_GR(22))
	stdi		gr24,@(gr8,#__THREAD_GR(24))
	stdi.p		gr26,@(gr8,#__THREAD_GR(26))

	or		gr8,gr8,gr22
	ldi.p		@(gr8,#__THREAD_USER),gr8
	call		save_user_regs
	or		gr22,gr22,gr8
	
	# retrieve the new context
	sethi.p		%hi(__kernel_frame0_ptr),gr6
	setlo		%lo(__kernel_frame0_ptr),gr6
	movsg		psr,gr4

	lddi.p		@(gr9,#__THREAD_FRAME),gr10
	or		gr10,gr10,gr27		; save prev for the return value

	ldi		@(gr11,#4),gr19		; get new_current->thread_info

	lddi		@(gr9,#__THREAD_SP),gr12
	ldi		@(gr9,#__THREAD_LR),gr14
	ldi		@(gr9,#__THREAD_PC),gr18
	ldi.p		@(gr9,#__THREAD_FRAME0),gr7

	# actually switch kernel contexts with ordinary exceptions disabled
	andi		gr4,#~PSR_ET,gr5
	movgs		gr5,psr

	or.p		gr10,gr0,gr28		; set __frame
	or		gr11,gr0,gr29		; set __current
	or.p		gr12,gr0,sp
	or		gr13,gr0,fp
	or		gr19,gr0,gr15		; set __current_thread_info

	sti		gr7,@(gr6,#0)		; set __kernel_frame0_ptr
	sti		gr29,@(gr6,#4)		; set __kernel_current_task

	movgs		gr14,lr
	bar

	srli		gr15,#28,gr5
	subicc		gr5,#0xc,gr0,icc0
	beq		icc0,#0,111f
	break
	nop
111:

	# jump to __switch_back or ret_from_fork as appropriate
	# - move prev to GR8
	movgs		gr4,psr
	jmpl.p		@(gr18,gr0)
	or		gr27,gr27,gr8

###############################################################################
#
# restore incoming process's context
# - on entry:
#   - SP, FP, LR, GR15, GR28 and GR29 will have been set up appropriately
#   - GR8 will point to the outgoing task_struct
#   - GR9 will point to the incoming thread_struct
#
###############################################################################
__switch_back:
	lddi		@(gr9,#__THREAD_GR(16)),gr16
	lddi		@(gr9,#__THREAD_GR(18)),gr18
	lddi		@(gr9,#__THREAD_GR(20)),gr20
	lddi		@(gr9,#__THREAD_GR(22)),gr22
	lddi		@(gr9,#__THREAD_GR(24)),gr24
	lddi		@(gr9,#__THREAD_GR(26)),gr26

	# fall through into restore_user_regs()
	ldi.p		@(gr9,#__THREAD_USER),gr8
	or		gr8,gr8,gr9

###############################################################################
#
# restore extra general regs and FP/Media regs
# - void *restore_user_regs(const struct user_context *target, void *retval)
# - on entry:
#   - GR8 will point to the user context to swap in
#   - GR9 will contain the value to be returned in GR8 (prev task on context switch)
#
###############################################################################
	.globl		restore_user_regs
restore_user_regs:
	movsg		hsr0,gr6
	ori		gr6,#HSR0_GRHE|HSR0_FRLE|HSR0_FRHE,gr6
	movgs		gr6,hsr0
	movsg		hsr0,gr6

	movsg		psr,gr7
	ori		gr7,#PSR_EF|PSR_EM,gr7
	movgs		gr7,psr
	movsg		psr,gr7
	srli		gr7,#24,gr7
	bar

	lddi		@(gr8,#__FPMEDIA_MSR(0)),gr4

	movgs		gr4,msr0
	movgs		gr5,msr1

	lddfi		@(gr8,#__FPMEDIA_ACC(0)),fr16
	lddfi		@(gr8,#__FPMEDIA_ACC(2)),fr18
	ldbfi		@(gr8,#__FPMEDIA_ACCG(0)),fr20
	ldbfi		@(gr8,#__FPMEDIA_ACCG(1)),fr21
	ldbfi		@(gr8,#__FPMEDIA_ACCG(2)),fr22
	ldbfi		@(gr8,#__FPMEDIA_ACCG(3)),fr23

	mwtacc		fr16,acc0
	mwtacc		fr17,acc1
	mwtacc		fr18,acc2
	mwtacc		fr19,acc3
	mwtaccg		fr20,accg0
	mwtaccg		fr21,accg1
	mwtaccg		fr22,accg2
	mwtaccg		fr23,accg3

	# some CPUs have extra ACCx and ACCGx regs and maybe FSRx regs
	subicc.p	gr7,#0x50,gr0,icc0
	subicc		gr7,#0x31,gr0,icc1
	beq		icc0,#0,__restore_acc_fr451
	beq		icc1,#0,__restore_acc_fr555
__restore_acc_cont:

	# some CPU's have GR32-GR63
	setlos		#HSR0_FRHE,gr4
	andcc		gr6,gr4,gr0,icc0
	beq		icc0,#1,__restore_skip_gr32_gr63

	lddi		@(gr8,#__INT_GR(32)),gr32
	lddi		@(gr8,#__INT_GR(34)),gr34
	lddi		@(gr8,#__INT_GR(36)),gr36
	lddi		@(gr8,#__INT_GR(38)),gr38
	lddi		@(gr8,#__INT_GR(40)),gr40
	lddi		@(gr8,#__INT_GR(42)),gr42
	lddi		@(gr8,#__INT_GR(44)),gr44
	lddi		@(gr8,#__INT_GR(46)),gr46
	lddi		@(gr8,#__INT_GR(48)),gr48
	lddi		@(gr8,#__INT_GR(50)),gr50
	lddi		@(gr8,#__INT_GR(52)),gr52
	lddi		@(gr8,#__INT_GR(54)),gr54
	lddi		@(gr8,#__INT_GR(56)),gr56
	lddi		@(gr8,#__INT_GR(58)),gr58
	lddi		@(gr8,#__INT_GR(60)),gr60
	lddi		@(gr8,#__INT_GR(62)),gr62
__restore_skip_gr32_gr63:

	# all CPU's have FR0-FR31
	lddfi		@(gr8,#__FPMEDIA_FR( 0)),fr0
	lddfi		@(gr8,#__FPMEDIA_FR( 2)),fr2
	lddfi		@(gr8,#__FPMEDIA_FR( 4)),fr4
	lddfi		@(gr8,#__FPMEDIA_FR( 6)),fr6
	lddfi		@(gr8,#__FPMEDIA_FR( 8)),fr8
	lddfi		@(gr8,#__FPMEDIA_FR(10)),fr10
	lddfi		@(gr8,#__FPMEDIA_FR(12)),fr12
	lddfi		@(gr8,#__FPMEDIA_FR(14)),fr14
	lddfi		@(gr8,#__FPMEDIA_FR(16)),fr16
	lddfi		@(gr8,#__FPMEDIA_FR(18)),fr18
	lddfi		@(gr8,#__FPMEDIA_FR(20)),fr20
	lddfi		@(gr8,#__FPMEDIA_FR(22)),fr22
	lddfi		@(gr8,#__FPMEDIA_FR(24)),fr24
	lddfi		@(gr8,#__FPMEDIA_FR(26)),fr26
	lddfi		@(gr8,#__FPMEDIA_FR(28)),fr28
	lddfi.p		@(gr8,#__FPMEDIA_FR(30)),fr30

	# some CPU's have FR32-FR63
	setlos		#HSR0_FRHE,gr4
	andcc		gr6,gr4,gr0,icc0
	beq		icc0,#1,__restore_skip_fr32_fr63

	lddfi		@(gr8,#__FPMEDIA_FR(32)),fr32
	lddfi		@(gr8,#__FPMEDIA_FR(34)),fr34
	lddfi		@(gr8,#__FPMEDIA_FR(36)),fr36
	lddfi		@(gr8,#__FPMEDIA_FR(38)),fr38
	lddfi		@(gr8,#__FPMEDIA_FR(40)),fr40
	lddfi		@(gr8,#__FPMEDIA_FR(42)),fr42
	lddfi		@(gr8,#__FPMEDIA_FR(44)),fr44
	lddfi		@(gr8,#__FPMEDIA_FR(46)),fr46
	lddfi		@(gr8,#__FPMEDIA_FR(48)),fr48
	lddfi		@(gr8,#__FPMEDIA_FR(50)),fr50
	lddfi		@(gr8,#__FPMEDIA_FR(52)),fr52
	lddfi		@(gr8,#__FPMEDIA_FR(54)),fr54
	lddfi		@(gr8,#__FPMEDIA_FR(56)),fr56
	lddfi		@(gr8,#__FPMEDIA_FR(58)),fr58
	lddfi		@(gr8,#__FPMEDIA_FR(60)),fr60
	lddfi		@(gr8,#__FPMEDIA_FR(62)),fr62
__restore_skip_fr32_fr63:

	lddi		@(gr8,#__FPMEDIA_FNER(0)),gr4
	movsg		fner0,gr4
	movsg		fner1,gr5
	or.p		gr9,gr9,gr8
	bralr

	# the FR451 also has ACC8-11/ACCG8-11 regs (but not 4-7...)
__restore_acc_fr451:
	lddfi		@(gr8,#__FPMEDIA_ACC(4)),fr16
	lddfi		@(gr8,#__FPMEDIA_ACC(6)),fr18
	ldbfi		@(gr8,#__FPMEDIA_ACCG(4)),fr20
	ldbfi		@(gr8,#__FPMEDIA_ACCG(5)),fr21
	ldbfi		@(gr8,#__FPMEDIA_ACCG(6)),fr22
	ldbfi		@(gr8,#__FPMEDIA_ACCG(7)),fr23

	mwtacc		fr16,acc8
	mwtacc		fr17,acc9
	mwtacc		fr18,acc10
	mwtacc		fr19,acc11
	mwtaccg		fr20,accg8
	mwtaccg		fr21,accg9
	mwtaccg		fr22,accg10
	mwtaccg		fr23,accg11
	bra		__restore_acc_cont

	# the FR555 also has ACC4-7/ACCG4-7 regs and an FSR0 reg
__restore_acc_fr555:
	lddfi		@(gr8,#__FPMEDIA_ACC(4)),fr16
	lddfi		@(gr8,#__FPMEDIA_ACC(6)),fr18
	ldbfi		@(gr8,#__FPMEDIA_ACCG(4)),fr20
	ldbfi		@(gr8,#__FPMEDIA_ACCG(5)),fr21
	ldbfi		@(gr8,#__FPMEDIA_ACCG(6)),fr22
	ldbfi		@(gr8,#__FPMEDIA_ACCG(7)),fr23

	mnop.p
	mwtacc		fr16,acc4
	mnop.p
	mwtacc		fr17,acc5
	mnop.p
	mwtacc		fr18,acc6
	mnop.p
	mwtacc		fr19,acc7
	mnop.p
	mwtaccg		fr20,accg4
	mnop.p
	mwtaccg		fr21,accg5
	mnop.p
	mwtaccg		fr22,accg6
	mnop.p
	mwtaccg		fr23,accg7

	ldi		@(gr8,#__FPMEDIA_FSR(0)),gr4
	movgs		gr4,fsr0

	bra		__restore_acc_cont


###############################################################################
#
# save extra general regs and FP/Media regs
# - void save_user_regs(struct user_context *target)
#
###############################################################################
	.globl		save_user_regs
save_user_regs:
	movsg		hsr0,gr6
	ori		gr6,#HSR0_GRHE|HSR0_FRLE|HSR0_FRHE,gr6
	movgs		gr6,hsr0
	movsg		hsr0,gr6

	movsg		psr,gr7
	ori		gr7,#PSR_EF|PSR_EM,gr7
	movgs		gr7,psr
	movsg		psr,gr7
	srli		gr7,#24,gr7
	bar

	movsg		fner0,gr4
	movsg		fner1,gr5
	stdi.p		gr4,@(gr8,#__FPMEDIA_FNER(0))

	# some CPU's have GR32-GR63
	setlos		#HSR0_GRHE,gr4
	andcc		gr6,gr4,gr0,icc0
	beq		icc0,#1,__save_skip_gr32_gr63

	stdi		gr32,@(gr8,#__INT_GR(32))
	stdi		gr34,@(gr8,#__INT_GR(34))
	stdi		gr36,@(gr8,#__INT_GR(36))
	stdi		gr38,@(gr8,#__INT_GR(38))
	stdi		gr40,@(gr8,#__INT_GR(40))
	stdi		gr42,@(gr8,#__INT_GR(42))
	stdi		gr44,@(gr8,#__INT_GR(44))
	stdi		gr46,@(gr8,#__INT_GR(46))
	stdi		gr48,@(gr8,#__INT_GR(48))
	stdi		gr50,@(gr8,#__INT_GR(50))
	stdi		gr52,@(gr8,#__INT_GR(52))
	stdi		gr54,@(gr8,#__INT_GR(54))
	stdi		gr56,@(gr8,#__INT_GR(56))
	stdi		gr58,@(gr8,#__INT_GR(58))
	stdi		gr60,@(gr8,#__INT_GR(60))
	stdi		gr62,@(gr8,#__INT_GR(62))
__save_skip_gr32_gr63:

	# all CPU's have FR0-FR31
	stdfi		fr0 ,@(gr8,#__FPMEDIA_FR( 0))
	stdfi		fr2 ,@(gr8,#__FPMEDIA_FR( 2))
	stdfi		fr4 ,@(gr8,#__FPMEDIA_FR( 4))
	stdfi		fr6 ,@(gr8,#__FPMEDIA_FR( 6))
	stdfi		fr8 ,@(gr8,#__FPMEDIA_FR( 8))
	stdfi		fr10,@(gr8,#__FPMEDIA_FR(10))
	stdfi		fr12,@(gr8,#__FPMEDIA_FR(12))
	stdfi		fr14,@(gr8,#__FPMEDIA_FR(14))
	stdfi		fr16,@(gr8,#__FPMEDIA_FR(16))
	stdfi		fr18,@(gr8,#__FPMEDIA_FR(18))
	stdfi		fr20,@(gr8,#__FPMEDIA_FR(20))
	stdfi		fr22,@(gr8,#__FPMEDIA_FR(22))
	stdfi		fr24,@(gr8,#__FPMEDIA_FR(24))
	stdfi		fr26,@(gr8,#__FPMEDIA_FR(26))
	stdfi		fr28,@(gr8,#__FPMEDIA_FR(28))
	stdfi.p		fr30,@(gr8,#__FPMEDIA_FR(30))

	# some CPU's have FR32-FR63
	setlos		#HSR0_FRHE,gr4
	andcc		gr6,gr4,gr0,icc0
	beq		icc0,#1,__save_skip_fr32_fr63

	stdfi		fr32,@(gr8,#__FPMEDIA_FR(32))
	stdfi		fr34,@(gr8,#__FPMEDIA_FR(34))
	stdfi		fr36,@(gr8,#__FPMEDIA_FR(36))
	stdfi		fr38,@(gr8,#__FPMEDIA_FR(38))
	stdfi		fr40,@(gr8,#__FPMEDIA_FR(40))
	stdfi		fr42,@(gr8,#__FPMEDIA_FR(42))
	stdfi		fr44,@(gr8,#__FPMEDIA_FR(44))
	stdfi		fr46,@(gr8,#__FPMEDIA_FR(46))
	stdfi		fr48,@(gr8,#__FPMEDIA_FR(48))
	stdfi		fr50,@(gr8,#__FPMEDIA_FR(50))
	stdfi		fr52,@(gr8,#__FPMEDIA_FR(52))
	stdfi		fr54,@(gr8,#__FPMEDIA_FR(54))
	stdfi		fr56,@(gr8,#__FPMEDIA_FR(56))
	stdfi		fr58,@(gr8,#__FPMEDIA_FR(58))
	stdfi		fr60,@(gr8,#__FPMEDIA_FR(60))
	stdfi		fr62,@(gr8,#__FPMEDIA_FR(62))
__save_skip_fr32_fr63:

	mrdacc		acc0 ,fr4
	mrdacc		acc1 ,fr5

	stdfi.p		fr4 ,@(gr8,#__FPMEDIA_ACC(0))

	mrdacc		acc2 ,fr6
	mrdacc		acc3 ,fr7

	stdfi.p		fr6 ,@(gr8,#__FPMEDIA_ACC(2))

	mrdaccg		accg0,fr4
	stbfi.p		fr4 ,@(gr8,#__FPMEDIA_ACCG(0))

	mrdaccg		accg1,fr5
	stbfi.p		fr5 ,@(gr8,#__FPMEDIA_ACCG(1))

	mrdaccg		accg2,fr6
	stbfi.p		fr6 ,@(gr8,#__FPMEDIA_ACCG(2))

	mrdaccg		accg3,fr7
	stbfi		fr7 ,@(gr8,#__FPMEDIA_ACCG(3))

	movsg		msr0 ,gr4
	movsg		msr1 ,gr5

	stdi		gr4 ,@(gr8,#__FPMEDIA_MSR(0))

	# some CPUs have extra ACCx and ACCGx regs and maybe FSRx regs
	subicc.p	gr7,#0x50,gr0,icc0
	subicc		gr7,#0x31,gr0,icc1
	beq		icc0,#0,__save_acc_fr451
	beq		icc1,#0,__save_acc_fr555
__save_acc_cont:

	lddfi		@(gr8,#__FPMEDIA_FR(4)),fr4
	lddfi.p		@(gr8,#__FPMEDIA_FR(6)),fr6
	bralr

	# the FR451 also has ACC8-11/ACCG8-11 regs (but not 4-7...)
__save_acc_fr451:
	mrdacc		acc8 ,fr4
	mrdacc		acc9 ,fr5

	stdfi.p		fr4 ,@(gr8,#__FPMEDIA_ACC(4))

	mrdacc		acc10,fr6
	mrdacc		acc11,fr7

	stdfi.p		fr6 ,@(gr8,#__FPMEDIA_ACC(6))

	mrdaccg		accg8,fr4
	stbfi.p		fr4 ,@(gr8,#__FPMEDIA_ACCG(4))

	mrdaccg		accg9,fr5
	stbfi.p		fr5 ,@(gr8,#__FPMEDIA_ACCG(5))

	mrdaccg		accg10,fr6
	stbfi.p		fr6 ,@(gr8,#__FPMEDIA_ACCG(6))

	mrdaccg		accg11,fr7
	stbfi		fr7 ,@(gr8,#__FPMEDIA_ACCG(7))
	bra		__save_acc_cont

	# the FR555 also has ACC4-7/ACCG4-7 regs and an FSR0 reg
__save_acc_fr555:
	mnop.p
	mrdacc		acc4 ,fr4
	mnop.p
	mrdacc		acc5 ,fr5

	stdfi		fr4 ,@(gr8,#__FPMEDIA_ACC(4))

	mnop.p
	mrdacc		acc6 ,fr6
	mnop.p
	mrdacc		acc7 ,fr7

	stdfi		fr6 ,@(gr8,#__FPMEDIA_ACC(6))

	mnop.p
	mrdaccg		accg4,fr4
	stbfi		fr4 ,@(gr8,#__FPMEDIA_ACCG(4))

	mnop.p
	mrdaccg		accg5,fr5
	stbfi		fr5 ,@(gr8,#__FPMEDIA_ACCG(5))

	mnop.p
	mrdaccg		accg6,fr6
	stbfi		fr6 ,@(gr8,#__FPMEDIA_ACCG(6))

	mnop.p
	mrdaccg		accg7,fr7
	stbfi		fr7 ,@(gr8,#__FPMEDIA_ACCG(7))

	movsg		fsr0 ,gr4
	sti		gr4 ,@(gr8,#__FPMEDIA_FSR(0))
	bra		__save_acc_cont