~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/hexagon/kernel/process.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Process creation support for Hexagon
  4  *
  5  * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
  6  */
  7 
  8 #include <linux/cpu.h>
  9 #include <linux/sched.h>
 10 #include <linux/sched/debug.h>
 11 #include <linux/sched/task.h>
 12 #include <linux/sched/task_stack.h>
 13 #include <linux/types.h>
 14 #include <linux/module.h>
 15 #include <linux/tick.h>
 16 #include <linux/uaccess.h>
 17 #include <linux/slab.h>
 18 #include <linux/resume_user_mode.h>
 19 
 20 /*
 21  * Program thread launch.  Often defined as a macro in processor.h,
 22  * but we're shooting for a small footprint and it's not an inner-loop
 23  * performance-critical operation.
 24  *
 25  * The Hexagon ABI specifies that R28 is zero'ed before program launch,
 26  * so that gets automatically done here.  If we ever stop doing that here,
 27  * we'll probably want to define the ELF_PLAT_INIT macro.
 28  */
 29 void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp)
 30 {
 31         /* We want to zero all data-containing registers. Is this overkill? */
 32         memset(regs, 0, sizeof(*regs));
 33         /* We might want to also zero all Processor registers here */
 34         pt_set_usermode(regs);
 35         pt_set_elr(regs, pc);
 36         pt_set_rte_sp(regs, sp);
 37 }
 38 
 39 /*
 40  *  Spin, or better still, do a hardware or VM wait instruction
 41  *  If hardware or VM offer wait termination even though interrupts
 42  *  are disabled.
 43  */
 44 void arch_cpu_idle(void)
 45 {
 46         __vmwait();
 47         /*  interrupts wake us up, but irqs are still disabled */
 48 }
 49 
 50 /*
 51  * Copy architecture-specific thread state
 52  */
 53 int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
 54 {
 55         unsigned long clone_flags = args->flags;
 56         unsigned long usp = args->stack;
 57         unsigned long tls = args->tls;
 58         struct thread_info *ti = task_thread_info(p);
 59         struct hexagon_switch_stack *ss;
 60         struct pt_regs *childregs;
 61         asmlinkage void ret_from_fork(void);
 62 
 63         childregs = (struct pt_regs *) (((unsigned long) ti + THREAD_SIZE) -
 64                                         sizeof(*childregs));
 65 
 66         ti->regs = childregs;
 67 
 68         /*
 69          * Establish kernel stack pointer and initial PC for new thread
 70          * Note that unlike the usual situation, we do not copy the
 71          * parent's callee-saved here; those are in pt_regs and whatever
 72          * we leave here will be overridden on return to userland.
 73          */
 74         ss = (struct hexagon_switch_stack *) ((unsigned long) childregs -
 75                                                     sizeof(*ss));
 76         ss->lr = (unsigned long)ret_from_fork;
 77         p->thread.switch_sp = ss;
 78         if (unlikely(args->fn)) {
 79                 memset(childregs, 0, sizeof(struct pt_regs));
 80                 /* r24 <- fn, r25 <- arg */
 81                 ss->r24 = (unsigned long)args->fn;
 82                 ss->r25 = (unsigned long)args->fn_arg;
 83                 pt_set_kmode(childregs);
 84                 return 0;
 85         }
 86         memcpy(childregs, current_pt_regs(), sizeof(*childregs));
 87         ss->r2524 = 0;
 88 
 89         if (usp)
 90                 pt_set_rte_sp(childregs, usp);
 91 
 92         /* Child sees zero return value */
 93         childregs->r00 = 0;
 94 
 95         /*
 96          * The clone syscall has the C signature:
 97          * int [r0] clone(int flags [r0],
 98          *           void *child_frame [r1],
 99          *           void *parent_tid [r2],
100          *           void *child_tid [r3],
101          *           void *thread_control_block [r4]);
102          * ugp is used to provide TLS support.
103          */
104         if (clone_flags & CLONE_SETTLS)
105                 childregs->ugp = tls;
106 
107         /*
108          * Parent sees new pid -- not necessary, not even possible at
109          * this point in the fork process
110          */
111 
112         return 0;
113 }
114 
115 /*
116  * Some archs flush debug and FPU info here
117  */
118 void flush_thread(void)
119 {
120 }
121 
122 /*
123  * The "wait channel" terminology is archaic, but what we want
124  * is an identification of the point at which the scheduler
125  * was invoked by a blocked thread.
126  */
127 unsigned long __get_wchan(struct task_struct *p)
128 {
129         unsigned long fp, pc;
130         unsigned long stack_page;
131         int count = 0;
132 
133         stack_page = (unsigned long)task_stack_page(p);
134         fp = ((struct hexagon_switch_stack *)p->thread.switch_sp)->fp;
135         do {
136                 if (fp < (stack_page + sizeof(struct thread_info)) ||
137                         fp >= (THREAD_SIZE - 8 + stack_page))
138                         return 0;
139                 pc = ((unsigned long *)fp)[1];
140                 if (!in_sched_functions(pc))
141                         return pc;
142                 fp = *(unsigned long *) fp;
143         } while (count++ < 16);
144 
145         return 0;
146 }
147 
148 /*
149  * Called on the exit path of event entry; see vm_entry.S
150  *
151  * Interrupts will already be disabled.
152  *
153  * Returns 0 if there's no need to re-check for more work.
154  */
155 
156 int do_work_pending(struct pt_regs *regs, u32 thread_info_flags);
157 int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
158 {
159         if (!(thread_info_flags & _TIF_WORK_MASK)) {
160                 return 0;
161         }  /* shortcut -- no work to be done */
162 
163         local_irq_enable();
164 
165         if (thread_info_flags & _TIF_NEED_RESCHED) {
166                 schedule();
167                 return 1;
168         }
169 
170         if (thread_info_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) {
171                 do_signal(regs);
172                 return 1;
173         }
174 
175         if (thread_info_flags & _TIF_NOTIFY_RESUME) {
176                 resume_user_mode_work(regs);
177                 return 1;
178         }
179 
180         /* Should not even reach here */
181         panic("%s: bad thread_info flags 0x%08x\n", __func__,
182                 thread_info_flags);
183 }
184 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php