Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86: split ret_from_fork

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 7076aada 44f4b56b

+68 -86
+1
arch/x86/Kconfig
··· 97 97 select KTIME_SCALAR if X86_32 98 98 select GENERIC_STRNCPY_FROM_USER 99 99 select GENERIC_STRNLEN_USER 100 + select GENERIC_KERNEL_THREAD 100 101 101 102 config INSTRUCTION_DECODER 102 103 def_bool (KPROBES || PERF_EVENTS || UPROBES)
-5
arch/x86/include/asm/processor.h
··· 589 589 } mm_segment_t; 590 590 591 591 592 - /* 593 - * create a kernel thread without removing it from tasklists 594 - */ 595 - extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); 596 - 597 592 /* Free all resources held by a thread. */ 598 593 extern void release_thread(struct task_struct *); 599 594
+10 -5
arch/x86/kernel/entry_32.S
··· 994 994 */ 995 995 .popsection 996 996 997 - ENTRY(kernel_thread_helper) 998 - pushl $0 # fake return address for unwinder 997 + ENTRY(ret_from_kernel_thread) 999 998 CFI_STARTPROC 1000 - movl %edi,%eax 1001 - call *%esi 999 + pushl_cfi %eax 1000 + call schedule_tail 1001 + GET_THREAD_INFO(%ebp) 1002 + popl_cfi %eax 1003 + pushl_cfi $0x0202 # Reset kernel eflags 1004 + popfl_cfi 1005 + movl PT_EBP(%esp),%eax 1006 + call *PT_EBX(%esp) 1002 1007 call do_exit 1003 1008 ud2 # padding for call trace 1004 1009 CFI_ENDPROC 1005 - ENDPROC(kernel_thread_helper) 1010 + ENDPROC(ret_from_kernel_thread) 1006 1011 1007 1012 #ifdef CONFIG_XEN 1008 1013 /* Xen doesn't set %esp to be precisely what the normal sysenter
+11 -16
arch/x86/kernel/entry_64.S
··· 450 450 RESTORE_REST 451 451 452 452 testl $3, CS-ARGOFFSET(%rsp) # from kernel_thread? 453 - jz retint_restore_args 453 + jz 1f 454 454 455 455 testl $_TIF_IA32, TI_flags(%rcx) # 32-bit compat task needs IRET 456 456 jnz int_ret_from_sys_call 457 457 458 458 RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET 459 459 jmp ret_from_sys_call # go to the SYSRET fastpath 460 + 461 + 1: 462 + subq $REST_SKIP, %rsp # move the stack pointer back 463 + CFI_ADJUST_CFA_OFFSET REST_SKIP 464 + movq %rbp, %rdi 465 + call *%rbx 466 + # exit 467 + mov %eax, %edi 468 + call do_exit 469 + ud2 # padding for call trace 460 470 461 471 CFI_ENDPROC 462 472 END(ret_from_fork) ··· 1215 1205 movl %eax,%gs 1216 1206 jmp 2b 1217 1207 .previous 1218 - 1219 - ENTRY(kernel_thread_helper) 1220 - pushq $0 # fake return address 1221 - CFI_STARTPROC 1222 - /* 1223 - * Here we are in the child and the registers are set as they were 1224 - * at kernel_thread() invocation in the parent. 1225 - */ 1226 - call *%rsi 1227 - # exit 1228 - mov %eax, %edi 1229 - call do_exit 1230 - ud2 # padding for call trace 1231 - CFI_ENDPROC 1232 - END(kernel_thread_helper) 1233 1208 1234 1209 /* 1235 1210 * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
-38
arch/x86/kernel/process.c
··· 299 299 } 300 300 301 301 /* 302 - * This gets run with %si containing the 303 - * function to call, and %di containing 304 - * the "args". 305 - */ 306 - extern void kernel_thread_helper(void); 307 - 308 - /* 309 - * Create a kernel thread 310 - */ 311 - int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) 312 - { 313 - struct pt_regs regs; 314 - 315 - memset(&regs, 0, sizeof(regs)); 316 - 317 - regs.si = (unsigned long) fn; 318 - regs.di = (unsigned long) arg; 319 - 320 - #ifdef CONFIG_X86_32 321 - regs.ds = __USER_DS; 322 - regs.es = __USER_DS; 323 - regs.fs = __KERNEL_PERCPU; 324 - regs.gs = __KERNEL_STACK_CANARY; 325 - #else 326 - regs.ss = __KERNEL_DS; 327 - #endif 328 - 329 - regs.orig_ax = -1; 330 - regs.ip = (unsigned long) kernel_thread_helper; 331 - regs.cs = __KERNEL_CS | get_kernel_rpl(); 332 - regs.flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; 333 - 334 - /* Ok, create the new process.. */ 335 - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL); 336 - } 337 - EXPORT_SYMBOL(kernel_thread); 338 - 339 - /* 340 302 * sys_execve() executes a new program. 341 303 */ 342 304 long sys_execve(const char __user *name,
+25 -8
arch/x86/kernel/process_32.c
··· 57 57 #include <asm/switch_to.h> 58 58 59 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 63 * Return saved PC of a blocked thread. ··· 128 127 } 129 128 130 129 int copy_thread(unsigned long clone_flags, unsigned long sp, 131 - unsigned long unused, 130 + unsigned long arg, 132 131 struct task_struct *p, struct pt_regs *regs) 133 132 { 134 - struct pt_regs *childregs; 133 + struct pt_regs *childregs = task_pt_regs(p); 135 134 struct task_struct *tsk; 136 135 int err; 137 - 138 - childregs = task_pt_regs(p); 139 - *childregs = *regs; 140 - childregs->ax = 0; 141 - childregs->sp = sp; 142 136 143 137 p->thread.sp = (unsigned long) childregs; 144 138 p->thread.sp0 = (unsigned long) (childregs+1); 145 139 146 - p->thread.ip = (unsigned long) ret_from_fork; 140 + if (unlikely(!regs)) { 141 + /* kernel thread */ 142 + memset(childregs, 0, sizeof(struct pt_regs)); 143 + p->thread.ip = (unsigned long) ret_from_kernel_thread; 144 + task_user_gs(p) = __KERNEL_STACK_CANARY; 145 + childregs->ds = __USER_DS; 146 + childregs->es = __USER_DS; 147 + childregs->fs = __KERNEL_PERCPU; 148 + childregs->bx = sp; /* function */ 149 + childregs->bp = arg; 150 + childregs->orig_ax = -1; 151 + childregs->cs = __KERNEL_CS | get_kernel_rpl(); 152 + childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; 153 + p->fpu_counter = 0; 154 + p->thread.io_bitmap_ptr = NULL; 155 + memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); 156 + return 0; 157 + } 158 + *childregs = *regs; 159 + childregs->ax = 0; 160 + childregs->sp = sp; 147 161 162 + p->thread.ip = (unsigned long) ret_from_fork; 148 163 task_user_gs(p) = get_user_gs(regs); 149 164 150 165 p->fpu_counter = 0;
+21 -14
arch/x86/kernel/process_64.c
··· 146 146 } 147 147 148 148 int copy_thread(unsigned long clone_flags, unsigned long sp, 149 - unsigned long unused, 149 + unsigned long arg, 150 150 struct task_struct *p, struct pt_regs *regs) 151 151 { 152 152 int err; 153 153 struct pt_regs *childregs; 154 154 struct task_struct *me = current; 155 155 156 - childregs = ((struct pt_regs *) 157 - (THREAD_SIZE + task_stack_page(p))) - 1; 158 - *childregs = *regs; 159 - 160 - childregs->ax = 0; 161 - if (user_mode(regs)) 162 - childregs->sp = sp; 163 - else 164 - childregs->sp = (unsigned long)childregs; 165 - 156 + p->thread.sp0 = (unsigned long)task_stack_page(p) + THREAD_SIZE; 157 + childregs = task_pt_regs(p); 166 158 p->thread.sp = (unsigned long) childregs; 167 - p->thread.sp0 = (unsigned long) (childregs+1); 168 159 p->thread.usersp = me->thread.usersp; 169 - 170 160 set_tsk_thread_flag(p, TIF_FORK); 171 - 172 161 p->fpu_counter = 0; 173 162 p->thread.io_bitmap_ptr = NULL; 174 163 ··· 167 178 p->thread.fs = p->thread.fsindex ? 0 : me->thread.fs; 168 179 savesegment(es, p->thread.es); 169 180 savesegment(ds, p->thread.ds); 181 + memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); 182 + 183 + if (unlikely(!regs)) { 184 + /* kernel thread */ 185 + memset(childregs, 0, sizeof(struct pt_regs)); 186 + childregs->sp = (unsigned long)childregs; 187 + childregs->ss = __KERNEL_DS; 188 + childregs->bx = sp; /* function */ 189 + childregs->bp = arg; 190 + childregs->orig_ax = -1; 191 + childregs->cs = __KERNEL_CS | get_kernel_rpl(); 192 + childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; 193 + return 0; 194 + } 195 + *childregs = *regs; 196 + 197 + childregs->ax = 0; 198 + childregs->sp = sp; 170 199 171 200 err = -ENOMEM; 172 201 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));