diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 23:02:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 23:02:25 -0400 |
commit | 42859eea96ba6beabfb0369a1eeffa3c7d2bd9cb (patch) | |
tree | fa38aeda0d6e7a4c48a882b166b8643594a1ad50 /arch/x86/kernel/process_32.c | |
parent | f59b51fe3d3092c08d7d554ecb40db24011b2ebc (diff) | |
parent | f322220d6159455da2b5a8a596d802c8695fed30 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull generic execve() changes from Al Viro:
"This introduces the generic kernel_thread() and kernel_execve()
functions, and switches x86, arm, alpha, um and s390 over to them."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (26 commits)
s390: convert to generic kernel_execve()
s390: switch to generic kernel_thread()
s390: fold kernel_thread_helper() into ret_from_fork()
s390: fold execve_tail() into start_thread(), convert to generic sys_execve()
um: switch to generic kernel_thread()
x86, um/x86: switch to generic sys_execve and kernel_execve
x86: split ret_from_fork
alpha: introduce ret_from_kernel_execve(), switch to generic kernel_execve()
alpha: switch to generic kernel_thread()
alpha: switch to generic sys_execve()
arm: get rid of execve wrapper, switch to generic execve() implementation
arm: optimized current_pt_regs()
arm: introduce ret_from_kernel_execve(), switch to generic kernel_execve()
arm: split ret_from_fork, simplify kernel_thread() [based on patch by rmk]
generic sys_execve()
generic kernel_execve()
new helper: current_pt_regs()
preparation for generic kernel_thread()
um: kill thread->forking
um: let signal_delivered() do SIGTRAP on singlestepping into handler
...
Diffstat (limited to 'arch/x86/kernel/process_32.c')
-rw-r--r-- | arch/x86/kernel/process_32.c | 37 |
1 files changed, 30 insertions, 7 deletions
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index b9ff83c7135b..44e0bff38e72 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -57,6 +57,7 @@ | |||
57 | #include <asm/switch_to.h> | 57 | #include <asm/switch_to.h> |
58 | 58 | ||
59 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 59 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
60 | asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread"); | ||
60 | 61 | ||
61 | /* | 62 | /* |
62 | * Return saved PC of a blocked thread. | 63 | * Return saved PC of a blocked thread. |
@@ -127,23 +128,39 @@ void release_thread(struct task_struct *dead_task) | |||
127 | } | 128 | } |
128 | 129 | ||
129 | int copy_thread(unsigned long clone_flags, unsigned long sp, | 130 | int copy_thread(unsigned long clone_flags, unsigned long sp, |
130 | unsigned long unused, | 131 | unsigned long arg, |
131 | struct task_struct *p, struct pt_regs *regs) | 132 | struct task_struct *p, struct pt_regs *regs) |
132 | { | 133 | { |
133 | struct pt_regs *childregs; | 134 | struct pt_regs *childregs = task_pt_regs(p); |
134 | struct task_struct *tsk; | 135 | struct task_struct *tsk; |
135 | int err; | 136 | int err; |
136 | 137 | ||
137 | childregs = task_pt_regs(p); | 138 | p->thread.sp = (unsigned long) childregs; |
139 | p->thread.sp0 = (unsigned long) (childregs+1); | ||
140 | |||
141 | if (unlikely(!regs)) { | ||
142 | /* kernel thread */ | ||
143 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
144 | p->thread.ip = (unsigned long) ret_from_kernel_thread; | ||
145 | task_user_gs(p) = __KERNEL_STACK_CANARY; | ||
146 | childregs->ds = __USER_DS; | ||
147 | childregs->es = __USER_DS; | ||
148 | childregs->fs = __KERNEL_PERCPU; | ||
149 | childregs->bx = sp; /* function */ | ||
150 | childregs->bp = arg; | ||
151 | childregs->orig_ax = -1; | ||
152 | childregs->cs = __KERNEL_CS | get_kernel_rpl(); | ||
153 | childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; | ||
154 | p->fpu_counter = 0; | ||
155 | p->thread.io_bitmap_ptr = NULL; | ||
156 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); | ||
157 | return 0; | ||
158 | } | ||
138 | *childregs = *regs; | 159 | *childregs = *regs; |
139 | childregs->ax = 0; | 160 | childregs->ax = 0; |
140 | childregs->sp = sp; | 161 | childregs->sp = sp; |
141 | 162 | ||
142 | p->thread.sp = (unsigned long) childregs; | ||
143 | p->thread.sp0 = (unsigned long) (childregs+1); | ||
144 | |||
145 | p->thread.ip = (unsigned long) ret_from_fork; | 163 | p->thread.ip = (unsigned long) ret_from_fork; |
146 | |||
147 | task_user_gs(p) = get_user_gs(regs); | 164 | task_user_gs(p) = get_user_gs(regs); |
148 | 165 | ||
149 | p->fpu_counter = 0; | 166 | p->fpu_counter = 0; |
@@ -190,6 +207,12 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) | |||
190 | regs->cs = __USER_CS; | 207 | regs->cs = __USER_CS; |
191 | regs->ip = new_ip; | 208 | regs->ip = new_ip; |
192 | regs->sp = new_sp; | 209 | regs->sp = new_sp; |
210 | regs->flags = X86_EFLAGS_IF; | ||
211 | /* | ||
212 | * force it to the iret return path by making it look as if there was | ||
213 | * some work pending. | ||
214 | */ | ||
215 | set_thread_flag(TIF_NOTIFY_RESUME); | ||
193 | } | 216 | } |
194 | EXPORT_SYMBOL_GPL(start_thread); | 217 | EXPORT_SYMBOL_GPL(start_thread); |
195 | 218 | ||