diff options
| -rw-r--r-- | arch/s390/Kconfig | 1 | ||||
| -rw-r--r-- | arch/s390/include/asm/processor.h | 1 | ||||
| -rw-r--r-- | arch/s390/kernel/process.c | 72 |
3 files changed, 34 insertions, 40 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 107610e01a29..57442393bac7 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
| @@ -125,6 +125,7 @@ config S390 | |||
| 125 | select GENERIC_CLOCKEVENTS | 125 | select GENERIC_CLOCKEVENTS |
| 126 | select KTIME_SCALAR if 32BIT | 126 | select KTIME_SCALAR if 32BIT |
| 127 | select HAVE_ARCH_SECCOMP_FILTER | 127 | select HAVE_ARCH_SECCOMP_FILTER |
| 128 | select GENERIC_KERNEL_THREAD | ||
| 128 | 129 | ||
| 129 | config SCHED_OMIT_FRAME_POINTER | 130 | config SCHED_OMIT_FRAME_POINTER |
| 130 | def_bool y | 131 | def_bool y |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 0bc77619c3a3..da6f5baeee5c 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
| @@ -135,7 +135,6 @@ struct seq_file; | |||
| 135 | 135 | ||
| 136 | /* Free all resources held by a thread. */ | 136 | /* Free all resources held by a thread. */ |
| 137 | extern void release_thread(struct task_struct *); | 137 | extern void release_thread(struct task_struct *); |
| 138 | extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
| 139 | 138 | ||
| 140 | /* | 139 | /* |
| 141 | * Return saved PC of a blocked thread. | 140 | * Return saved PC of a blocked thread. |
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 2868a364ff94..bab088de4569 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
| @@ -98,25 +98,6 @@ void cpu_idle(void) | |||
| 98 | 98 | ||
| 99 | extern void __kprobes kernel_thread_starter(void); | 99 | extern void __kprobes kernel_thread_starter(void); |
| 100 | 100 | ||
| 101 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
| 102 | { | ||
| 103 | struct pt_regs regs; | ||
| 104 | |||
| 105 | memset(®s, 0, sizeof(regs)); | ||
| 106 | regs.psw.mask = psw_kernel_bits | | ||
| 107 | PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK; | ||
| 108 | regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE; | ||
| 109 | regs.gprs[9] = (unsigned long) fn; | ||
| 110 | regs.gprs[10] = (unsigned long) arg; | ||
| 111 | regs.gprs[11] = (unsigned long) do_exit; | ||
| 112 | regs.orig_gpr2 = -1; | ||
| 113 | |||
| 114 | /* Ok, create the new process.. */ | ||
| 115 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, | ||
| 116 | 0, ®s, 0, NULL, NULL); | ||
| 117 | } | ||
| 118 | EXPORT_SYMBOL(kernel_thread); | ||
| 119 | |||
| 120 | /* | 101 | /* |
| 121 | * Free current thread data structures etc.. | 102 | * Free current thread data structures etc.. |
| 122 | */ | 103 | */ |
| @@ -133,7 +114,7 @@ void release_thread(struct task_struct *dead_task) | |||
| 133 | } | 114 | } |
| 134 | 115 | ||
| 135 | int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | 116 | int copy_thread(unsigned long clone_flags, unsigned long new_stackp, |
| 136 | unsigned long unused, | 117 | unsigned long arg, |
| 137 | struct task_struct *p, struct pt_regs *regs) | 118 | struct task_struct *p, struct pt_regs *regs) |
| 138 | { | 119 | { |
| 139 | struct thread_info *ti; | 120 | struct thread_info *ti; |
| @@ -145,20 +126,44 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | |||
| 145 | 126 | ||
| 146 | frame = container_of(task_pt_regs(p), struct fake_frame, childregs); | 127 | frame = container_of(task_pt_regs(p), struct fake_frame, childregs); |
| 147 | p->thread.ksp = (unsigned long) frame; | 128 | p->thread.ksp = (unsigned long) frame; |
| 148 | /* Store access registers to kernel stack of new process. */ | 129 | /* Save access registers to new thread structure. */ |
| 149 | frame->childregs = *regs; | 130 | save_access_regs(&p->thread.acrs[0]); |
| 150 | frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */ | 131 | /* start new process with ar4 pointing to the correct address space */ |
| 151 | frame->childregs.gprs[15] = new_stackp; | 132 | p->thread.mm_segment = get_fs(); |
| 152 | frame->sf.back_chain = 0; | 133 | /* Don't copy debug registers */ |
| 134 | memset(&p->thread.per_user, 0, sizeof(p->thread.per_user)); | ||
| 135 | memset(&p->thread.per_event, 0, sizeof(p->thread.per_event)); | ||
| 136 | clear_tsk_thread_flag(p, TIF_SINGLE_STEP); | ||
| 137 | clear_tsk_thread_flag(p, TIF_PER_TRAP); | ||
| 138 | /* Initialize per thread user and system timer values */ | ||
| 139 | ti = task_thread_info(p); | ||
| 140 | ti->user_timer = 0; | ||
| 141 | ti->system_timer = 0; | ||
| 153 | 142 | ||
| 143 | frame->sf.back_chain = 0; | ||
| 154 | /* new return point is ret_from_fork */ | 144 | /* new return point is ret_from_fork */ |
| 155 | frame->sf.gprs[8] = (unsigned long) ret_from_fork; | 145 | frame->sf.gprs[8] = (unsigned long) ret_from_fork; |
| 156 | |||
| 157 | /* fake return stack for resume(), don't go back to schedule */ | 146 | /* fake return stack for resume(), don't go back to schedule */ |
| 158 | frame->sf.gprs[9] = (unsigned long) frame; | 147 | frame->sf.gprs[9] = (unsigned long) frame; |
| 159 | 148 | ||
| 160 | /* Save access registers to new thread structure. */ | 149 | /* Store access registers to kernel stack of new process. */ |
| 161 | save_access_regs(&p->thread.acrs[0]); | 150 | if (unlikely(!regs)) { |
| 151 | /* kernel thread */ | ||
| 152 | memset(&frame->childregs, 0, sizeof(struct pt_regs)); | ||
| 153 | frame->childregs.psw.mask = psw_kernel_bits | PSW_MASK_DAT | | ||
| 154 | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK; | ||
| 155 | frame->childregs.psw.addr = PSW_ADDR_AMODE | | ||
| 156 | (unsigned long) kernel_thread_starter; | ||
| 157 | frame->childregs.gprs[9] = new_stackp; /* function */ | ||
| 158 | frame->childregs.gprs[10] = arg; | ||
| 159 | frame->childregs.gprs[11] = (unsigned long) do_exit; | ||
| 160 | frame->childregs.orig_gpr2 = -1; | ||
| 161 | |||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | frame->childregs = *regs; | ||
| 165 | frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */ | ||
| 166 | frame->childregs.gprs[15] = new_stackp; | ||
| 162 | 167 | ||
| 163 | #ifndef CONFIG_64BIT | 168 | #ifndef CONFIG_64BIT |
| 164 | /* | 169 | /* |
| @@ -184,17 +189,6 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | |||
| 184 | } | 189 | } |
| 185 | } | 190 | } |
| 186 | #endif /* CONFIG_64BIT */ | 191 | #endif /* CONFIG_64BIT */ |
| 187 | /* start new process with ar4 pointing to the correct address space */ | ||
| 188 | p->thread.mm_segment = get_fs(); | ||
| 189 | /* Don't copy debug registers */ | ||
| 190 | memset(&p->thread.per_user, 0, sizeof(p->thread.per_user)); | ||
| 191 | memset(&p->thread.per_event, 0, sizeof(p->thread.per_event)); | ||
| 192 | clear_tsk_thread_flag(p, TIF_SINGLE_STEP); | ||
| 193 | clear_tsk_thread_flag(p, TIF_PER_TRAP); | ||
| 194 | /* Initialize per thread user and system timer values */ | ||
| 195 | ti = task_thread_info(p); | ||
| 196 | ti->user_timer = 0; | ||
| 197 | ti->system_timer = 0; | ||
| 198 | return 0; | 192 | return 0; |
| 199 | } | 193 | } |
| 200 | 194 | ||
