^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0-only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Context switch support for Hexagon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <asm/asm-offsets.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) .text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * The register used as a fast-path thread information pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * is determined as a kernel configuration option. If it happens
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * to be a callee-save register, we're going to be saving and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * restoring it twice here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * This code anticipates a revised ABI where R20-23 are added
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * to the set of callee-save registers, but this should be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * backward compatible to legacy tools.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * void switch_to(struct task_struct *prev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * struct task_struct *next, struct task_struct *last);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) .p2align 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) .globl __switch_to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) .type __switch_to, @function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * When we exit the wormhole, we need to store the previous task
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * in the new R0's pointer. Technically it should be R2, but they should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * be the same; seems like a legacy thing. In short, don't butcher
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * R0, let it go back out unmolested.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) __switch_to:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * Push callee-saves onto "prev" stack.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * Here, we're sneaky because the LR and FP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * storage of the thread_stack structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * is automagically allocated by allocframe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * so we pass struct size less 8.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) allocframe(#(_SWITCH_STACK_SIZE - 8));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) memd(R29+#(_SWITCH_R2726))=R27:26;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) memd(R29+#(_SWITCH_R2524))=R25:24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) memd(R29+#(_SWITCH_R2322))=R23:22;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) memd(R29+#(_SWITCH_R2120))=R21:20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) memd(R29+#(_SWITCH_R1918))=R19:18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) memd(R29+#(_SWITCH_R1716))=R17:16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* Stash thread_info pointer in task_struct */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) memw(R0+#_TASK_THREAD_INFO) = THREADINFO_REG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) memw(R0 +#(_TASK_STRUCT_THREAD + _THREAD_STRUCT_SWITCH_SP)) = R29;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* Switch to "next" stack and restore callee saves from there */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) R29 = memw(R1 + #(_TASK_STRUCT_THREAD + _THREAD_STRUCT_SWITCH_SP));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) R27:26 = memd(R29+#(_SWITCH_R2726));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) R25:24 = memd(R29+#(_SWITCH_R2524));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) R23:22 = memd(R29+#(_SWITCH_R2322));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) R21:20 = memd(R29+#(_SWITCH_R2120));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) R19:18 = memd(R29+#(_SWITCH_R1918));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) R17:16 = memd(R29+#(_SWITCH_R1716));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /* THREADINFO_REG is currently one of the callee-saved regs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * above, and so be sure to re-load it last.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) THREADINFO_REG = memw(R1 + #_TASK_THREAD_INFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) R31:30 = memd(R29+#_SWITCH_FP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) R29 = add(R29,#_SWITCH_STACK_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) jumpr R31;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) .size __switch_to, .-__switch_to