Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / hexagon / kernel / vm_switch.S
diff --git a/kernel/arch/hexagon/kernel/vm_switch.S b/kernel/arch/hexagon/kernel/vm_switch.S
new file mode 100644 (file)
index 0000000..62c6df9
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Context switch support for Hexagon
+ *
+ * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <asm/asm-offsets.h>
+
+.text
+
+/*
+ * The register used as a fast-path thread information pointer
+ * is determined as a kernel configuration option.  If it happens
+ * to be a callee-save register, we're going to be saving and
+ * restoring it twice here.
+ *
+ * This code anticipates a revised ABI where R20-23 are added
+ * to the set of callee-save registers, but this should be
+ * backward compatible to legacy tools.
+ */
+
+
+/*
+ *     void switch_to(struct task_struct *prev,
+ *             struct task_struct *next, struct task_struct *last);
+ */
+       .p2align 2
+       .globl __switch_to
+       .type   __switch_to, @function
+
+/*
+ * When we exit the wormhole, we need to store the previous task
+ * in the new R0's pointer.  Technically it should be R2, but they should
+ * be the same; seems like a legacy thing.  In short, don't butcher
+ * R0, let it go back out unmolested.
+ */
+
+__switch_to:
+       /*
+        * Push callee-saves onto "prev" stack.
+        * Here, we're sneaky because the LR and FP
+        * storage of the thread_stack structure
+        * is automagically allocated by allocframe,
+        * so we pass struct size less 8.
+        */
+       allocframe(#(_SWITCH_STACK_SIZE - 8));
+       memd(R29+#(_SWITCH_R2726))=R27:26;
+       memd(R29+#(_SWITCH_R2524))=R25:24;
+       memd(R29+#(_SWITCH_R2322))=R23:22;
+       memd(R29+#(_SWITCH_R2120))=R21:20;
+       memd(R29+#(_SWITCH_R1918))=R19:18;
+       memd(R29+#(_SWITCH_R1716))=R17:16;
+       /* Stash thread_info pointer in task_struct */
+       memw(R0+#_TASK_THREAD_INFO) = THREADINFO_REG;
+       memw(R0 +#(_TASK_STRUCT_THREAD + _THREAD_STRUCT_SWITCH_SP)) = R29;
+       /* Switch to "next" stack and restore callee saves from there */
+       R29 = memw(R1 + #(_TASK_STRUCT_THREAD + _THREAD_STRUCT_SWITCH_SP));
+       {
+           R27:26 = memd(R29+#(_SWITCH_R2726));
+           R25:24 = memd(R29+#(_SWITCH_R2524));
+       }
+       {
+           R23:22 = memd(R29+#(_SWITCH_R2322));
+           R21:20 = memd(R29+#(_SWITCH_R2120));
+       }
+       {
+           R19:18 = memd(R29+#(_SWITCH_R1918));
+           R17:16 = memd(R29+#(_SWITCH_R1716));
+       }
+       {
+           /* THREADINFO_REG is currently one of the callee-saved regs
+            * above, and so be sure to re-load it last.
+            */
+           THREADINFO_REG = memw(R1 + #_TASK_THREAD_INFO);
+           R31:30 = memd(R29+#_SWITCH_FP);
+       }
+       {
+           R29 = add(R29,#_SWITCH_STACK_SIZE);
+           jumpr R31;
+       }
+       .size   __switch_to, .-__switch_to