Thomas Gleixner | 08dbd0f | 2019-05-29 07:12:41 -0700 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Richard Kuo | e49ee29 | 2011-10-31 18:39:14 -0500 | [diff] [blame] | 2 | /* |
| 3 | * Context switch support for Hexagon |
| 4 | * |
Richard Kuo | e1858b2 | 2012-09-19 16:22:02 -0500 | [diff] [blame] | 5 | * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. |
Richard Kuo | e49ee29 | 2011-10-31 18:39:14 -0500 | [diff] [blame] | 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 |