diff options
Diffstat (limited to 'arch/s390/kernel/process.c')
-rw-r--r-- | arch/s390/kernel/process.c | 107 |
1 files changed, 33 insertions, 74 deletions
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 | ||
101 | extern void __kprobes kernel_thread_starter(void); | 101 | extern void __kprobes kernel_thread_starter(void); |
102 | 102 | ||
103 | asm( | ||
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 | |||
113 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
114 | { | ||
115 | struct pt_regs regs; | ||
116 | |||
117 | memset(®s, 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, ®s, 0, NULL, NULL); | ||
129 | } | ||
130 | EXPORT_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 | ||
148 | int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | 119 | int 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 | */ | ||
263 | SYSCALL_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]; | ||
280 | out: | ||
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 | */ |
288 | int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs) | 247 | int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs) |