Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
0004  *
0005  * Vineetg: Aug 2009
0006  *  -"C" version of lowest level context switch asm macro called by schedular
0007  *   gcc doesn't generate the dward CFI info for hand written asm, hence can't
0008  *   backtrace out of it (e.g. tasks sleeping in kernel).
0009  *   So we cheat a bit by writing almost similar code in inline-asm.
0010  *  -This is a hacky way of doing things, but there is no other simple way.
0011  *   I don't want/intend to extend unwinding code to understand raw asm
0012  */
0013 
0014 #include <asm/asm-offsets.h>
0015 #include <linux/sched.h>
0016 #include <linux/sched/debug.h>
0017 
0018 #define KSP_WORD_OFF    ((TASK_THREAD + THREAD_KSP) / 4)
0019 
0020 struct task_struct *__sched
0021 __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
0022 {
0023     unsigned int tmp;
0024     unsigned int prev = (unsigned int)prev_task;
0025     unsigned int next = (unsigned int)next_task;
0026 
0027     __asm__ __volatile__(
0028         /* FP/BLINK save generated by gcc (standard function prologue */
0029         "st.a    r13, [sp, -4]   \n\t"
0030         "st.a    r14, [sp, -4]   \n\t"
0031         "st.a    r15, [sp, -4]   \n\t"
0032         "st.a    r16, [sp, -4]   \n\t"
0033         "st.a    r17, [sp, -4]   \n\t"
0034         "st.a    r18, [sp, -4]   \n\t"
0035         "st.a    r19, [sp, -4]   \n\t"
0036         "st.a    r20, [sp, -4]   \n\t"
0037         "st.a    r21, [sp, -4]   \n\t"
0038         "st.a    r22, [sp, -4]   \n\t"
0039         "st.a    r23, [sp, -4]   \n\t"
0040         "st.a    r24, [sp, -4]   \n\t"
0041 #ifndef CONFIG_ARC_CURR_IN_REG
0042         "st.a    r25, [sp, -4]   \n\t"
0043 #else
0044         "sub     sp, sp, 4      \n\t"   /* usual r25 placeholder */
0045 #endif
0046 
0047         /* set ksp of outgoing task in tsk->thread.ksp */
0048 #if KSP_WORD_OFF <= 255
0049         "st.as   sp, [%3, %1]    \n\t"
0050 #else
0051         /*
0052          * Workaround for NR_CPUS=4k
0053          * %1 is bigger than 255 (S9 offset for st.as)
0054          */
0055         "add2    r24, %3, %1     \n\t"
0056         "st      sp, [r24]       \n\t"
0057 #endif
0058 
0059         /*
0060          * setup _current_task with incoming tsk.
0061          * optionally, set r25 to that as well
0062          * For SMP extra work to get to &_current_task[cpu]
0063          * (open coded SET_CURR_TASK_ON_CPU)
0064          */
0065 #ifndef CONFIG_SMP
0066         "st  %2, [@_current_task]   \n\t"
0067 #else
0068         "lr   r24, [identity]       \n\t"
0069         "lsr  r24, r24, 8       \n\t"
0070         "bmsk r24, r24, 7       \n\t"
0071         "add2 r24, @_current_task, r24  \n\t"
0072         "st   %2,  [r24]        \n\t"
0073 #endif
0074 #ifdef CONFIG_ARC_CURR_IN_REG
0075         "mov r25, %2   \n\t"
0076 #endif
0077 
0078         /* get ksp of incoming task from tsk->thread.ksp */
0079         "ld.as  sp, [%2, %1]   \n\t"
0080 
0081         /* start loading it's CALLEE reg file */
0082 
0083 #ifndef CONFIG_ARC_CURR_IN_REG
0084         "ld.ab   r25, [sp, 4]   \n\t"
0085 #else
0086         "add    sp, sp, 4       \n\t"
0087 #endif
0088         "ld.ab   r24, [sp, 4]   \n\t"
0089         "ld.ab   r23, [sp, 4]   \n\t"
0090         "ld.ab   r22, [sp, 4]   \n\t"
0091         "ld.ab   r21, [sp, 4]   \n\t"
0092         "ld.ab   r20, [sp, 4]   \n\t"
0093         "ld.ab   r19, [sp, 4]   \n\t"
0094         "ld.ab   r18, [sp, 4]   \n\t"
0095         "ld.ab   r17, [sp, 4]   \n\t"
0096         "ld.ab   r16, [sp, 4]   \n\t"
0097         "ld.ab   r15, [sp, 4]   \n\t"
0098         "ld.ab   r14, [sp, 4]   \n\t"
0099         "ld.ab   r13, [sp, 4]   \n\t"
0100 
0101         /* last (ret value) = prev : although for ARC it mov r0, r0 */
0102         "mov     %0, %3        \n\t"
0103 
0104         /* FP/BLINK restore generated by gcc (standard func epilogue */
0105 
0106         : "=r"(tmp)
0107         : "n"(KSP_WORD_OFF), "r"(next), "r"(prev)
0108         : "blink"
0109     );
0110 
0111     return (struct task_struct *)tmp;
0112 }