aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-09 23:02:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-09 23:02:25 -0400
commit42859eea96ba6beabfb0369a1eeffa3c7d2bd9cb (patch)
treefa38aeda0d6e7a4c48a882b166b8643594a1ad50 /arch/s390/kernel
parentf59b51fe3d3092c08d7d554ecb40db24011b2ebc (diff)
parentf322220d6159455da2b5a8a596d802c8695fed30 (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/s390/kernel')
-rw-r--r--arch/s390/kernel/compat_linux.c26
-rw-r--r--arch/s390/kernel/compat_linux.h2
-rw-r--r--arch/s390/kernel/compat_wrapper.S2
-rw-r--r--arch/s390/kernel/entry.S51
-rw-r--r--arch/s390/kernel/entry.h3
-rw-r--r--arch/s390/kernel/entry64.S50
-rw-r--r--arch/s390/kernel/process.c107
7 files changed, 75 insertions, 166 deletions
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 189963c90c6e..65cca95843e1 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -432,32 +432,6 @@ sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
432 return ret; 432 return ret;
433} 433}
434 434
435/*
436 * sys32_execve() executes a new program after the asm stub has set
437 * things up for us. This should basically do what I want it to.
438 */
439asmlinkage long sys32_execve(const char __user *name, compat_uptr_t __user *argv,
440 compat_uptr_t __user *envp)
441{
442 struct pt_regs *regs = task_pt_regs(current);
443 char *filename;
444 long rc;
445
446 filename = getname(name);
447 rc = PTR_ERR(filename);
448 if (IS_ERR(filename))
449 return rc;
450 rc = compat_do_execve(filename, argv, envp, regs);
451 if (rc)
452 goto out;
453 current->thread.fp_regs.fpc=0;
454 asm volatile("sfpc %0,0" : : "d" (0));
455 rc = regs->gprs[2];
456out:
457 putname(filename);
458 return rc;
459}
460
461asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf, 435asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
462 size_t count, u32 poshi, u32 poslo) 436 size_t count, u32 poshi, u32 poslo)
463{ 437{
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 90887bd98cf0..d4d0239970ac 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -125,8 +125,6 @@ long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
125 compat_sigset_t __user *oset, size_t sigsetsize); 125 compat_sigset_t __user *oset, size_t sigsetsize);
126long sys32_rt_sigpending(compat_sigset_t __user *set, size_t sigsetsize); 126long sys32_rt_sigpending(compat_sigset_t __user *set, size_t sigsetsize);
127long sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo); 127long sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo);
128long sys32_execve(const char __user *name, compat_uptr_t __user *argv,
129 compat_uptr_t __user *envp);
130long sys32_init_module(void __user *umod, unsigned long len, 128long sys32_init_module(void __user *umod, unsigned long len,
131 const char __user *uargs); 129 const char __user *uargs);
132long sys32_delete_module(const char __user *name_user, unsigned int flags); 130long sys32_delete_module(const char __user *name_user, unsigned int flags);
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 3afba804fe97..ad79b846535c 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -1576,7 +1576,7 @@ ENTRY(sys32_execve_wrapper)
1576 llgtr %r2,%r2 # char * 1576 llgtr %r2,%r2 # char *
1577 llgtr %r3,%r3 # compat_uptr_t * 1577 llgtr %r3,%r3 # compat_uptr_t *
1578 llgtr %r4,%r4 # compat_uptr_t * 1578 llgtr %r4,%r4 # compat_uptr_t *
1579 jg sys32_execve # branch to system call 1579 jg compat_sys_execve # branch to system call
1580 1580
1581ENTRY(sys_fanotify_init_wrapper) 1581ENTRY(sys_fanotify_init_wrapper)
1582 llgfr %r2,%r2 # unsigned int 1582 llgfr %r2,%r2 # unsigned int
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 870bad6d56fc..ef46f66bc0d6 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -331,45 +331,38 @@ ENTRY(ret_from_fork)
331 l %r12,__LC_THREAD_INFO 331 l %r12,__LC_THREAD_INFO
332 l %r13,__LC_SVC_NEW_PSW+4 332 l %r13,__LC_SVC_NEW_PSW+4
333 tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? 333 tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ?
334 jo 0f 334 je 1f
335 st %r15,__PT_R15(%r11) # store stack pointer for new kthread 335 l %r1,BASED(.Lschedule_tail)
3360: l %r1,BASED(.Lschedule_tail)
337 basr %r14,%r1 # call schedule_tail 336 basr %r14,%r1 # call schedule_tail
338 TRACE_IRQS_ON 337 TRACE_IRQS_ON
339 ssm __LC_SVC_NEW_PSW # reenable interrupts 338 ssm __LC_SVC_NEW_PSW # reenable interrupts
340 j sysc_tracenogo 339 j sysc_tracenogo
341 340
3411: # it's a kernel thread
342 st %r15,__PT_R15(%r11) # store stack pointer for new kthread
343 l %r1,BASED(.Lschedule_tail)
344 basr %r14,%r1 # call schedule_tail
345 TRACE_IRQS_ON
346 ssm __LC_SVC_NEW_PSW # reenable interrupts
347 lm %r9,%r11,__PT_R9(%r11) # load gprs
348ENTRY(kernel_thread_starter)
349 la %r2,0(%r10)
350 basr %r14,%r9
351 la %r2,0
352 br %r11 # do_exit
353
342# 354#
343# kernel_execve function needs to deal with pt_regs that is not 355# kernel_execve function needs to deal with pt_regs that is not
344# at the usual place 356# at the usual place
345# 357#
346ENTRY(kernel_execve) 358ENTRY(ret_from_kernel_execve)
347 stm %r12,%r15,48(%r15) 359 ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
348 lr %r14,%r15 360 lr %r15,%r2
349 l %r13,__LC_SVC_NEW_PSW+4 361 lr %r11,%r2
350 ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) 362 ahi %r15,-STACK_FRAME_OVERHEAD
351 st %r14,__SF_BACKCHAIN(%r15)
352 la %r12,STACK_FRAME_OVERHEAD(%r15)
353 xc 0(__PT_SIZE,%r12),0(%r12)
354 l %r1,BASED(.Ldo_execve)
355 lr %r5,%r12
356 basr %r14,%r1 # call do_execve
357 ltr %r2,%r2
358 je 0f
359 ahi %r15,(STACK_FRAME_OVERHEAD + __PT_SIZE)
360 lm %r12,%r15,48(%r15)
361 br %r14
362 # execve succeeded.
3630: ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
364 l %r15,__LC_KERNEL_STACK # load ksp
365 ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
366 la %r11,STACK_FRAME_OVERHEAD(%r15)
367 mvc 0(__PT_SIZE,%r11),0(%r12) # copy pt_regs
368 l %r12,__LC_THREAD_INFO
369 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) 363 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
364 l %r12,__LC_THREAD_INFO
370 ssm __LC_SVC_NEW_PSW # reenable interrupts 365 ssm __LC_SVC_NEW_PSW # reenable interrupts
371 l %r1,BASED(.Lexecve_tail)
372 basr %r14,%r1 # call execve_tail
373 j sysc_return 366 j sysc_return
374 367
375/* 368/*
@@ -931,8 +924,6 @@ cleanup_idle_wait:
931.Ldo_signal: .long do_signal 924.Ldo_signal: .long do_signal
932.Ldo_notify_resume: .long do_notify_resume 925.Ldo_notify_resume: .long do_notify_resume
933.Ldo_per_trap: .long do_per_trap 926.Ldo_per_trap: .long do_per_trap
934.Ldo_execve: .long do_execve
935.Lexecve_tail: .long execve_tail
936.Ljump_table: .long pgm_check_table 927.Ljump_table: .long pgm_check_table
937.Lschedule: .long schedule 928.Lschedule: .long schedule
938#ifdef CONFIG_PREEMPT 929#ifdef CONFIG_PREEMPT
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index a5f4dc42a5db..d0d3f69a7346 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -58,9 +58,6 @@ long sys_fork(void);
58long sys_clone(unsigned long newsp, unsigned long clone_flags, 58long sys_clone(unsigned long newsp, unsigned long clone_flags,
59 int __user *parent_tidptr, int __user *child_tidptr); 59 int __user *parent_tidptr, int __user *child_tidptr);
60long sys_vfork(void); 60long sys_vfork(void);
61void execve_tail(void);
62long sys_execve(const char __user *name, const char __user *const __user *argv,
63 const char __user *const __user *envp);
64long sys_sigsuspend(int history0, int history1, old_sigset_t mask); 61long sys_sigsuspend(int history0, int history1, old_sigset_t mask);
65long sys_sigaction(int sig, const struct old_sigaction __user *act, 62long sys_sigaction(int sig, const struct old_sigaction __user *act,
66 struct old_sigaction __user *oact); 63 struct old_sigaction __user *oact);
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 7549985402f7..f9761f806c9e 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -353,41 +353,31 @@ ENTRY(ret_from_fork)
353 la %r11,STACK_FRAME_OVERHEAD(%r15) 353 la %r11,STACK_FRAME_OVERHEAD(%r15)
354 lg %r12,__LC_THREAD_INFO 354 lg %r12,__LC_THREAD_INFO
355 tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? 355 tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ?
356 jo 0f 356 je 1f
357 stg %r15,__PT_R15(%r11) # store stack pointer for new kthread 357 brasl %r14,schedule_tail
3580: brasl %r14,schedule_tail
359 TRACE_IRQS_ON 358 TRACE_IRQS_ON
360 ssm __LC_SVC_NEW_PSW # reenable interrupts 359 ssm __LC_SVC_NEW_PSW # reenable interrupts
361 j sysc_tracenogo 360 j sysc_tracenogo
362 3611: # it's a kernel thread
363# 362 stg %r15,__PT_R15(%r11) # store stack pointer for new kthread
364# kernel_execve function needs to deal with pt_regs that is not 363 brasl %r14,schedule_tail
365# at the usual place 364 TRACE_IRQS_ON
366# 365 ssm __LC_SVC_NEW_PSW # reenable interrupts
367ENTRY(kernel_execve) 366 lmg %r9,%r11,__PT_R9(%r11) # load gprs
368 stmg %r12,%r15,96(%r15) 367ENTRY(kernel_thread_starter)
369 lgr %r14,%r15 368 la %r2,0(%r10)
370 aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) 369 basr %r14,%r9
371 stg %r14,__SF_BACKCHAIN(%r15) 370 la %r2,0
372 la %r12,STACK_FRAME_OVERHEAD(%r15) 371 br %r11 # do_exit
373 xc 0(__PT_SIZE,%r12),0(%r12) 372
374 lgr %r5,%r12 373ENTRY(ret_from_kernel_execve)
375 brasl %r14,do_execve 374 ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
376 ltgfr %r2,%r2 375 lgr %r15,%r2
377 je 0f 376 lgr %r11,%r2
378 aghi %r15,(STACK_FRAME_OVERHEAD + __PT_SIZE) 377 aghi %r15,-STACK_FRAME_OVERHEAD
379 lmg %r12,%r15,96(%r15)
380 br %r14
381 # execve succeeded.
3820: ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
383 lg %r15,__LC_KERNEL_STACK # load ksp
384 aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
385 la %r11,STACK_FRAME_OVERHEAD(%r15)
386 mvc 0(__PT_SIZE,%r11),0(%r12) # copy pt_regs
387 lg %r12,__LC_THREAD_INFO
388 xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) 378 xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
379 lg %r12,__LC_THREAD_INFO
389 ssm __LC_SVC_NEW_PSW # reenable interrupts 380 ssm __LC_SVC_NEW_PSW # reenable interrupts
390 brasl %r14,execve_tail
391 j sysc_return 381 j sysc_return
392 382
393/* 383/*
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 5024be27df44..cd31ad457a9b 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -100,35 +100,6 @@ void cpu_idle(void)
100 100
101extern void __kprobes kernel_thread_starter(void); 101extern void __kprobes kernel_thread_starter(void);
102 102
103asm(
104 ".section .kprobes.text, \"ax\"\n"
105 ".global kernel_thread_starter\n"
106 "kernel_thread_starter:\n"
107 " la 2,0(10)\n"
108 " basr 14,9\n"
109 " la 2,0\n"
110 " br 11\n"
111 ".previous\n");
112
113int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
114{
115 struct pt_regs regs;
116
117 memset(&regs, 0, sizeof(regs));
118 regs.psw.mask = psw_kernel_bits |
119 PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
120 regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
121 regs.gprs[9] = (unsigned long) fn;
122 regs.gprs[10] = (unsigned long) arg;
123 regs.gprs[11] = (unsigned long) do_exit;
124 regs.orig_gpr2 = -1;
125
126 /* Ok, create the new process.. */
127 return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
128 0, &regs, 0, NULL, NULL);
129}
130EXPORT_SYMBOL(kernel_thread);
131
132/* 103/*
133 * Free current thread data structures etc.. 104 * Free current thread data structures etc..
134 */ 105 */
@@ -146,7 +117,7 @@ void release_thread(struct task_struct *dead_task)
146} 117}
147 118
148int copy_thread(unsigned long clone_flags, unsigned long new_stackp, 119int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
149 unsigned long unused, 120 unsigned long arg,
150 struct task_struct *p, struct pt_regs *regs) 121 struct task_struct *p, struct pt_regs *regs)
151{ 122{
152 struct thread_info *ti; 123 struct thread_info *ti;
@@ -158,20 +129,44 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
158 129
159 frame = container_of(task_pt_regs(p), struct fake_frame, childregs); 130 frame = container_of(task_pt_regs(p), struct fake_frame, childregs);
160 p->thread.ksp = (unsigned long) frame; 131 p->thread.ksp = (unsigned long) frame;
161 /* Store access registers to kernel stack of new process. */ 132 /* Save access registers to new thread structure. */
162 frame->childregs = *regs; 133 save_access_regs(&p->thread.acrs[0]);
163 frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */ 134 /* start new process with ar4 pointing to the correct address space */
164 frame->childregs.gprs[15] = new_stackp; 135 p->thread.mm_segment = get_fs();
165 frame->sf.back_chain = 0; 136 /* Don't copy debug registers */
137 memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
138 memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
139 clear_tsk_thread_flag(p, TIF_SINGLE_STEP);
140 clear_tsk_thread_flag(p, TIF_PER_TRAP);
141 /* Initialize per thread user and system timer values */
142 ti = task_thread_info(p);
143 ti->user_timer = 0;
144 ti->system_timer = 0;
166 145
146 frame->sf.back_chain = 0;
167 /* new return point is ret_from_fork */ 147 /* new return point is ret_from_fork */
168 frame->sf.gprs[8] = (unsigned long) ret_from_fork; 148 frame->sf.gprs[8] = (unsigned long) ret_from_fork;
169
170 /* fake return stack for resume(), don't go back to schedule */ 149 /* fake return stack for resume(), don't go back to schedule */
171 frame->sf.gprs[9] = (unsigned long) frame; 150 frame->sf.gprs[9] = (unsigned long) frame;
172 151
173 /* Save access registers to new thread structure. */ 152 /* Store access registers to kernel stack of new process. */
174 save_access_regs(&p->thread.acrs[0]); 153 if (unlikely(!regs)) {
154 /* kernel thread */
155 memset(&frame->childregs, 0, sizeof(struct pt_regs));
156 frame->childregs.psw.mask = psw_kernel_bits | PSW_MASK_DAT |
157 PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
158 frame->childregs.psw.addr = PSW_ADDR_AMODE |
159 (unsigned long) kernel_thread_starter;
160 frame->childregs.gprs[9] = new_stackp; /* function */
161 frame->childregs.gprs[10] = arg;
162 frame->childregs.gprs[11] = (unsigned long) do_exit;
163 frame->childregs.orig_gpr2 = -1;
164
165 return 0;
166 }
167 frame->childregs = *regs;
168 frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */
169 frame->childregs.gprs[15] = new_stackp;
175 170
176 /* Don't copy runtime instrumentation info */ 171 /* Don't copy runtime instrumentation info */
177 p->thread.ri_cb = NULL; 172 p->thread.ri_cb = NULL;
@@ -202,17 +197,6 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
202 } 197 }
203 } 198 }
204#endif /* CONFIG_64BIT */ 199#endif /* CONFIG_64BIT */
205 /* start new process with ar4 pointing to the correct address space */
206 p->thread.mm_segment = get_fs();
207 /* Don't copy debug registers */
208 memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
209 memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
210 clear_tsk_thread_flag(p, TIF_SINGLE_STEP);
211 clear_tsk_thread_flag(p, TIF_PER_TRAP);
212 /* Initialize per thread user and system timer values */
213 ti = task_thread_info(p);
214 ti->user_timer = 0;
215 ti->system_timer = 0;
216 return 0; 200 return 0;
217} 201}
218 202
@@ -258,31 +242,6 @@ asmlinkage void execve_tail(void)
258} 242}
259 243
260/* 244/*
261 * sys_execve() executes a new program.
262 */
263SYSCALL_DEFINE3(execve, const char __user *, name,
264 const char __user *const __user *, argv,
265 const char __user *const __user *, envp)
266{
267 struct pt_regs *regs = task_pt_regs(current);
268 char *filename;
269 long rc;
270
271 filename = getname(name);
272 rc = PTR_ERR(filename);
273 if (IS_ERR(filename))
274 return rc;
275 rc = do_execve(filename, argv, envp, regs);
276 if (rc)
277 goto out;
278 execve_tail();
279 rc = regs->gprs[2];
280out:
281 putname(filename);
282 return rc;
283}
284
285/*
286 * fill in the FPU structure for a core dump. 245 * fill in the FPU structure for a core dump.
287 */ 246 */
288int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs) 247int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)