Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
cbf23cf1
Commit
cbf23cf1
authored
Oct 19, 2012
by
Jonas Bonn
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
openrisc: use generic kernel_thread/kernel_execve
Signed-off-by:
Jonas Bonn
<
jonas@southpole.se
>
parent
287ad220
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
68 additions
and
102 deletions
+68
-102
arch/openrisc/Kconfig
arch/openrisc/Kconfig
+2
-0
arch/openrisc/kernel/entry.S
arch/openrisc/kernel/entry.S
+10
-20
arch/openrisc/kernel/process.c
arch/openrisc/kernel/process.c
+56
-82
No files found.
arch/openrisc/Kconfig
View file @
cbf23cf1
...
...
@@ -22,6 +22,8 @@ config OPENRISC
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select MODULES_USE_ELF_RELA
select GENERIC_KERNEL_THREAD
select GENERIC_KERNEL_EXECVE
config MMU
def_bool y
...
...
arch/openrisc/kernel/entry.S
View file @
cbf23cf1
...
...
@@ -894,6 +894,16 @@ ENTRY(ret_from_fork)
l.jal
schedule_tail
l.nop
/
*
Check
if
we
are
a
kernel
thread
*/
l.sfeqi
r20
,
0
l.bf
1
f
l.nop
/
*
...
we
are
a
kernel
thread
so
invoke
the
requested
callback
*/
l.jalr
r20
l.or
r3
,
r22
,
r0
1
:
/
*
_syscall_returns
expect
r11
to
contain
return
value
*/
l.lwz
r11
,
PT_GPR11
(
r1
)
...
...
@@ -915,26 +925,6 @@ ENTRY(ret_from_fork)
l.j
_syscall_return
l.nop
/*
Since
syscalls
don
't save call-clobbered registers, the args to
*
kernel_thread_helper
will
need
to
be
passed
through
callee
-
saved
*
registers
and
copied
to
the
parameter
registers
when
the
thread
*
begins
running
.
*
*
See
arch
/
openrisc
/
kernel
/
process
.
c
:
*
The
args
are
passed
as
follows
:
*
arg1
(
r3
)
:
passed
in
r20
*
arg2
(
r4
)
:
passed
in
r22
*/
ENTRY
(
_kernel_thread_helper
)
l.or
r3
,
r20
,
r0
l.or
r4
,
r22
,
r0
l.movhi
r31
,
hi
(
kernel_thread_helper
)
l.ori
r31
,
r31
,
lo
(
kernel_thread_helper
)
l.jr
r31
l.nop
/*
========================================================
[
switch
]
===
*/
/*
...
...
arch/openrisc/kernel/process.c
View file @
cbf23cf1
...
...
@@ -109,65 +109,82 @@ void release_thread(struct task_struct *dead_task)
*/
extern
asmlinkage
void
ret_from_fork
(
void
);
/*
* copy_thread
* @clone_flags: flags
* @usp: user stack pointer or fn for kernel thread
* @arg: arg to fn for kernel thread; always NULL for userspace thread
* @p: the newly created task
* @regs: CPU context to copy for userspace thread; always NULL for kthread
*
* At the top of a newly initialized kernel stack are two stacked pt_reg
* structures. The first (topmost) is the userspace context of the thread.
* The second is the kernelspace context of the thread.
*
* A kernel thread will not be returning to userspace, so the topmost pt_regs
* struct can be uninitialized; it _does_ need to exist, though, because
* a kernel thread can become a userspace thread by doing a kernel_execve, in
* which case the topmost context will be initialized and used for 'returning'
* to userspace.
*
* The second pt_reg struct needs to be initialized to 'return' to
* ret_from_fork. A kernel thread will need to set r20 to the address of
* a function to call into (with arg in r22); userspace threads need to set
* r20 to NULL in which case ret_from_fork will just continue a return to
* userspace.
*
* A kernel thread 'fn' may return; this is effectively what happens when
* kernel_execve is called. In that case, the userspace pt_regs must have
* been initialized (which kernel_execve takes care of, see start_thread
* below); ret_from_fork will then continue its execution causing the
* 'kernel thread' to return to userspace as a userspace thread.
*/
int
copy_thread
(
unsigned
long
clone_flags
,
unsigned
long
usp
,
unsigned
long
unused
,
struct
task_struct
*
p
,
struct
pt_regs
*
regs
)
unsigned
long
arg
,
struct
task_struct
*
p
,
struct
pt_regs
*
regs
)
{
struct
pt_regs
*
child
regs
;
struct
pt_regs
*
user
regs
;
struct
pt_regs
*
kregs
;
unsigned
long
sp
=
(
unsigned
long
)
task_stack_page
(
p
)
+
THREAD_SIZE
;
struct
thread_info
*
ti
;
unsigned
long
top_of_kernel_stack
;
top_of_kernel_stack
=
sp
;
p
->
set_child_tid
=
p
->
clear_child_tid
=
NULL
;
/* Copy registers */
/* redzone */
sp
-=
STACK_FRAME_OVERHEAD
;
/* Locate userspace context on stack... */
sp
-=
STACK_FRAME_OVERHEAD
;
/* redzone */
sp
-=
sizeof
(
struct
pt_regs
);
childregs
=
(
struct
pt_regs
*
)
sp
;
userregs
=
(
struct
pt_regs
*
)
sp
;
/* Copy parent registers */
*
childregs
=
*
regs
;
/* ...and kernel context */
sp
-=
STACK_FRAME_OVERHEAD
;
/* redzone */
sp
-=
sizeof
(
struct
pt_regs
);
kregs
=
(
struct
pt_regs
*
)
sp
;
if
((
childregs
->
sr
&
SPR_SR_SM
)
==
1
)
{
/* for kernel thread, set `current_thread_info'
* and stackptr in new task
*/
childregs
->
sp
=
(
unsigned
long
)
task_stack_page
(
p
)
+
THREAD_SIZE
;
childregs
->
gpr
[
10
]
=
(
unsigned
long
)
task_thread_info
(
p
);
if
(
unlikely
(
p
->
flags
&
PF_KTHREAD
))
{
memset
(
kregs
,
0
,
sizeof
(
struct
pt_regs
));
kregs
->
gpr
[
20
]
=
usp
;
/* fn, kernel thread */
kregs
->
gpr
[
22
]
=
arg
;
}
else
{
childregs
->
sp
=
usp
;
}
childregs
->
gpr
[
11
]
=
0
;
/* Result from fork() */
*
userregs
=
*
regs
;
/*
* The way this works is that at some point in the future
* some task will call _switch to switch to the new task.
* That will pop off the stack frame created below and start
* the new task running at ret_from_fork. The new task will
* do some house keeping and then return from the fork or clone
* system call, using the stack frame created above.
*/
/* redzone */
sp
-=
STACK_FRAME_OVERHEAD
;
sp
-=
sizeof
(
struct
pt_regs
);
kregs
=
(
struct
pt_regs
*
)
sp
;
userregs
->
sp
=
usp
;
userregs
->
gpr
[
11
]
=
0
;
/* Result from fork() */
ti
=
task_thread_info
(
p
);
ti
->
ksp
=
sp
;
kregs
->
gpr
[
20
]
=
0
;
/* Userspace thread */
}
/*
kregs->sp must store the location of the 'pre-switch' kernel stack
*
pointer... for a newly forked process, this is simply the top of
*
the kernel stack
.
/*
*
_switch wants the kernel stack page in pt_regs->sp so that it
*
can restore it to thread_info->ksp... see _switch for details
.
*/
kregs
->
sp
=
top_of_kernel_stack
;
kregs
->
gpr
[
10
]
=
(
unsigned
long
)
task_thread_info
(
p
);
kregs
->
gpr
[
9
]
=
(
unsigned
long
)
ret_from_fork
;
task_thread_info
(
p
)
->
ksp
=
(
unsigned
long
)
kregs
;
return
0
;
}
...
...
@@ -176,16 +193,14 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
*/
void
start_thread
(
struct
pt_regs
*
regs
,
unsigned
long
pc
,
unsigned
long
sp
)
{
unsigned
long
sr
=
regs
->
sr
&
~
SPR_SR_SM
;
unsigned
long
sr
=
mfspr
(
SPR_SR
)
&
~
SPR_SR_SM
;
set_fs
(
USER_DS
);
memset
(
regs
->
gpr
,
0
,
sizeof
(
regs
->
gpr
));
memset
(
regs
,
0
,
sizeof
(
struct
pt_regs
));
regs
->
pc
=
pc
;
regs
->
sr
=
sr
;
regs
->
sp
=
sp
;
/* printk("start thread, ksp = %lx\n", current_thread_info()->ksp);*/
}
/* Fill in the fpu structure for a core dump. */
...
...
@@ -236,31 +251,6 @@ void dump_elf_thread(elf_greg_t *dest, struct pt_regs* regs)
dest
[
35
]
=
0
;
}
extern
void
_kernel_thread_helper
(
void
);
void
__noreturn
kernel_thread_helper
(
int
(
*
fn
)
(
void
*
),
void
*
arg
)
{
do_exit
(
fn
(
arg
));
}
/*
* Create a kernel thread.
*/
int
kernel_thread
(
int
(
*
fn
)
(
void
*
),
void
*
arg
,
unsigned
long
flags
)
{
struct
pt_regs
regs
;
memset
(
&
regs
,
0
,
sizeof
(
regs
));
regs
.
gpr
[
20
]
=
(
unsigned
long
)
fn
;
regs
.
gpr
[
22
]
=
(
unsigned
long
)
arg
;
regs
.
sr
=
mfspr
(
SPR_SR
);
regs
.
pc
=
(
unsigned
long
)
_kernel_thread_helper
;
return
do_fork
(
flags
|
CLONE_VM
|
CLONE_UNTRACED
,
0
,
&
regs
,
0
,
NULL
,
NULL
);
}
/*
* sys_execve() executes a new program.
*/
...
...
@@ -291,19 +281,3 @@ unsigned long get_wchan(struct task_struct *p)
return
0
;
}
int
kernel_execve
(
const
char
*
filename
,
char
*
const
argv
[],
char
*
const
envp
[])
{
register
long
__res
asm
(
"r11"
)
=
__NR_execve
;
register
long
__a
asm
(
"r3"
)
=
(
long
)(
filename
);
register
long
__b
asm
(
"r4"
)
=
(
long
)(
argv
);
register
long
__c
asm
(
"r5"
)
=
(
long
)(
envp
);
__asm__
volatile
(
"l.sys 1"
:
"=r"
(
__res
),
"=r"
(
__a
),
"=r"
(
__b
),
"=r"
(
__c
)
:
"0"
(
__res
),
"1"
(
__a
),
"2"
(
__b
),
"3"
(
__c
)
:
"r6"
,
"r7"
,
"r8"
,
"r12"
,
"r13"
,
"r15"
,
"r17"
,
"r19"
,
"r21"
,
"r23"
,
"r25"
,
"r27"
,
"r29"
,
"r31"
);
__asm__
volatile
(
"l.nop"
);
return
__res
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment