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 |
83 | |