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, 95, 96, 99, 2001 Ralf Baechle 7 * Copyright (C) 1994, 1995, 1996 Paul M. Antoine. 8 * Copyright (C) 1999 Silicon Graphics, Inc. 9 * Copyright (C) 2007 Maciej W. Rozycki 10 */ 11 #ifndef _ASM_STACKFRAME_H 12 #define _ASM_STACKFRAME_H 13 14 #include <linux/threads.h> 15 16 #include <asm/asm.h> 17 #include <asm/asmmacro.h> 18 #include <asm/mipsregs.h> 19 #include <asm/asm-offsets.h> 20 #include <asm/thread_info.h> 21 22 #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) 23 #define STATMASK 0x3f 24 #else 25 #define STATMASK 0x1f 26 #endif 27 28 .macro SAVE_AT 29 .set push 30 .set noat 31 LONG_S $1, PT_R1(sp) 32 .set pop 33 .endm 34 35 .macro SAVE_TEMP 36 #ifdef CONFIG_CPU_HAS_SMARTMIPS 37 mflhxu v1 38 LONG_S v1, PT_LO(sp) 39 mflhxu v1 40 LONG_S v1, PT_HI(sp) 41 mflhxu v1 42 LONG_S v1, PT_ACX(sp) 43 #elif !defined(CONFIG_CPU_MIPSR6) 44 mfhi v1 45 #endif 46 #ifdef CONFIG_32BIT 47 LONG_S $8, PT_R8(sp) 48 LONG_S $9, PT_R9(sp) 49 #endif 50 LONG_S $10, PT_R10(sp) 51 LONG_S $11, PT_R11(sp) 52 LONG_S $12, PT_R12(sp) 53 #if !defined(CONFIG_CPU_HAS_SMARTMIPS) && !defined(CONFIG_CPU_MIPSR6) 54 LONG_S v1, PT_HI(sp) 55 mflo v1 56 #endif 57 LONG_S $13, PT_R13(sp) 58 LONG_S $14, PT_R14(sp) 59 LONG_S $15, PT_R15(sp) 60 LONG_S $24, PT_R24(sp) 61 #if !defined(CONFIG_CPU_HAS_SMARTMIPS) && !defined(CONFIG_CPU_MIPSR6) 62 LONG_S v1, PT_LO(sp) 63 #endif 64 #ifdef CONFIG_CPU_CAVIUM_OCTEON 65 /* 66 * The Octeon multiplier state is affected by general 67 * multiply instructions. It must be saved before and 68 * kernel code might corrupt it 69 */ 70 jal octeon_mult_save 71 #endif 72 .endm 73 74 .macro SAVE_STATIC 75 LONG_S $16, PT_R16(sp) 76 LONG_S $17, PT_R17(sp) 77 LONG_S $18, PT_R18(sp) 78 LONG_S $19, PT_R19(sp) 79 LONG_S $20, PT_R20(sp) 80 LONG_S $21, PT_R21(sp) 81 LONG_S $22, PT_R22(sp) 82 LONG_S $23, PT_R23(sp) 83 LONG_S $30, PT_R30(sp) 84 .endm 85 86 #ifdef CONFIG_SMP 87 .macro get_saved_sp /* SMP variation */ 88 ASM_CPUID_MFC0 k0, ASM_SMP_CPUID_REG 89 #if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) 90 lui k1, %hi(kernelsp) 91 #else 92 lui k1, %highest(kernelsp) 93 daddiu k1, %higher(kernelsp) 94 dsll k1, 16 95 daddiu k1, %hi(kernelsp) 96 dsll k1, 16 97 #endif 98 LONG_SRL k0, SMP_CPUID_PTRSHIFT 99 LONG_ADDU k1, k0 100 LONG_L k1, %lo(kernelsp)(k1) 101 .endm 102 103 .macro set_saved_sp stackp temp temp2 104 ASM_CPUID_MFC0 \temp, ASM_SMP_CPUID_REG 105 LONG_SRL \temp, SMP_CPUID_PTRSHIFT 106 LONG_S \stackp, kernelsp(\temp) 107 .endm 108 #else /* !CONFIG_SMP */ 109 .macro get_saved_sp /* Uniprocessor variation */ 110 #ifdef CONFIG_CPU_JUMP_WORKAROUNDS 111 /* 112 * Clear BTB (branch target buffer), forbid RAS (return address 113 * stack) to workaround the Out-of-order Issue in Loongson2F 114 * via its diagnostic register. 115 */ 116 move k0, ra 117 jal 1f 118 nop 119 1: jal 1f 120 nop 121 1: jal 1f 122 nop 123 1: jal 1f 124 nop 125 1: move ra, k0 126 li k0, 3 127 mtc0 k0, $22 128 #endif /* CONFIG_CPU_JUMP_WORKAROUNDS */ 129 #if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) 130 lui k1, %hi(kernelsp) 131 #else 132 lui k1, %highest(kernelsp) 133 daddiu k1, %higher(kernelsp) 134 dsll k1, k1, 16 135 daddiu k1, %hi(kernelsp) 136 dsll k1, k1, 16 137 #endif 138 LONG_L k1, %lo(kernelsp)(k1) 139 .endm 140 141 .macro set_saved_sp stackp temp temp2 142 LONG_S \stackp, kernelsp 143 .endm 144 #endif 145 146 .macro SAVE_SOME 147 .set push 148 .set noat 149 .set reorder 150 mfc0 k0, CP0_STATUS 151 sll k0, 3 /* extract cu0 bit */ 152 .set noreorder 153 bltz k0, 8f 154 move k1, sp 155 .set reorder 156 /* Called from user mode, new stack. */ 157 get_saved_sp 158 #ifndef CONFIG_CPU_DADDI_WORKAROUNDS 159 8: move k0, sp 160 PTR_SUBU sp, k1, PT_SIZE 161 #else 162 .set at=k0 163 8: PTR_SUBU k1, PT_SIZE 164 .set noat 165 move k0, sp 166 move sp, k1 167 #endif 168 LONG_S k0, PT_R29(sp) 169 LONG_S $3, PT_R3(sp) 170 /* 171 * You might think that you don't need to save $0, 172 * but the FPU emulator and gdb remote debug stub 173 * need it to operate correctly 174 */ 175 LONG_S $0, PT_R0(sp) 176 mfc0 v1, CP0_STATUS 177 LONG_S $2, PT_R2(sp) 178 LONG_S v1, PT_STATUS(sp) 179 LONG_S $4, PT_R4(sp) 180 mfc0 v1, CP0_CAUSE 181 LONG_S $5, PT_R5(sp) 182 LONG_S v1, PT_CAUSE(sp) 183 LONG_S $6, PT_R6(sp) 184 MFC0 v1, CP0_EPC 185 LONG_S $7, PT_R7(sp) 186 #ifdef CONFIG_64BIT 187 LONG_S $8, PT_R8(sp) 188 LONG_S $9, PT_R9(sp) 189 #endif 190 LONG_S v1, PT_EPC(sp) 191 LONG_S $25, PT_R25(sp) 192 LONG_S $28, PT_R28(sp) 193 LONG_S $31, PT_R31(sp) 194 ori $28, sp, _THREAD_MASK 195 xori $28, _THREAD_MASK 196 #ifdef CONFIG_CPU_CAVIUM_OCTEON 197 .set mips64 198 pref 0, 0($28) /* Prefetch the current pointer */ 199 #endif 200 .set pop 201 .endm 202 203 .macro SAVE_ALL 204 SAVE_SOME 205 SAVE_AT 206 SAVE_TEMP 207 SAVE_STATIC 208 .endm 209 210 .macro RESTORE_AT 211 .set push 212 .set noat 213 LONG_L $1, PT_R1(sp) 214 .set pop 215 .endm 216 217 .macro RESTORE_TEMP 218 #ifdef CONFIG_CPU_CAVIUM_OCTEON 219 /* Restore the Octeon multiplier state */ 220 jal octeon_mult_restore 221 #endif 222 #ifdef CONFIG_CPU_HAS_SMARTMIPS 223 LONG_L $24, PT_ACX(sp) 224 mtlhx $24 225 LONG_L $24, PT_HI(sp) 226 mtlhx $24 227 LONG_L $24, PT_LO(sp) 228 mtlhx $24 229 #elif !defined(CONFIG_CPU_MIPSR6) 230 LONG_L $24, PT_LO(sp) 231 mtlo $24 232 LONG_L $24, PT_HI(sp) 233 mthi $24 234 #endif 235 #ifdef CONFIG_32BIT 236 LONG_L $8, PT_R8(sp) 237 LONG_L $9, PT_R9(sp) 238 #endif 239 LONG_L $10, PT_R10(sp) 240 LONG_L $11, PT_R11(sp) 241 LONG_L $12, PT_R12(sp) 242 LONG_L $13, PT_R13(sp) 243 LONG_L $14, PT_R14(sp) 244 LONG_L $15, PT_R15(sp) 245 LONG_L $24, PT_R24(sp) 246 .endm 247 248 .macro RESTORE_STATIC 249 LONG_L $16, PT_R16(sp) 250 LONG_L $17, PT_R17(sp) 251 LONG_L $18, PT_R18(sp) 252 LONG_L $19, PT_R19(sp) 253 LONG_L $20, PT_R20(sp) 254 LONG_L $21, PT_R21(sp) 255 LONG_L $22, PT_R22(sp) 256 LONG_L $23, PT_R23(sp) 257 LONG_L $30, PT_R30(sp) 258 .endm 259 260 #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) 261 262 .macro RESTORE_SOME 263 .set push 264 .set reorder 265 .set noat 266 mfc0 a0, CP0_STATUS 267 li v1, 0xff00 268 ori a0, STATMASK 269 xori a0, STATMASK 270 mtc0 a0, CP0_STATUS 271 and a0, v1 272 LONG_L v0, PT_STATUS(sp) 273 nor v1, $0, v1 274 and v0, v1 275 or v0, a0 276 mtc0 v0, CP0_STATUS 277 LONG_L $31, PT_R31(sp) 278 LONG_L $28, PT_R28(sp) 279 LONG_L $25, PT_R25(sp) 280 LONG_L $7, PT_R7(sp) 281 LONG_L $6, PT_R6(sp) 282 LONG_L $5, PT_R5(sp) 283 LONG_L $4, PT_R4(sp) 284 LONG_L $3, PT_R3(sp) 285 LONG_L $2, PT_R2(sp) 286 .set pop 287 .endm 288 289 .macro RESTORE_SP_AND_RET 290 .set push 291 .set noreorder 292 LONG_L k0, PT_EPC(sp) 293 LONG_L sp, PT_R29(sp) 294 jr k0 295 rfe 296 .set pop 297 .endm 298 299 #else 300 .macro RESTORE_SOME 301 .set push 302 .set reorder 303 .set noat 304 mfc0 a0, CP0_STATUS 305 ori a0, STATMASK 306 xori a0, STATMASK 307 mtc0 a0, CP0_STATUS 308 li v1, 0xff00 309 and a0, v1 310 LONG_L v0, PT_STATUS(sp) 311 nor v1, $0, v1 312 and v0, v1 313 or v0, a0 314 mtc0 v0, CP0_STATUS 315 LONG_L v1, PT_EPC(sp) 316 MTC0 v1, CP0_EPC 317 LONG_L $31, PT_R31(sp) 318 LONG_L $28, PT_R28(sp) 319 LONG_L $25, PT_R25(sp) 320 #ifdef CONFIG_64BIT 321 LONG_L $8, PT_R8(sp) 322 LONG_L $9, PT_R9(sp) 323 #endif 324 LONG_L $7, PT_R7(sp) 325 LONG_L $6, PT_R6(sp) 326 LONG_L $5, PT_R5(sp) 327 LONG_L $4, PT_R4(sp) 328 LONG_L $3, PT_R3(sp) 329 LONG_L $2, PT_R2(sp) 330 .set pop 331 .endm 332 333 .macro RESTORE_SP_AND_RET 334 LONG_L sp, PT_R29(sp) 335 .set arch=r4000 336 eret 337 .set mips0 338 .endm 339 340 #endif 341 342 .macro RESTORE_SP 343 LONG_L sp, PT_R29(sp) 344 .endm 345 346 .macro RESTORE_ALL 347 RESTORE_TEMP 348 RESTORE_STATIC 349 RESTORE_AT 350 RESTORE_SOME 351 RESTORE_SP 352 .endm 353 354 .macro RESTORE_ALL_AND_RET 355 RESTORE_TEMP 356 RESTORE_STATIC 357 RESTORE_AT 358 RESTORE_SOME 359 RESTORE_SP_AND_RET 360 .endm 361 362 /* 363 * Move to kernel mode and disable interrupts. 364 * Set cp0 enable bit as sign that we're running on the kernel stack 365 */ 366 .macro CLI 367 mfc0 t0, CP0_STATUS 368 li t1, ST0_CU0 | STATMASK 369 or t0, t1 370 xori t0, STATMASK 371 mtc0 t0, CP0_STATUS 372 irq_disable_hazard 373 .endm 374 375 /* 376 * Move to kernel mode and enable interrupts. 377 * Set cp0 enable bit as sign that we're running on the kernel stack 378 */ 379 .macro STI 380 mfc0 t0, CP0_STATUS 381 li t1, ST0_CU0 | STATMASK 382 or t0, t1 383 xori t0, STATMASK & ~1 384 mtc0 t0, CP0_STATUS 385 irq_enable_hazard 386 .endm 387 388 /* 389 * Just move to kernel mode and leave interrupts as they are. Note 390 * for the R3000 this means copying the previous enable from IEp. 391 * Set cp0 enable bit as sign that we're running on the kernel stack 392 */ 393 .macro KMODE 394 mfc0 t0, CP0_STATUS 395 li t1, ST0_CU0 | (STATMASK & ~1) 396 #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) 397 andi t2, t0, ST0_IEP 398 srl t2, 2 399 or t0, t2 400 #endif 401 or t0, t1 402 xori t0, STATMASK & ~1 403 mtc0 t0, CP0_STATUS 404 irq_disable_hazard 405 .endm 406 407 #endif /* _ASM_STACKFRAME_H */ 408