1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Context switch support for Hexagon 4 * 5 * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. 6 */ 7 8 #include <asm/asm-offsets.h> 9 10 .text 11 12 /* 13 * The register used as a fast-path thread information pointer 14 * is determined as a kernel configuration option. If it happens 15 * to be a callee-save register, we're going to be saving and 16 * restoring it twice here. 17 * 18 * This code anticipates a revised ABI where R20-23 are added 19 * to the set of callee-save registers, but this should be 20 * backward compatible to legacy tools. 21 */ 22 23 24 /* 25 * void switch_to(struct task_struct *prev, 26 * struct task_struct *next, struct task_struct *last); 27 */ 28 .p2align 2 29 .globl __switch_to 30 .type __switch_to, @function 31 32 /* 33 * When we exit the wormhole, we need to store the previous task 34 * in the new R0's pointer. Technically it should be R2, but they should 35 * be the same; seems like a legacy thing. In short, don't butcher 36 * R0, let it go back out unmolested. 37 */ 38 39 __switch_to: 40 /* 41 * Push callee-saves onto "prev" stack. 42 * Here, we're sneaky because the LR and FP 43 * storage of the thread_stack structure 44 * is automagically allocated by allocframe, 45 * so we pass struct size less 8. 46 */ 47 allocframe(#(_SWITCH_STACK_SIZE - 8)); 48 memd(R29+#(_SWITCH_R2726))=R27:26; 49 memd(R29+#(_SWITCH_R2524))=R25:24; 50 memd(R29+#(_SWITCH_R2322))=R23:22; 51 memd(R29+#(_SWITCH_R2120))=R21:20; 52 memd(R29+#(_SWITCH_R1918))=R19:18; 53 memd(R29+#(_SWITCH_R1716))=R17:16; 54 /* Stash thread_info pointer in task_struct */ 55 memw(R0+#_TASK_THREAD_INFO) = THREADINFO_REG; 56 memw(R0 +#(_TASK_STRUCT_THREAD + _THREAD_STRUCT_SWITCH_SP)) = R29; 57 /* Switch to "next" stack and restore callee saves from there */ 58 R29 = memw(R1 + #(_TASK_STRUCT_THREAD + _THREAD_STRUCT_SWITCH_SP)); 59 { 60 R27:26 = memd(R29+#(_SWITCH_R2726)); 61 R25:24 = memd(R29+#(_SWITCH_R2524)); 62 } 63 { 64 R23:22 = memd(R29+#(_SWITCH_R2322)); 65 R21:20 = memd(R29+#(_SWITCH_R2120)); 66 } 67 { 68 R19:18 = memd(R29+#(_SWITCH_R1918)); 69 R17:16 = memd(R29+#(_SWITCH_R1716)); 70 } 71 { 72 /* THREADINFO_REG is currently one of the callee-saved regs 73 * above, and so be sure to re-load it last. 74 */ 75 THREADINFO_REG = memw(R1 + #_TASK_THREAD_INFO); 76 R31:30 = memd(R29+#_SWITCH_FP); 77 } 78 { 79 R29 = add(R29,#_SWITCH_STACK_SIZE); 80 jumpr R31; 81 } 82 .size __switch_to, .-__switch_to