MIPS: initial stack protector support
[deliverable/linux.git] / arch / mips / kernel / octeon_switch.S
CommitLineData
5b3b1688
DD
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1994, 1995, 1996, 1998, 1999, 2002, 2003 Ralf Baechle
79add627 7 * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
5b3b1688
DD
8 * Copyright (C) 1994, 1995, 1996, by Andreas Busse
9 * Copyright (C) 1999 Silicon Graphics, Inc.
10 * Copyright (C) 2000 MIPS Technologies, Inc.
11 * written by Carsten Langgaard, carstenl@mips.com
12 */
13#include <asm/asm.h>
14#include <asm/cachectl.h>
15#include <asm/fpregdef.h>
16#include <asm/mipsregs.h>
17#include <asm/asm-offsets.h>
5b3b1688
DD
18#include <asm/pgtable-bits.h>
19#include <asm/regdef.h>
20#include <asm/stackframe.h>
21#include <asm/thread_info.h>
22
23#include <asm/asmmacro.h>
24
25/*
26 * Offset to the current process status flags, the first 32 bytes of the
27 * stack are not used.
28 */
29#define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS)
30
31/*
32 * task_struct *resume(task_struct *prev, task_struct *next,
70342287 33 * struct thread_info *next_ti, int usedfpu)
5b3b1688
DD
34 */
35 .align 7
36 LEAF(resume)
37 .set arch=octeon
5b3b1688
DD
38 mfc0 t1, CP0_STATUS
39 LONG_S t1, THREAD_STATUS(a0)
40 cpu_save_nonscratch a0
41 LONG_S ra, THREAD_REG31(a0)
42
5b3b1688
DD
43#if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0
44 /* Check if we need to store CVMSEG state */
70342287 45 mfc0 t0, $11,7 /* CvmMemCtl */
5b3b1688
DD
46 bbit0 t0, 6, 3f /* Is user access enabled? */
47
48 /* Store the CVMSEG state */
49 /* Extract the size of CVMSEG */
50 andi t0, 0x3f
51 /* Multiply * (cache line size/sizeof(long)/2) */
52 sll t0, 7-LONGLOG-1
70342287
RB
53 li t1, -32768 /* Base address of CVMSEG */
54 LONG_ADDI t2, a0, THREAD_CVMSEG /* Where to store CVMSEG to */
5b3b1688
DD
55 synciobdma
562:
57 .set noreorder
58 LONG_L t8, 0(t1) /* Load from CVMSEG */
59 subu t0, 1 /* Decrement loop var */
60 LONG_L t9, LONGSIZE(t1)/* Load from CVMSEG */
61 LONG_ADDU t1, LONGSIZE*2 /* Increment loc in CVMSEG */
62 LONG_S t8, 0(t2) /* Store CVMSEG to thread storage */
63 LONG_ADDU t2, LONGSIZE*2 /* Increment loc in thread storage */
64 bnez t0, 2b /* Loop until we've copied it all */
70342287 65 LONG_S t9, -LONGSIZE(t2)/* Store CVMSEG to thread storage */
5b3b1688
DD
66 .set reorder
67
68 /* Disable access to CVMSEG */
70342287 69 mfc0 t0, $11,7 /* CvmMemCtl */
5b3b1688 70 xori t0, t0, 0x40 /* Bit 6 is CVMSEG user enable */
70342287 71 mtc0 t0, $11,7 /* CvmMemCtl */
5b3b1688
DD
72#endif
733:
74 /*
75 * The order of restoring the registers takes care of the race
76 * updating $28, $29 and kernelsp without disabling ints.
77 */
78 move $28, a2
79 cpu_restore_nonscratch a1
80
81#if (_THREAD_SIZE - 32) < 0x8000
82 PTR_ADDIU t0, $28, _THREAD_SIZE - 32
83#else
84 PTR_LI t0, _THREAD_SIZE - 32
85 PTR_ADDU t0, $28
86#endif
87 set_saved_sp t0, t1, t2
88
89 mfc0 t1, CP0_STATUS /* Do we really need this? */
90 li a3, 0xff01
91 and t1, a3
92 LONG_L a2, THREAD_STATUS(a1)
93 nor a3, $0, a3
94 and a2, a3
95 or a2, t1
96 mtc0 a2, CP0_STATUS
97 move v0, a0
98 jr ra
99 END(resume)
100
101/*
102 * void octeon_cop2_save(struct octeon_cop2_state *a0)
103 */
104 .align 7
105 LEAF(octeon_cop2_save)
106
107 dmfc0 t9, $9,7 /* CvmCtl register. */
108
70342287 109 /* Save the COP2 CRC state */
5b3b1688
DD
110 dmfc2 t0, 0x0201
111 dmfc2 t1, 0x0202
112 dmfc2 t2, 0x0200
113 sd t0, OCTEON_CP2_CRC_IV(a0)
114 sd t1, OCTEON_CP2_CRC_LENGTH(a0)
115 sd t2, OCTEON_CP2_CRC_POLY(a0)
116 /* Skip next instructions if CvmCtl[NODFA_CP2] set */
117 bbit1 t9, 28, 1f
118
119 /* Save the LLM state */
120 dmfc2 t0, 0x0402
121 dmfc2 t1, 0x040A
122 sd t0, OCTEON_CP2_LLM_DAT(a0)
123 sd t1, OCTEON_CP2_LLM_DAT+8(a0)
124
70342287 1251: bbit1 t9, 26, 3f /* done if CvmCtl[NOCRYPTO] set */
5b3b1688
DD
126
127 /* Save the COP2 crypto state */
70342287
RB
128 /* this part is mostly common to both pass 1 and later revisions */
129 dmfc2 t0, 0x0084
130 dmfc2 t1, 0x0080
131 dmfc2 t2, 0x0081
132 dmfc2 t3, 0x0082
5b3b1688 133 sd t0, OCTEON_CP2_3DES_IV(a0)
70342287 134 dmfc2 t0, 0x0088
5b3b1688 135 sd t1, OCTEON_CP2_3DES_KEY(a0)
70342287 136 dmfc2 t1, 0x0111 /* only necessary for pass 1 */
5b3b1688 137 sd t2, OCTEON_CP2_3DES_KEY+8(a0)
70342287 138 dmfc2 t2, 0x0102
5b3b1688 139 sd t3, OCTEON_CP2_3DES_KEY+16(a0)
70342287 140 dmfc2 t3, 0x0103
5b3b1688 141 sd t0, OCTEON_CP2_3DES_RESULT(a0)
70342287
RB
142 dmfc2 t0, 0x0104
143 sd t1, OCTEON_CP2_AES_INP0(a0) /* only necessary for pass 1 */
144 dmfc2 t1, 0x0105
5b3b1688
DD
145 sd t2, OCTEON_CP2_AES_IV(a0)
146 dmfc2 t2, 0x0106
147 sd t3, OCTEON_CP2_AES_IV+8(a0)
70342287 148 dmfc2 t3, 0x0107
5b3b1688
DD
149 sd t0, OCTEON_CP2_AES_KEY(a0)
150 dmfc2 t0, 0x0110
151 sd t1, OCTEON_CP2_AES_KEY+8(a0)
152 dmfc2 t1, 0x0100
153 sd t2, OCTEON_CP2_AES_KEY+16(a0)
154 dmfc2 t2, 0x0101
155 sd t3, OCTEON_CP2_AES_KEY+24(a0)
70342287 156 mfc0 t3, $15,0 /* Get the processor ID register */
5b3b1688
DD
157 sd t0, OCTEON_CP2_AES_KEYLEN(a0)
158 li t0, 0x000d0000 /* This is the processor ID of Octeon Pass1 */
159 sd t1, OCTEON_CP2_AES_RESULT(a0)
160 sd t2, OCTEON_CP2_AES_RESULT+8(a0)
161 /* Skip to the Pass1 version of the remainder of the COP2 state */
162 beq t3, t0, 2f
163
70342287 164 /* the non-pass1 state when !CvmCtl[NOCRYPTO] */
5b3b1688
DD
165 dmfc2 t1, 0x0240
166 dmfc2 t2, 0x0241
167 dmfc2 t3, 0x0242
168 dmfc2 t0, 0x0243
169 sd t1, OCTEON_CP2_HSH_DATW(a0)
170 dmfc2 t1, 0x0244
171 sd t2, OCTEON_CP2_HSH_DATW+8(a0)
172 dmfc2 t2, 0x0245
173 sd t3, OCTEON_CP2_HSH_DATW+16(a0)
174 dmfc2 t3, 0x0246
175 sd t0, OCTEON_CP2_HSH_DATW+24(a0)
176 dmfc2 t0, 0x0247
177 sd t1, OCTEON_CP2_HSH_DATW+32(a0)
178 dmfc2 t1, 0x0248
179 sd t2, OCTEON_CP2_HSH_DATW+40(a0)
180 dmfc2 t2, 0x0249
181 sd t3, OCTEON_CP2_HSH_DATW+48(a0)
182 dmfc2 t3, 0x024A
183 sd t0, OCTEON_CP2_HSH_DATW+56(a0)
184 dmfc2 t0, 0x024B
185 sd t1, OCTEON_CP2_HSH_DATW+64(a0)
186 dmfc2 t1, 0x024C
187 sd t2, OCTEON_CP2_HSH_DATW+72(a0)
188 dmfc2 t2, 0x024D
189 sd t3, OCTEON_CP2_HSH_DATW+80(a0)
70342287 190 dmfc2 t3, 0x024E
5b3b1688
DD
191 sd t0, OCTEON_CP2_HSH_DATW+88(a0)
192 dmfc2 t0, 0x0250
193 sd t1, OCTEON_CP2_HSH_DATW+96(a0)
194 dmfc2 t1, 0x0251
195 sd t2, OCTEON_CP2_HSH_DATW+104(a0)
196 dmfc2 t2, 0x0252
197 sd t3, OCTEON_CP2_HSH_DATW+112(a0)
198 dmfc2 t3, 0x0253
199 sd t0, OCTEON_CP2_HSH_IVW(a0)
200 dmfc2 t0, 0x0254
201 sd t1, OCTEON_CP2_HSH_IVW+8(a0)
202 dmfc2 t1, 0x0255
203 sd t2, OCTEON_CP2_HSH_IVW+16(a0)
204 dmfc2 t2, 0x0256
205 sd t3, OCTEON_CP2_HSH_IVW+24(a0)
206 dmfc2 t3, 0x0257
207 sd t0, OCTEON_CP2_HSH_IVW+32(a0)
70342287 208 dmfc2 t0, 0x0258
5b3b1688 209 sd t1, OCTEON_CP2_HSH_IVW+40(a0)
70342287 210 dmfc2 t1, 0x0259
5b3b1688
DD
211 sd t2, OCTEON_CP2_HSH_IVW+48(a0)
212 dmfc2 t2, 0x025E
213 sd t3, OCTEON_CP2_HSH_IVW+56(a0)
214 dmfc2 t3, 0x025A
215 sd t0, OCTEON_CP2_GFM_MULT(a0)
216 dmfc2 t0, 0x025B
217 sd t1, OCTEON_CP2_GFM_MULT+8(a0)
218 sd t2, OCTEON_CP2_GFM_POLY(a0)
219 sd t3, OCTEON_CP2_GFM_RESULT(a0)
220 sd t0, OCTEON_CP2_GFM_RESULT+8(a0)
221 jr ra
222
70342287 2232: /* pass 1 special stuff when !CvmCtl[NOCRYPTO] */
5b3b1688
DD
224 dmfc2 t3, 0x0040
225 dmfc2 t0, 0x0041
226 dmfc2 t1, 0x0042
227 dmfc2 t2, 0x0043
228 sd t3, OCTEON_CP2_HSH_DATW(a0)
229 dmfc2 t3, 0x0044
230 sd t0, OCTEON_CP2_HSH_DATW+8(a0)
231 dmfc2 t0, 0x0045
232 sd t1, OCTEON_CP2_HSH_DATW+16(a0)
233 dmfc2 t1, 0x0046
234 sd t2, OCTEON_CP2_HSH_DATW+24(a0)
235 dmfc2 t2, 0x0048
236 sd t3, OCTEON_CP2_HSH_DATW+32(a0)
237 dmfc2 t3, 0x0049
238 sd t0, OCTEON_CP2_HSH_DATW+40(a0)
239 dmfc2 t0, 0x004A
240 sd t1, OCTEON_CP2_HSH_DATW+48(a0)
241 sd t2, OCTEON_CP2_HSH_IVW(a0)
242 sd t3, OCTEON_CP2_HSH_IVW+8(a0)
243 sd t0, OCTEON_CP2_HSH_IVW+16(a0)
244
70342287 2453: /* pass 1 or CvmCtl[NOCRYPTO] set */
5b3b1688
DD
246 jr ra
247 END(octeon_cop2_save)
248
249/*
250 * void octeon_cop2_restore(struct octeon_cop2_state *a0)
251 */
252 .align 7
253 .set push
254 .set noreorder
255 LEAF(octeon_cop2_restore)
70342287
RB
256 /* First cache line was prefetched before the call */
257 pref 4, 128(a0)
5b3b1688
DD
258 dmfc0 t9, $9,7 /* CvmCtl register. */
259
70342287 260 pref 4, 256(a0)
5b3b1688 261 ld t0, OCTEON_CP2_CRC_IV(a0)
70342287 262 pref 4, 384(a0)
5b3b1688
DD
263 ld t1, OCTEON_CP2_CRC_LENGTH(a0)
264 ld t2, OCTEON_CP2_CRC_POLY(a0)
265
266 /* Restore the COP2 CRC state */
267 dmtc2 t0, 0x0201
70342287 268 dmtc2 t1, 0x1202
5b3b1688
DD
269 bbit1 t9, 28, 2f /* Skip LLM if CvmCtl[NODFA_CP2] is set */
270 dmtc2 t2, 0x4200
271
272 /* Restore the LLM state */
273 ld t0, OCTEON_CP2_LLM_DAT(a0)
274 ld t1, OCTEON_CP2_LLM_DAT+8(a0)
275 dmtc2 t0, 0x0402
276 dmtc2 t1, 0x040A
277
2782:
279 bbit1 t9, 26, done_restore /* done if CvmCtl[NOCRYPTO] set */
280 nop
281
282 /* Restore the COP2 crypto state common to pass 1 and pass 2 */
283 ld t0, OCTEON_CP2_3DES_IV(a0)
284 ld t1, OCTEON_CP2_3DES_KEY(a0)
285 ld t2, OCTEON_CP2_3DES_KEY+8(a0)
70342287 286 dmtc2 t0, 0x0084
5b3b1688 287 ld t0, OCTEON_CP2_3DES_KEY+16(a0)
70342287 288 dmtc2 t1, 0x0080
5b3b1688 289 ld t1, OCTEON_CP2_3DES_RESULT(a0)
70342287 290 dmtc2 t2, 0x0081
5b3b1688
DD
291 ld t2, OCTEON_CP2_AES_INP0(a0) /* only really needed for pass 1 */
292 dmtc2 t0, 0x0082
293 ld t0, OCTEON_CP2_AES_IV(a0)
70342287 294 dmtc2 t1, 0x0098
5b3b1688 295 ld t1, OCTEON_CP2_AES_IV+8(a0)
70342287 296 dmtc2 t2, 0x010A /* only really needed for pass 1 */
5b3b1688 297 ld t2, OCTEON_CP2_AES_KEY(a0)
70342287 298 dmtc2 t0, 0x0102
5b3b1688
DD
299 ld t0, OCTEON_CP2_AES_KEY+8(a0)
300 dmtc2 t1, 0x0103
301 ld t1, OCTEON_CP2_AES_KEY+16(a0)
302 dmtc2 t2, 0x0104
303 ld t2, OCTEON_CP2_AES_KEY+24(a0)
304 dmtc2 t0, 0x0105
305 ld t0, OCTEON_CP2_AES_KEYLEN(a0)
306 dmtc2 t1, 0x0106
307 ld t1, OCTEON_CP2_AES_RESULT(a0)
308 dmtc2 t2, 0x0107
309 ld t2, OCTEON_CP2_AES_RESULT+8(a0)
70342287 310 mfc0 t3, $15,0 /* Get the processor ID register */
5b3b1688
DD
311 dmtc2 t0, 0x0110
312 li t0, 0x000d0000 /* This is the processor ID of Octeon Pass1 */
313 dmtc2 t1, 0x0100
314 bne t0, t3, 3f /* Skip the next stuff for non-pass1 */
315 dmtc2 t2, 0x0101
316
70342287 317 /* this code is specific for pass 1 */
5b3b1688
DD
318 ld t0, OCTEON_CP2_HSH_DATW(a0)
319 ld t1, OCTEON_CP2_HSH_DATW+8(a0)
320 ld t2, OCTEON_CP2_HSH_DATW+16(a0)
321 dmtc2 t0, 0x0040
322 ld t0, OCTEON_CP2_HSH_DATW+24(a0)
323 dmtc2 t1, 0x0041
324 ld t1, OCTEON_CP2_HSH_DATW+32(a0)
325 dmtc2 t2, 0x0042
326 ld t2, OCTEON_CP2_HSH_DATW+40(a0)
327 dmtc2 t0, 0x0043
328 ld t0, OCTEON_CP2_HSH_DATW+48(a0)
329 dmtc2 t1, 0x0044
330 ld t1, OCTEON_CP2_HSH_IVW(a0)
331 dmtc2 t2, 0x0045
332 ld t2, OCTEON_CP2_HSH_IVW+8(a0)
333 dmtc2 t0, 0x0046
334 ld t0, OCTEON_CP2_HSH_IVW+16(a0)
335 dmtc2 t1, 0x0048
336 dmtc2 t2, 0x0049
70342287 337 b done_restore /* unconditional branch */
5b3b1688
DD
338 dmtc2 t0, 0x004A
339
70342287 3403: /* this is post-pass1 code */
5b3b1688
DD
341 ld t2, OCTEON_CP2_HSH_DATW(a0)
342 ld t0, OCTEON_CP2_HSH_DATW+8(a0)
343 ld t1, OCTEON_CP2_HSH_DATW+16(a0)
344 dmtc2 t2, 0x0240
345 ld t2, OCTEON_CP2_HSH_DATW+24(a0)
346 dmtc2 t0, 0x0241
347 ld t0, OCTEON_CP2_HSH_DATW+32(a0)
348 dmtc2 t1, 0x0242
349 ld t1, OCTEON_CP2_HSH_DATW+40(a0)
350 dmtc2 t2, 0x0243
351 ld t2, OCTEON_CP2_HSH_DATW+48(a0)
352 dmtc2 t0, 0x0244
353 ld t0, OCTEON_CP2_HSH_DATW+56(a0)
354 dmtc2 t1, 0x0245
355 ld t1, OCTEON_CP2_HSH_DATW+64(a0)
356 dmtc2 t2, 0x0246
357 ld t2, OCTEON_CP2_HSH_DATW+72(a0)
358 dmtc2 t0, 0x0247
359 ld t0, OCTEON_CP2_HSH_DATW+80(a0)
360 dmtc2 t1, 0x0248
361 ld t1, OCTEON_CP2_HSH_DATW+88(a0)
362 dmtc2 t2, 0x0249
363 ld t2, OCTEON_CP2_HSH_DATW+96(a0)
364 dmtc2 t0, 0x024A
365 ld t0, OCTEON_CP2_HSH_DATW+104(a0)
366 dmtc2 t1, 0x024B
367 ld t1, OCTEON_CP2_HSH_DATW+112(a0)
368 dmtc2 t2, 0x024C
369 ld t2, OCTEON_CP2_HSH_IVW(a0)
370 dmtc2 t0, 0x024D
371 ld t0, OCTEON_CP2_HSH_IVW+8(a0)
372 dmtc2 t1, 0x024E
373 ld t1, OCTEON_CP2_HSH_IVW+16(a0)
374 dmtc2 t2, 0x0250
375 ld t2, OCTEON_CP2_HSH_IVW+24(a0)
376 dmtc2 t0, 0x0251
377 ld t0, OCTEON_CP2_HSH_IVW+32(a0)
378 dmtc2 t1, 0x0252
379 ld t1, OCTEON_CP2_HSH_IVW+40(a0)
380 dmtc2 t2, 0x0253
381 ld t2, OCTEON_CP2_HSH_IVW+48(a0)
382 dmtc2 t0, 0x0254
383 ld t0, OCTEON_CP2_HSH_IVW+56(a0)
384 dmtc2 t1, 0x0255
385 ld t1, OCTEON_CP2_GFM_MULT(a0)
386 dmtc2 t2, 0x0256
387 ld t2, OCTEON_CP2_GFM_MULT+8(a0)
388 dmtc2 t0, 0x0257
389 ld t0, OCTEON_CP2_GFM_POLY(a0)
390 dmtc2 t1, 0x0258
391 ld t1, OCTEON_CP2_GFM_RESULT(a0)
392 dmtc2 t2, 0x0259
393 ld t2, OCTEON_CP2_GFM_RESULT+8(a0)
394 dmtc2 t0, 0x025E
395 dmtc2 t1, 0x025A
396 dmtc2 t2, 0x025B
397
398done_restore:
399 jr ra
400 nop
401 END(octeon_cop2_restore)
402 .set pop
403
404/*
405 * void octeon_mult_save()
406 * sp is assumed to point to a struct pt_regs
407 *
408 * NOTE: This is called in SAVE_SOME in stackframe.h. It can only
70342287 409 * safely modify k0 and k1.
5b3b1688
DD
410 */
411 .align 7
412 .set push
413 .set noreorder
414 LEAF(octeon_mult_save)
415 dmfc0 k0, $9,7 /* CvmCtl register. */
416 bbit1 k0, 27, 1f /* Skip CvmCtl[NOMUL] */
417 nop
418
419 /* Save the multiplier state */
420 v3mulu k0, $0, $0
421 v3mulu k1, $0, $0
70342287 422 sd k0, PT_MTP(sp) /* PT_MTP has P0 */
5b3b1688
DD
423 v3mulu k0, $0, $0
424 sd k1, PT_MTP+8(sp) /* PT_MTP+8 has P1 */
425 ori k1, $0, 1
426 v3mulu k1, k1, $0
427 sd k0, PT_MTP+16(sp) /* PT_MTP+16 has P2 */
428 v3mulu k0, $0, $0
70342287 429 sd k1, PT_MPL(sp) /* PT_MPL has MPL0 */
5b3b1688
DD
430 v3mulu k1, $0, $0
431 sd k0, PT_MPL+8(sp) /* PT_MPL+8 has MPL1 */
432 jr ra
433 sd k1, PT_MPL+16(sp) /* PT_MPL+16 has MPL2 */
434
4351: /* Resume here if CvmCtl[NOMUL] */
436 jr ra
437 END(octeon_mult_save)
438 .set pop
439
440/*
441 * void octeon_mult_restore()
442 * sp is assumed to point to a struct pt_regs
443 *
444 * NOTE: This is called in RESTORE_SOME in stackframe.h.
445 */
446 .align 7
447 .set push
448 .set noreorder
449 LEAF(octeon_mult_restore)
450 dmfc0 k1, $9,7 /* CvmCtl register. */
70342287
RB
451 ld v0, PT_MPL(sp) /* MPL0 */
452 ld v1, PT_MPL+8(sp) /* MPL1 */
453 ld k0, PT_MPL+16(sp) /* MPL2 */
5b3b1688
DD
454 bbit1 k1, 27, 1f /* Skip CvmCtl[NOMUL] */
455 /* Normally falls through, so no time wasted here */
456 nop
457
458 /* Restore the multiplier state */
70342287 459 ld k1, PT_MTP+16(sp) /* P2 */
5b3b1688
DD
460 MTM0 v0 /* MPL0 */
461 ld v0, PT_MTP+8(sp) /* P1 */
462 MTM1 v1 /* MPL1 */
70342287 463 ld v1, PT_MTP(sp) /* P0 */
5b3b1688
DD
464 MTM2 k0 /* MPL2 */
465 MTP2 k1 /* P2 */
466 MTP1 v0 /* P1 */
467 jr ra
468 MTP0 v1 /* P0 */
469
4701: /* Resume here if CvmCtl[NOMUL] */
471 jr ra
472 nop
473 END(octeon_mult_restore)
474 .set pop
This page took 0.277351 seconds and 5 git commands to generate.