1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * OpenRISC process.c |
4 | * |
5 | * Linux architectural port borrowing liberally from similar works of |
6 | * others. All original copyrights apply as per the original source |
7 | * declaration. |
8 | * |
9 | * Modifications for the OpenRISC architecture: |
10 | * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> |
11 | * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> |
12 | * |
13 | * This file handles the architecture-dependent parts of process handling... |
14 | */ |
15 | |
16 | #define __KERNEL_SYSCALLS__ |
17 | #include <linux/cpu.h> |
18 | #include <linux/errno.h> |
19 | #include <linux/sched.h> |
20 | #include <linux/sched/debug.h> |
21 | #include <linux/sched/task.h> |
22 | #include <linux/sched/task_stack.h> |
23 | #include <linux/kernel.h> |
24 | #include <linux/export.h> |
25 | #include <linux/mm.h> |
26 | #include <linux/stddef.h> |
27 | #include <linux/unistd.h> |
28 | #include <linux/ptrace.h> |
29 | #include <linux/slab.h> |
30 | #include <linux/elfcore.h> |
31 | #include <linux/interrupt.h> |
32 | #include <linux/delay.h> |
33 | #include <linux/init_task.h> |
34 | #include <linux/mqueue.h> |
35 | #include <linux/fs.h> |
36 | #include <linux/reboot.h> |
37 | |
38 | #include <linux/uaccess.h> |
39 | #include <asm/io.h> |
40 | #include <asm/processor.h> |
41 | #include <asm/spr_defs.h> |
42 | #include <asm/switch_to.h> |
43 | |
44 | #include <linux/smp.h> |
45 | |
46 | /* |
47 | * Pointer to Current thread info structure. |
48 | * |
49 | * Used at user space -> kernel transitions. |
50 | */ |
51 | struct thread_info *current_thread_info_set[NR_CPUS] = { &init_thread_info, }; |
52 | |
53 | void machine_restart(char *cmd) |
54 | { |
55 | do_kernel_restart(cmd); |
56 | |
57 | __asm__("l.nop 13" ); |
58 | |
59 | /* Give a grace period for failure to restart of 1s */ |
60 | mdelay(1000); |
61 | |
62 | /* Whoops - the platform was unable to reboot. Tell the user! */ |
63 | pr_emerg("Reboot failed -- System halted\n" ); |
64 | while (1); |
65 | } |
66 | |
67 | /* |
68 | * This is used if pm_power_off has not been set by a power management |
69 | * driver, in this case we can assume we are on a simulator. On |
70 | * OpenRISC simulators l.nop 1 will trigger the simulator exit. |
71 | */ |
72 | static void default_power_off(void) |
73 | { |
74 | __asm__("l.nop 1" ); |
75 | } |
76 | |
77 | /* |
78 | * Similar to machine_power_off, but don't shut off power. Add code |
79 | * here to freeze the system for e.g. post-mortem debug purpose when |
80 | * possible. This halt has nothing to do with the idle halt. |
81 | */ |
82 | void machine_halt(void) |
83 | { |
84 | printk(KERN_INFO "*** MACHINE HALT ***\n" ); |
85 | __asm__("l.nop 1" ); |
86 | } |
87 | |
88 | /* If or when software power-off is implemented, add code here. */ |
89 | void machine_power_off(void) |
90 | { |
91 | printk(KERN_INFO "*** MACHINE POWER OFF ***\n" ); |
92 | if (pm_power_off != NULL) |
93 | pm_power_off(); |
94 | else |
95 | default_power_off(); |
96 | } |
97 | |
98 | /* |
99 | * Send the doze signal to the cpu if available. |
100 | * Make sure, that all interrupts are enabled |
101 | */ |
102 | void arch_cpu_idle(void) |
103 | { |
104 | raw_local_irq_enable(); |
105 | if (mfspr(SPR_UPR) & SPR_UPR_PMP) |
106 | mtspr(SPR_PMR, mfspr(SPR_PMR) | SPR_PMR_DME); |
107 | raw_local_irq_disable(); |
108 | } |
109 | |
110 | void (*pm_power_off)(void) = NULL; |
111 | EXPORT_SYMBOL(pm_power_off); |
112 | |
113 | /* |
114 | * When a process does an "exec", machine state like FPU and debug |
115 | * registers need to be reset. This is a hook function for that. |
116 | * Currently we don't have any such state to reset, so this is empty. |
117 | */ |
118 | void flush_thread(void) |
119 | { |
120 | } |
121 | |
122 | void show_regs(struct pt_regs *regs) |
123 | { |
124 | show_regs_print_info(KERN_DEFAULT); |
125 | /* __PHX__ cleanup this mess */ |
126 | show_registers(regs); |
127 | } |
128 | |
129 | /* |
130 | * Copy the thread-specific (arch specific) info from the current |
131 | * process to the new one p |
132 | */ |
133 | extern asmlinkage void ret_from_fork(void); |
134 | |
135 | /* |
136 | * copy_thread |
137 | * @clone_flags: flags |
138 | * @usp: user stack pointer or fn for kernel thread |
139 | * @arg: arg to fn for kernel thread; always NULL for userspace thread |
140 | * @p: the newly created task |
141 | * @tls: the Thread Local Storage pointer for the new process |
142 | * |
143 | * At the top of a newly initialized kernel stack are two stacked pt_reg |
144 | * structures. The first (topmost) is the userspace context of the thread. |
145 | * The second is the kernelspace context of the thread. |
146 | * |
147 | * A kernel thread will not be returning to userspace, so the topmost pt_regs |
148 | * struct can be uninitialized; it _does_ need to exist, though, because |
149 | * a kernel thread can become a userspace thread by doing a kernel_execve, in |
150 | * which case the topmost context will be initialized and used for 'returning' |
151 | * to userspace. |
152 | * |
153 | * The second pt_reg struct needs to be initialized to 'return' to |
154 | * ret_from_fork. A kernel thread will need to set r20 to the address of |
155 | * a function to call into (with arg in r22); userspace threads need to set |
156 | * r20 to NULL in which case ret_from_fork will just continue a return to |
157 | * userspace. |
158 | * |
159 | * A kernel thread 'fn' may return; this is effectively what happens when |
160 | * kernel_execve is called. In that case, the userspace pt_regs must have |
161 | * been initialized (which kernel_execve takes care of, see start_thread |
162 | * below); ret_from_fork will then continue its execution causing the |
163 | * 'kernel thread' to return to userspace as a userspace thread. |
164 | */ |
165 | |
166 | int |
167 | copy_thread(struct task_struct *p, const struct kernel_clone_args *args) |
168 | { |
169 | unsigned long clone_flags = args->flags; |
170 | unsigned long usp = args->stack; |
171 | unsigned long tls = args->tls; |
172 | struct pt_regs *userregs; |
173 | struct pt_regs *kregs; |
174 | unsigned long sp = (unsigned long)task_stack_page(task: p) + THREAD_SIZE; |
175 | unsigned long top_of_kernel_stack; |
176 | |
177 | top_of_kernel_stack = sp; |
178 | |
179 | /* Locate userspace context on stack... */ |
180 | sp -= STACK_FRAME_OVERHEAD; /* redzone */ |
181 | sp -= sizeof(struct pt_regs); |
182 | userregs = (struct pt_regs *) sp; |
183 | |
184 | /* ...and kernel context */ |
185 | sp -= STACK_FRAME_OVERHEAD; /* redzone */ |
186 | sp -= sizeof(struct pt_regs); |
187 | kregs = (struct pt_regs *)sp; |
188 | |
189 | if (unlikely(args->fn)) { |
190 | memset(kregs, 0, sizeof(struct pt_regs)); |
191 | kregs->gpr[20] = (unsigned long)args->fn; |
192 | kregs->gpr[22] = (unsigned long)args->fn_arg; |
193 | } else { |
194 | *userregs = *current_pt_regs(); |
195 | |
196 | if (usp) |
197 | userregs->sp = usp; |
198 | |
199 | /* |
200 | * For CLONE_SETTLS set "tp" (r10) to the TLS pointer. |
201 | */ |
202 | if (clone_flags & CLONE_SETTLS) |
203 | userregs->gpr[10] = tls; |
204 | |
205 | userregs->gpr[11] = 0; /* Result from fork() */ |
206 | |
207 | kregs->gpr[20] = 0; /* Userspace thread */ |
208 | } |
209 | |
210 | /* |
211 | * _switch wants the kernel stack page in pt_regs->sp so that it |
212 | * can restore it to thread_info->ksp... see _switch for details. |
213 | */ |
214 | kregs->sp = top_of_kernel_stack; |
215 | kregs->gpr[9] = (unsigned long)ret_from_fork; |
216 | |
217 | task_thread_info(p)->ksp = (unsigned long)kregs; |
218 | |
219 | return 0; |
220 | } |
221 | |
222 | /* |
223 | * Set up a thread for executing a new program |
224 | */ |
225 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) |
226 | { |
227 | unsigned long sr = mfspr(SPR_SR) & ~SPR_SR_SM; |
228 | |
229 | memset(regs, 0, sizeof(struct pt_regs)); |
230 | |
231 | regs->pc = pc; |
232 | regs->sr = sr; |
233 | regs->sp = sp; |
234 | } |
235 | |
236 | extern struct thread_info *_switch(struct thread_info *old_ti, |
237 | struct thread_info *new_ti); |
238 | extern int lwa_flag; |
239 | |
240 | struct task_struct *__switch_to(struct task_struct *old, |
241 | struct task_struct *new) |
242 | { |
243 | struct task_struct *last; |
244 | struct thread_info *new_ti, *old_ti; |
245 | unsigned long flags; |
246 | |
247 | local_irq_save(flags); |
248 | |
249 | /* current_set is an array of saved current pointers |
250 | * (one for each cpu). we need them at user->kernel transition, |
251 | * while we save them at kernel->user transition |
252 | */ |
253 | new_ti = new->stack; |
254 | old_ti = old->stack; |
255 | |
256 | lwa_flag = 0; |
257 | |
258 | current_thread_info_set[smp_processor_id()] = new_ti; |
259 | last = (_switch(old_ti, new_ti))->task; |
260 | |
261 | local_irq_restore(flags); |
262 | |
263 | return last; |
264 | } |
265 | |
266 | /* |
267 | * Write out registers in core dump format, as defined by the |
268 | * struct user_regs_struct |
269 | */ |
270 | void dump_elf_thread(elf_greg_t *dest, struct pt_regs* regs) |
271 | { |
272 | dest[0] = 0; /* r0 */ |
273 | memcpy(dest+1, regs->gpr+1, 31*sizeof(unsigned long)); |
274 | dest[32] = regs->pc; |
275 | dest[33] = regs->sr; |
276 | dest[34] = 0; |
277 | dest[35] = 0; |
278 | } |
279 | |
280 | unsigned long __get_wchan(struct task_struct *p) |
281 | { |
282 | /* TODO */ |
283 | |
284 | return 0; |
285 | } |
286 | |