linux/arch/arc/kernel/ctx_sw.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
   4 *
   5 * Vineetg: Aug 2009
   6 *  -"C" version of lowest level context switch asm macro called by schedular
   7 *   gcc doesn't generate the dward CFI info for hand written asm, hence can't
   8 *   backtrace out of it (e.g. tasks sleeping in kernel).
   9 *   So we cheat a bit by writing almost similar code in inline-asm.
  10 *  -This is a hacky way of doing things, but there is no other simple way.
  11 *   I don't want/intend to extend unwinding code to understand raw asm
  12 */
  13
  14#include <asm/asm-offsets.h>
  15#include <linux/sched.h>
  16#include <linux/sched/debug.h>
  17
  18#define KSP_WORD_OFF    ((TASK_THREAD + THREAD_KSP) / 4)
  19
  20struct task_struct *__sched
  21__switch_to(struct task_struct *prev_task, struct task_struct *next_task)
  22{
  23        unsigned int tmp;
  24        unsigned int prev = (unsigned int)prev_task;
  25        unsigned int next = (unsigned int)next_task;
  26
  27        __asm__ __volatile__(
  28                /* FP/BLINK save generated by gcc (standard function prologue */
  29                "st.a    r13, [sp, -4]   \n\t"
  30                "st.a    r14, [sp, -4]   \n\t"
  31                "st.a    r15, [sp, -4]   \n\t"
  32                "st.a    r16, [sp, -4]   \n\t"
  33                "st.a    r17, [sp, -4]   \n\t"
  34                "st.a    r18, [sp, -4]   \n\t"
  35                "st.a    r19, [sp, -4]   \n\t"
  36                "st.a    r20, [sp, -4]   \n\t"
  37                "st.a    r21, [sp, -4]   \n\t"
  38                "st.a    r22, [sp, -4]   \n\t"
  39                "st.a    r23, [sp, -4]   \n\t"
  40                "st.a    r24, [sp, -4]   \n\t"
  41#ifndef CONFIG_ARC_CURR_IN_REG
  42                "st.a    r25, [sp, -4]   \n\t"
  43#else
  44                "sub     sp, sp, 4      \n\t"   /* usual r25 placeholder */
  45#endif
  46
  47                /* set ksp of outgoing task in tsk->thread.ksp */
  48#if KSP_WORD_OFF <= 255
  49                "st.as   sp, [%3, %1]    \n\t"
  50#else
  51                /*
  52                 * Workaround for NR_CPUS=4k
  53                 * %1 is bigger than 255 (S9 offset for st.as)
  54                 */
  55                "add2    r24, %3, %1     \n\t"
  56                "st      sp, [r24]       \n\t"
  57#endif
  58
  59                /*
  60                 * setup _current_task with incoming tsk.
  61                 * optionally, set r25 to that as well
  62                 * For SMP extra work to get to &_current_task[cpu]
  63                 * (open coded SET_CURR_TASK_ON_CPU)
  64                 */
  65#ifndef CONFIG_SMP
  66                "st  %2, [@_current_task]       \n\t"
  67#else
  68                "lr   r24, [identity]           \n\t"
  69                "lsr  r24, r24, 8               \n\t"
  70                "bmsk r24, r24, 7               \n\t"
  71                "add2 r24, @_current_task, r24  \n\t"
  72                "st   %2,  [r24]                \n\t"
  73#endif
  74#ifdef CONFIG_ARC_CURR_IN_REG
  75                "mov r25, %2   \n\t"
  76#endif
  77
  78                /* get ksp of incoming task from tsk->thread.ksp */
  79                "ld.as  sp, [%2, %1]   \n\t"
  80
  81                /* start loading it's CALLEE reg file */
  82
  83#ifndef CONFIG_ARC_CURR_IN_REG
  84                "ld.ab   r25, [sp, 4]   \n\t"
  85#else
  86                "add    sp, sp, 4       \n\t"
  87#endif
  88                "ld.ab   r24, [sp, 4]   \n\t"
  89                "ld.ab   r23, [sp, 4]   \n\t"
  90                "ld.ab   r22, [sp, 4]   \n\t"
  91                "ld.ab   r21, [sp, 4]   \n\t"
  92                "ld.ab   r20, [sp, 4]   \n\t"
  93                "ld.ab   r19, [sp, 4]   \n\t"
  94                "ld.ab   r18, [sp, 4]   \n\t"
  95                "ld.ab   r17, [sp, 4]   \n\t"
  96                "ld.ab   r16, [sp, 4]   \n\t"
  97                "ld.ab   r15, [sp, 4]   \n\t"
  98                "ld.ab   r14, [sp, 4]   \n\t"
  99                "ld.ab   r13, [sp, 4]   \n\t"
 100
 101                /* last (ret value) = prev : although for ARC it mov r0, r0 */
 102                "mov     %0, %3        \n\t"
 103
 104                /* FP/BLINK restore generated by gcc (standard func epilogue */
 105
 106                : "=r"(tmp)
 107                : "n"(KSP_WORD_OFF), "r"(next), "r"(prev)
 108                : "blink"
 109        );
 110
 111        return (struct task_struct *)tmp;
 112}
 113