1/* 2 * Context switch support for Hexagon 3 * 4 * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 and 8 * only version 2 as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 * 02110-1301, USA. 19 */ 20 21#include <asm/asm-offsets.h> 22 23.text 24 25/* 26 * The register used as a fast-path thread information pointer 27 * is determined as a kernel configuration option. If it happens 28 * to be a callee-save register, we're going to be saving and 29 * restoring it twice here. 30 * 31 * This code anticipates a revised ABI where R20-23 are added 32 * to the set of callee-save registers, but this should be 33 * backward compatible to legacy tools. 34 */ 35 36 37/* 38 * void switch_to(struct task_struct *prev, 39 * struct task_struct *next, struct task_struct *last); 40 */ 41 .p2align 2 42 .globl __switch_to 43 .type __switch_to, @function 44 45/* 46 * When we exit the wormhole, we need to store the previous task 47 * in the new R0's pointer. Technically it should be R2, but they should 48 * be the same; seems like a legacy thing. In short, don't butcher 49 * R0, let it go back out unmolested. 50 */ 51 52__switch_to: 53 /* 54 * Push callee-saves onto "prev" stack. 55 * Here, we're sneaky because the LR and FP 56 * storage of the thread_stack structure 57 * is automagically allocated by allocframe, 58 * so we pass struct size less 8. 59 */ 60 allocframe(#(_SWITCH_STACK_SIZE - 8)); 61 memd(R29+#(_SWITCH_R2726))=R27:26; 62 memd(R29+#(_SWITCH_R2524))=R25:24; 63 memd(R29+#(_SWITCH_R2322))=R23:22; 64 memd(R29+#(_SWITCH_R2120))=R21:20; 65 memd(R29+#(_SWITCH_R1918))=R19:18; 66 memd(R29+#(_SWITCH_R1716))=R17:16; 67 /* Stash thread_info pointer in task_struct */ 68 memw(R0+#_TASK_THREAD_INFO) = THREADINFO_REG; 69 memw(R0 +#(_TASK_STRUCT_THREAD + _THREAD_STRUCT_SWITCH_SP)) = R29; 70 /* Switch to "next" stack and restore callee saves from there */ 71 R29 = memw(R1 + #(_TASK_STRUCT_THREAD + _THREAD_STRUCT_SWITCH_SP)); 72 { 73 R27:26 = memd(R29+#(_SWITCH_R2726)); 74 R25:24 = memd(R29+#(_SWITCH_R2524)); 75 } 76 { 77 R23:22 = memd(R29+#(_SWITCH_R2322)); 78 R21:20 = memd(R29+#(_SWITCH_R2120)); 79 } 80 { 81 R19:18 = memd(R29+#(_SWITCH_R1918)); 82 R17:16 = memd(R29+#(_SWITCH_R1716)); 83 } 84 { 85 /* THREADINFO_REG is currently one of the callee-saved regs 86 * above, and so be sure to re-load it last. 87 */ 88 THREADINFO_REG = memw(R1 + #_TASK_THREAD_INFO); 89 R31:30 = memd(R29+#_SWITCH_FP); 90 } 91 { 92 R29 = add(R29,#_SWITCH_STACK_SIZE); 93 jumpr R31; 94 } 95 .size __switch_to, .-__switch_to 96