162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Context switch support for Hexagon 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <asm/asm-offsets.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci.text 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* 1362306a36Sopenharmony_ci * The register used as a fast-path thread information pointer 1462306a36Sopenharmony_ci * is determined as a kernel configuration option. If it happens 1562306a36Sopenharmony_ci * to be a callee-save register, we're going to be saving and 1662306a36Sopenharmony_ci * restoring it twice here. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * This code anticipates a revised ABI where R20-23 are added 1962306a36Sopenharmony_ci * to the set of callee-save registers, but this should be 2062306a36Sopenharmony_ci * backward compatible to legacy tools. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * void switch_to(struct task_struct *prev, 2662306a36Sopenharmony_ci * struct task_struct *next, struct task_struct *last); 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci .p2align 2 2962306a36Sopenharmony_ci .globl __switch_to 3062306a36Sopenharmony_ci .type __switch_to, @function 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * When we exit the wormhole, we need to store the previous task 3462306a36Sopenharmony_ci * in the new R0's pointer. Technically it should be R2, but they should 3562306a36Sopenharmony_ci * be the same; seems like a legacy thing. In short, don't butcher 3662306a36Sopenharmony_ci * R0, let it go back out unmolested. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci__switch_to: 4062306a36Sopenharmony_ci /* 4162306a36Sopenharmony_ci * Push callee-saves onto "prev" stack. 4262306a36Sopenharmony_ci * Here, we're sneaky because the LR and FP 4362306a36Sopenharmony_ci * storage of the thread_stack structure 4462306a36Sopenharmony_ci * is automagically allocated by allocframe, 4562306a36Sopenharmony_ci * so we pass struct size less 8. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci allocframe(#(_SWITCH_STACK_SIZE - 8)); 4862306a36Sopenharmony_ci memd(R29+#(_SWITCH_R2726))=R27:26; 4962306a36Sopenharmony_ci memd(R29+#(_SWITCH_R2524))=R25:24; 5062306a36Sopenharmony_ci memd(R29+#(_SWITCH_R2322))=R23:22; 5162306a36Sopenharmony_ci memd(R29+#(_SWITCH_R2120))=R21:20; 5262306a36Sopenharmony_ci memd(R29+#(_SWITCH_R1918))=R19:18; 5362306a36Sopenharmony_ci memd(R29+#(_SWITCH_R1716))=R17:16; 5462306a36Sopenharmony_ci /* Stash thread_info pointer in task_struct */ 5562306a36Sopenharmony_ci memw(R0+#_TASK_THREAD_INFO) = THREADINFO_REG; 5662306a36Sopenharmony_ci memw(R0 +#(_TASK_STRUCT_THREAD + _THREAD_STRUCT_SWITCH_SP)) = R29; 5762306a36Sopenharmony_ci /* Switch to "next" stack and restore callee saves from there */ 5862306a36Sopenharmony_ci R29 = memw(R1 + #(_TASK_STRUCT_THREAD + _THREAD_STRUCT_SWITCH_SP)); 5962306a36Sopenharmony_ci { 6062306a36Sopenharmony_ci R27:26 = memd(R29+#(_SWITCH_R2726)); 6162306a36Sopenharmony_ci R25:24 = memd(R29+#(_SWITCH_R2524)); 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci { 6462306a36Sopenharmony_ci R23:22 = memd(R29+#(_SWITCH_R2322)); 6562306a36Sopenharmony_ci R21:20 = memd(R29+#(_SWITCH_R2120)); 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci { 6862306a36Sopenharmony_ci R19:18 = memd(R29+#(_SWITCH_R1918)); 6962306a36Sopenharmony_ci R17:16 = memd(R29+#(_SWITCH_R1716)); 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci { 7262306a36Sopenharmony_ci /* THREADINFO_REG is currently one of the callee-saved regs 7362306a36Sopenharmony_ci * above, and so be sure to re-load it last. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci THREADINFO_REG = memw(R1 + #_TASK_THREAD_INFO); 7662306a36Sopenharmony_ci R31:30 = memd(R29+#_SWITCH_FP); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci { 7962306a36Sopenharmony_ci R29 = add(R29,#_SWITCH_STACK_SIZE); 8062306a36Sopenharmony_ci jumpr R31; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci .size __switch_to, .-__switch_to 83