Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / arch / hexagon / kernel / vm_switch.S
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