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