Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/sh/kernel/process_32.c
10817 views
1
/*
2
* arch/sh/kernel/process.c
3
*
4
* This file handles the architecture-dependent parts of process handling..
5
*
6
* Copyright (C) 1995 Linus Torvalds
7
*
8
* SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
9
* Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
10
* Copyright (C) 2002 - 2008 Paul Mundt
11
*
12
* This file is subject to the terms and conditions of the GNU General Public
13
* License. See the file "COPYING" in the main directory of this archive
14
* for more details.
15
*/
16
#include <linux/module.h>
17
#include <linux/mm.h>
18
#include <linux/slab.h>
19
#include <linux/elfcore.h>
20
#include <linux/kallsyms.h>
21
#include <linux/fs.h>
22
#include <linux/ftrace.h>
23
#include <linux/hw_breakpoint.h>
24
#include <linux/prefetch.h>
25
#include <asm/uaccess.h>
26
#include <asm/mmu_context.h>
27
#include <asm/system.h>
28
#include <asm/fpu.h>
29
#include <asm/syscalls.h>
30
31
void show_regs(struct pt_regs * regs)
32
{
33
printk("\n");
34
printk("Pid : %d, Comm: \t\t%s\n", task_pid_nr(current), current->comm);
35
printk("CPU : %d \t\t%s (%s %.*s)\n\n",
36
smp_processor_id(), print_tainted(), init_utsname()->release,
37
(int)strcspn(init_utsname()->version, " "),
38
init_utsname()->version);
39
40
print_symbol("PC is at %s\n", instruction_pointer(regs));
41
print_symbol("PR is at %s\n", regs->pr);
42
43
printk("PC : %08lx SP : %08lx SR : %08lx ",
44
regs->pc, regs->regs[15], regs->sr);
45
#ifdef CONFIG_MMU
46
printk("TEA : %08x\n", __raw_readl(MMU_TEA));
47
#else
48
printk("\n");
49
#endif
50
51
printk("R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n",
52
regs->regs[0],regs->regs[1],
53
regs->regs[2],regs->regs[3]);
54
printk("R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n",
55
regs->regs[4],regs->regs[5],
56
regs->regs[6],regs->regs[7]);
57
printk("R8 : %08lx R9 : %08lx R10 : %08lx R11 : %08lx\n",
58
regs->regs[8],regs->regs[9],
59
regs->regs[10],regs->regs[11]);
60
printk("R12 : %08lx R13 : %08lx R14 : %08lx\n",
61
regs->regs[12],regs->regs[13],
62
regs->regs[14]);
63
printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n",
64
regs->mach, regs->macl, regs->gbr, regs->pr);
65
66
show_trace(NULL, (unsigned long *)regs->regs[15], regs);
67
show_code(regs);
68
}
69
70
/*
71
* Create a kernel thread
72
*/
73
ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
74
{
75
do_exit(fn(arg));
76
}
77
78
/* Don't use this in BL=1(cli). Or else, CPU resets! */
79
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
80
{
81
struct pt_regs regs;
82
int pid;
83
84
memset(&regs, 0, sizeof(regs));
85
regs.regs[4] = (unsigned long)arg;
86
regs.regs[5] = (unsigned long)fn;
87
88
regs.pc = (unsigned long)kernel_thread_helper;
89
regs.sr = SR_MD;
90
#if defined(CONFIG_SH_FPU)
91
regs.sr |= SR_FD;
92
#endif
93
94
/* Ok, create the new process.. */
95
pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
96
&regs, 0, NULL, NULL);
97
98
return pid;
99
}
100
EXPORT_SYMBOL(kernel_thread);
101
102
void start_thread(struct pt_regs *regs, unsigned long new_pc,
103
unsigned long new_sp)
104
{
105
regs->pr = 0;
106
regs->sr = SR_FD;
107
regs->pc = new_pc;
108
regs->regs[15] = new_sp;
109
110
free_thread_xstate(current);
111
}
112
EXPORT_SYMBOL(start_thread);
113
114
/*
115
* Free current thread data structures etc..
116
*/
117
void exit_thread(void)
118
{
119
}
120
121
void flush_thread(void)
122
{
123
struct task_struct *tsk = current;
124
125
flush_ptrace_hw_breakpoint(tsk);
126
127
#if defined(CONFIG_SH_FPU)
128
/* Forget lazy FPU state */
129
clear_fpu(tsk, task_pt_regs(tsk));
130
clear_used_math();
131
#endif
132
}
133
134
void release_thread(struct task_struct *dead_task)
135
{
136
/* do nothing */
137
}
138
139
/* Fill in the fpu structure for a core dump.. */
140
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
141
{
142
int fpvalid = 0;
143
144
#if defined(CONFIG_SH_FPU)
145
struct task_struct *tsk = current;
146
147
fpvalid = !!tsk_used_math(tsk);
148
if (fpvalid)
149
fpvalid = !fpregs_get(tsk, NULL, 0,
150
sizeof(struct user_fpu_struct),
151
fpu, NULL);
152
#endif
153
154
return fpvalid;
155
}
156
EXPORT_SYMBOL(dump_fpu);
157
158
/*
159
* This gets called before we allocate a new thread and copy
160
* the current task into it.
161
*/
162
void prepare_to_copy(struct task_struct *tsk)
163
{
164
unlazy_fpu(tsk, task_pt_regs(tsk));
165
}
166
167
asmlinkage void ret_from_fork(void);
168
169
int copy_thread(unsigned long clone_flags, unsigned long usp,
170
unsigned long unused,
171
struct task_struct *p, struct pt_regs *regs)
172
{
173
struct thread_info *ti = task_thread_info(p);
174
struct pt_regs *childregs;
175
176
#if defined(CONFIG_SH_DSP)
177
struct task_struct *tsk = current;
178
179
if (is_dsp_enabled(tsk)) {
180
/* We can use the __save_dsp or just copy the struct:
181
* __save_dsp(p);
182
* p->thread.dsp_status.status |= SR_DSP
183
*/
184
p->thread.dsp_status = tsk->thread.dsp_status;
185
}
186
#endif
187
188
childregs = task_pt_regs(p);
189
*childregs = *regs;
190
191
if (user_mode(regs)) {
192
childregs->regs[15] = usp;
193
ti->addr_limit = USER_DS;
194
} else {
195
childregs->regs[15] = (unsigned long)childregs;
196
ti->addr_limit = KERNEL_DS;
197
ti->status &= ~TS_USEDFPU;
198
p->fpu_counter = 0;
199
}
200
201
if (clone_flags & CLONE_SETTLS)
202
childregs->gbr = childregs->regs[0];
203
204
childregs->regs[0] = 0; /* Set return value for child */
205
206
p->thread.sp = (unsigned long) childregs;
207
p->thread.pc = (unsigned long) ret_from_fork;
208
209
memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
210
211
return 0;
212
}
213
214
/*
215
* switch_to(x,y) should switch tasks from x to y.
216
*
217
*/
218
__notrace_funcgraph struct task_struct *
219
__switch_to(struct task_struct *prev, struct task_struct *next)
220
{
221
struct thread_struct *next_t = &next->thread;
222
223
unlazy_fpu(prev, task_pt_regs(prev));
224
225
/* we're going to use this soon, after a few expensive things */
226
if (next->fpu_counter > 5)
227
prefetch(next_t->xstate);
228
229
#ifdef CONFIG_MMU
230
/*
231
* Restore the kernel mode register
232
* k7 (r7_bank1)
233
*/
234
asm volatile("ldc %0, r7_bank"
235
: /* no output */
236
: "r" (task_thread_info(next)));
237
#endif
238
239
/*
240
* If the task has used fpu the last 5 timeslices, just do a full
241
* restore of the math state immediately to avoid the trap; the
242
* chances of needing FPU soon are obviously high now
243
*/
244
if (next->fpu_counter > 5)
245
__fpu_state_restore();
246
247
return prev;
248
}
249
250
asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
251
unsigned long r6, unsigned long r7,
252
struct pt_regs __regs)
253
{
254
#ifdef CONFIG_MMU
255
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
256
return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL);
257
#else
258
/* fork almost works, enough to trick you into looking elsewhere :-( */
259
return -EINVAL;
260
#endif
261
}
262
263
asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
264
unsigned long parent_tidptr,
265
unsigned long child_tidptr,
266
struct pt_regs __regs)
267
{
268
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
269
if (!newsp)
270
newsp = regs->regs[15];
271
return do_fork(clone_flags, newsp, regs, 0,
272
(int __user *)parent_tidptr,
273
(int __user *)child_tidptr);
274
}
275
276
/*
277
* This is trivial, and on the face of it looks like it
278
* could equally well be done in user mode.
279
*
280
* Not so, for quite unobvious reasons - register pressure.
281
* In user mode vfork() cannot have a stack frame, and if
282
* done by calling the "clone()" system call directly, you
283
* do not have enough call-clobbered registers to hold all
284
* the information you need.
285
*/
286
asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
287
unsigned long r6, unsigned long r7,
288
struct pt_regs __regs)
289
{
290
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
291
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->regs[15], regs,
292
0, NULL, NULL);
293
}
294
295
/*
296
* sys_execve() executes a new program.
297
*/
298
asmlinkage int sys_execve(const char __user *ufilename,
299
const char __user *const __user *uargv,
300
const char __user *const __user *uenvp,
301
unsigned long r7, struct pt_regs __regs)
302
{
303
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
304
int error;
305
char *filename;
306
307
filename = getname(ufilename);
308
error = PTR_ERR(filename);
309
if (IS_ERR(filename))
310
goto out;
311
312
error = do_execve(filename, uargv, uenvp, regs);
313
putname(filename);
314
out:
315
return error;
316
}
317
318
unsigned long get_wchan(struct task_struct *p)
319
{
320
unsigned long pc;
321
322
if (!p || p == current || p->state == TASK_RUNNING)
323
return 0;
324
325
/*
326
* The same comment as on the Alpha applies here, too ...
327
*/
328
pc = thread_saved_pc(p);
329
330
#ifdef CONFIG_FRAME_POINTER
331
if (in_sched_functions(pc)) {
332
unsigned long schedule_frame = (unsigned long)p->thread.sp;
333
return ((unsigned long *)schedule_frame)[21];
334
}
335
#endif
336
337
return pc;
338
}
339
340