linux/arch/arc/kernel/process.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 * Amit Bhor, Kanika Nema: Codito Technologies 2004
   6 */
   7
   8#include <linux/errno.h>
   9#include <linux/module.h>
  10#include <linux/sched.h>
  11#include <linux/sched/task.h>
  12#include <linux/sched/task_stack.h>
  13
  14#include <linux/mm.h>
  15#include <linux/fs.h>
  16#include <linux/unistd.h>
  17#include <linux/ptrace.h>
  18#include <linux/slab.h>
  19#include <linux/syscalls.h>
  20#include <linux/elf.h>
  21#include <linux/tick.h>
  22
  23SYSCALL_DEFINE1(arc_settls, void *, user_tls_data_ptr)
  24{
  25        task_thread_info(current)->thr_ptr = (unsigned int)user_tls_data_ptr;
  26        return 0;
  27}
  28
  29/*
  30 * We return the user space TLS data ptr as sys-call return code
  31 * Ideally it should be copy to user.
  32 * However we can cheat by the fact that some sys-calls do return
  33 * absurdly high values
  34 * Since the tls dat aptr is not going to be in range of 0xFFFF_xxxx
  35 * it won't be considered a sys-call error
  36 * and it will be loads better than copy-to-user, which is a definite
  37 * D-TLB Miss
  38 */
  39SYSCALL_DEFINE0(arc_gettls)
  40{
  41        return task_thread_info(current)->thr_ptr;
  42}
  43
  44SYSCALL_DEFINE3(arc_usr_cmpxchg, int *, uaddr, int, expected, int, new)
  45{
  46        struct pt_regs *regs = current_pt_regs();
  47        u32 uval;
  48        int ret;
  49
  50        /*
  51         * This is only for old cores lacking LLOCK/SCOND, which by defintion
  52         * can't possibly be SMP. Thus doesn't need to be SMP safe.
  53         * And this also helps reduce the overhead for serializing in
  54         * the UP case
  55         */
  56        WARN_ON_ONCE(IS_ENABLED(CONFIG_SMP));
  57
  58        /* Z indicates to userspace if operation succeded */
  59        regs->status32 &= ~STATUS_Z_MASK;
  60
  61        ret = access_ok(uaddr, sizeof(*uaddr));
  62        if (!ret)
  63                 goto fail;
  64
  65again:
  66        preempt_disable();
  67
  68        ret = __get_user(uval, uaddr);
  69        if (ret)
  70                 goto fault;
  71
  72        if (uval != expected)
  73                 goto out;
  74
  75        ret = __put_user(new, uaddr);
  76        if (ret)
  77                 goto fault;
  78
  79        regs->status32 |= STATUS_Z_MASK;
  80
  81out:
  82        preempt_enable();
  83        return uval;
  84
  85fault:
  86        preempt_enable();
  87
  88        if (unlikely(ret != -EFAULT))
  89                 goto fail;
  90
  91        down_read(&current->mm->mmap_sem);
  92        ret = fixup_user_fault(current, current->mm, (unsigned long) uaddr,
  93                               FAULT_FLAG_WRITE, NULL);
  94        up_read(&current->mm->mmap_sem);
  95
  96        if (likely(!ret))
  97                 goto again;
  98
  99fail:
 100        force_sig(SIGSEGV);
 101        return ret;
 102}
 103
 104#ifdef CONFIG_ISA_ARCV2
 105
 106void arch_cpu_idle(void)
 107{
 108        /* Re-enable interrupts <= default irq priority before commiting SLEEP */
 109        const unsigned int arg = 0x10 | ARCV2_IRQ_DEF_PRIO;
 110
 111        __asm__ __volatile__(
 112                "sleep %0       \n"
 113                :
 114                :"I"(arg)); /* can't be "r" has to be embedded const */
 115}
 116
 117#elif defined(CONFIG_EZNPS_MTM_EXT)     /* ARC700 variant in NPS */
 118
 119void arch_cpu_idle(void)
 120{
 121        /* only the calling HW thread needs to sleep */
 122        __asm__ __volatile__(
 123                ".word %0       \n"
 124                :
 125                :"i"(CTOP_INST_HWSCHD_WFT_IE12));
 126}
 127
 128#else   /* ARC700 */
 129
 130void arch_cpu_idle(void)
 131{
 132        /* sleep, but enable both set E1/E2 (levels of interrutps) before committing */
 133        __asm__ __volatile__("sleep 0x3 \n");
 134}
 135
 136#endif
 137
 138asmlinkage void ret_from_fork(void);
 139
 140/*
 141 * Copy architecture-specific thread state
 142 *
 143 * Layout of Child kernel mode stack as setup at the end of this function is
 144 *
 145 * |     ...        |
 146 * |     ...        |
 147 * |    unused      |
 148 * |                |
 149 * ------------------
 150 * |     r25        |   <==== top of Stack (thread.ksp)
 151 * ~                ~
 152 * |    --to--      |   (CALLEE Regs of kernel mode)
 153 * |     r13        |
 154 * ------------------
 155 * |     fp         |
 156 * |    blink       |   @ret_from_fork
 157 * ------------------
 158 * |                |
 159 * ~                ~
 160 * ~                ~
 161 * |                |
 162 * ------------------
 163 * |     r12        |
 164 * ~                ~
 165 * |    --to--      |   (scratch Regs of user mode)
 166 * |     r0         |
 167 * ------------------
 168 * |      SP        |
 169 * |    orig_r0     |
 170 * |    event/ECR   |
 171 * |    user_r25    |
 172 * ------------------  <===== END of PAGE
 173 */
 174int copy_thread(unsigned long clone_flags,
 175                unsigned long usp, unsigned long kthread_arg,
 176                struct task_struct *p)
 177{
 178        struct pt_regs *c_regs;        /* child's pt_regs */
 179        unsigned long *childksp;       /* to unwind out of __switch_to() */
 180        struct callee_regs *c_callee;  /* child's callee regs */
 181        struct callee_regs *parent_callee;  /* paren't callee */
 182        struct pt_regs *regs = current_pt_regs();
 183
 184        /* Mark the specific anchors to begin with (see pic above) */
 185        c_regs = task_pt_regs(p);
 186        childksp = (unsigned long *)c_regs - 2;  /* 2 words for FP/BLINK */
 187        c_callee = ((struct callee_regs *)childksp) - 1;
 188
 189        /*
 190         * __switch_to() uses thread.ksp to start unwinding stack
 191         * For kernel threads we don't need to create callee regs, the
 192         * stack layout nevertheless needs to remain the same.
 193         * Also, since __switch_to anyways unwinds callee regs, we use
 194         * this to populate kernel thread entry-pt/args into callee regs,
 195         * so that ret_from_kernel_thread() becomes simpler.
 196         */
 197        p->thread.ksp = (unsigned long)c_callee;        /* THREAD_KSP */
 198
 199        /* __switch_to expects FP(0), BLINK(return addr) at top */
 200        childksp[0] = 0;                        /* fp */
 201        childksp[1] = (unsigned long)ret_from_fork; /* blink */
 202
 203        if (unlikely(p->flags & PF_KTHREAD)) {
 204                memset(c_regs, 0, sizeof(struct pt_regs));
 205
 206                c_callee->r13 = kthread_arg;
 207                c_callee->r14 = usp;  /* function */
 208
 209                return 0;
 210        }
 211
 212        /*--------- User Task Only --------------*/
 213
 214        /* __switch_to expects FP(0), BLINK(return addr) at top of stack */
 215        childksp[0] = 0;                                /* for POP fp */
 216        childksp[1] = (unsigned long)ret_from_fork;     /* for POP blink */
 217
 218        /* Copy parents pt regs on child's kernel mode stack */
 219        *c_regs = *regs;
 220
 221        if (usp)
 222                c_regs->sp = usp;
 223
 224        c_regs->r0 = 0;         /* fork returns 0 in child */
 225
 226        parent_callee = ((struct callee_regs *)regs) - 1;
 227        *c_callee = *parent_callee;
 228
 229        if (unlikely(clone_flags & CLONE_SETTLS)) {
 230                /*
 231                 * set task's userland tls data ptr from 4th arg
 232                 * clone C-lib call is difft from clone sys-call
 233                 */
 234                task_thread_info(p)->thr_ptr = regs->r3;
 235        } else {
 236                /* Normal fork case: set parent's TLS ptr in child */
 237                task_thread_info(p)->thr_ptr =
 238                task_thread_info(current)->thr_ptr;
 239        }
 240
 241
 242        /*
 243         * setup usermode thread pointer #1:
 244         * when child is picked by scheduler, __switch_to() uses @c_callee to
 245         * populate usermode callee regs: this works (despite being in a kernel
 246         * function) since special return path for child @ret_from_fork()
 247         * ensures those regs are not clobbered all the way to RTIE to usermode
 248         */
 249        c_callee->r25 = task_thread_info(p)->thr_ptr;
 250
 251#ifdef CONFIG_ARC_CURR_IN_REG
 252        /*
 253         * setup usermode thread pointer #2:
 254         * however for this special use of r25 in kernel, __switch_to() sets
 255         * r25 for kernel needs and only in the final return path is usermode
 256         * r25 setup, from pt_regs->user_r25. So set that up as well
 257         */
 258        c_regs->user_r25 = c_callee->r25;
 259#endif
 260
 261        return 0;
 262}
 263
 264/*
 265 * Do necessary setup to start up a new user task
 266 */
 267void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long usp)
 268{
 269        regs->sp = usp;
 270        regs->ret = pc;
 271
 272        /*
 273         * [U]ser Mode bit set
 274         * [L] ZOL loop inhibited to begin with - cleared by a LP insn
 275         * Interrupts enabled
 276         */
 277        regs->status32 = STATUS_U_MASK | STATUS_L_MASK | ISA_INIT_STATUS_BITS;
 278
 279#ifdef CONFIG_EZNPS_MTM_EXT
 280        regs->eflags = 0;
 281#endif
 282
 283        /* bogus seed values for debugging */
 284        regs->lp_start = 0x10;
 285        regs->lp_end = 0x80;
 286}
 287
 288/*
 289 * Some archs flush debug and FPU info here
 290 */
 291void flush_thread(void)
 292{
 293}
 294
 295int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 296{
 297        return 0;
 298}
 299
 300int elf_check_arch(const struct elf32_hdr *x)
 301{
 302        unsigned int eflags;
 303
 304        if (x->e_machine != EM_ARC_INUSE) {
 305                pr_err("ELF not built for %s ISA\n",
 306                        is_isa_arcompact() ? "ARCompact":"ARCv2");
 307                return 0;
 308        }
 309
 310        eflags = x->e_flags;
 311        if ((eflags & EF_ARC_OSABI_MSK) != EF_ARC_OSABI_CURRENT) {
 312                pr_err("ABI mismatch - you need newer toolchain\n");
 313                force_sigsegv(SIGSEGV);
 314                return 0;
 315        }
 316
 317        return 1;
 318}
 319EXPORT_SYMBOL(elf_check_arch);
 320