Loading arch/x86/include/asm/syscalls.h +10 −22 Original line number Diff line number Diff line Loading @@ -18,16 +18,24 @@ /* Common in X86_32 and X86_64 */ /* kernel/ioport.c */ asmlinkage long sys_ioperm(unsigned long, unsigned long, int); long sys_iopl(unsigned int, struct pt_regs *); /* kernel/process.c */ int sys_fork(struct pt_regs *); int sys_vfork(struct pt_regs *); long sys_execve(char __user *, char __user * __user *, char __user * __user *, struct pt_regs *); long sys_clone(unsigned long, unsigned long, void __user *, void __user *, struct pt_regs *); /* kernel/ldt.c */ asmlinkage int sys_modify_ldt(int, void __user *, unsigned long); /* kernel/signal.c */ long sys_rt_sigreturn(struct pt_regs *); long sys_sigaltstack(const stack_t __user *, stack_t __user *, struct pt_regs *); /* kernel/tls.c */ asmlinkage int sys_set_thread_area(struct user_desc __user *); Loading @@ -35,18 +43,11 @@ asmlinkage int sys_get_thread_area(struct user_desc __user *); /* X86_32 only */ #ifdef CONFIG_X86_32 /* kernel/ioport.c */ long sys_iopl(struct pt_regs *); /* kernel/process_32.c */ int sys_clone(struct pt_regs *); int sys_execve(struct pt_regs *); /* kernel/signal.c */ asmlinkage int sys_sigsuspend(int, int, old_sigset_t); asmlinkage int sys_sigaction(int, const struct old_sigaction __user *, struct old_sigaction __user *); int sys_sigaltstack(struct pt_regs *); unsigned long sys_sigreturn(struct pt_regs *); /* kernel/sys_i386_32.c */ Loading @@ -64,28 +65,15 @@ asmlinkage int sys_uname(struct old_utsname __user *); asmlinkage int sys_olduname(struct oldold_utsname __user *); /* kernel/vm86_32.c */ int sys_vm86old(struct pt_regs *); int sys_vm86(struct pt_regs *); int sys_vm86old(struct vm86_struct __user *, struct pt_regs *); int sys_vm86(unsigned long, unsigned long, struct pt_regs *); #else /* CONFIG_X86_32 */ /* X86_64 only */ /* kernel/ioport.c */ asmlinkage long sys_iopl(unsigned int, struct pt_regs *); /* kernel/process_64.c */ asmlinkage long sys_clone(unsigned long, unsigned long, void __user *, void __user *, struct pt_regs *); asmlinkage long sys_execve(char __user *, char __user * __user *, char __user * __user *, struct pt_regs *); long sys_arch_prctl(int, unsigned long); /* kernel/signal.c */ asmlinkage long sys_sigaltstack(const stack_t __user *, stack_t __user *, struct pt_regs *); /* kernel/sys_x86_64.c */ struct new_utsname; Loading arch/x86/kernel/entry_32.S +52 −17 Original line number Diff line number Diff line Loading @@ -725,22 +725,61 @@ END(syscall_badsys) /* * System calls that need a pt_regs pointer. */ #define PTREGSCALL(name) \ #define PTREGSCALL0(name) \ ALIGN; \ ptregs_##name: \ leal 4(%esp),%eax; \ jmp sys_##name; PTREGSCALL(iopl) PTREGSCALL(fork) PTREGSCALL(clone) PTREGSCALL(vfork) PTREGSCALL(execve) PTREGSCALL(sigaltstack) PTREGSCALL(sigreturn) PTREGSCALL(rt_sigreturn) PTREGSCALL(vm86) PTREGSCALL(vm86old) #define PTREGSCALL1(name) \ ALIGN; \ ptregs_##name: \ leal 4(%esp),%edx; \ movl (PT_EBX+4)(%esp),%eax; \ jmp sys_##name; #define PTREGSCALL2(name) \ ALIGN; \ ptregs_##name: \ leal 4(%esp),%ecx; \ movl (PT_ECX+4)(%esp),%edx; \ movl (PT_EBX+4)(%esp),%eax; \ jmp sys_##name; #define PTREGSCALL3(name) \ ALIGN; \ ptregs_##name: \ leal 4(%esp),%eax; \ pushl %eax; \ movl PT_EDX(%eax),%ecx; \ movl PT_ECX(%eax),%edx; \ movl PT_EBX(%eax),%eax; \ call sys_##name; \ addl $4,%esp; \ ret PTREGSCALL1(iopl) PTREGSCALL0(fork) PTREGSCALL0(vfork) PTREGSCALL3(execve) PTREGSCALL2(sigaltstack) PTREGSCALL0(sigreturn) PTREGSCALL0(rt_sigreturn) PTREGSCALL2(vm86) PTREGSCALL1(vm86old) /* Clone is an oddball. The 4th arg is in %edi */ ALIGN; ptregs_clone: leal 4(%esp),%eax pushl %eax pushl PT_EDI(%eax) movl PT_EDX(%eax),%ecx movl PT_ECX(%eax),%edx movl PT_EBX(%eax),%eax call sys_clone addl $8,%esp ret .macro FIXUP_ESPFIX_STACK /* Loading Loading @@ -1008,12 +1047,8 @@ END(spurious_interrupt_bug) ENTRY(kernel_thread_helper) pushl $0 # fake return address for unwinder CFI_STARTPROC movl %edx,%eax push %edx CFI_ADJUST_CFA_OFFSET 4 call *%ebx push %eax CFI_ADJUST_CFA_OFFSET 4 movl %edi,%eax call *%esi call do_exit ud2 # padding for call trace CFI_ENDPROC Loading arch/x86/kernel/entry_64.S +3 −46 Original line number Diff line number Diff line Loading @@ -1166,63 +1166,20 @@ bad_gs: jmp 2b .previous /* * Create a kernel thread. * * C extern interface: * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) * * asm input arguments: * rdi: fn, rsi: arg, rdx: flags */ ENTRY(kernel_thread) CFI_STARTPROC FAKE_STACK_FRAME $child_rip SAVE_ALL # rdi: flags, rsi: usp, rdx: will be &pt_regs movq %rdx,%rdi orq kernel_thread_flags(%rip),%rdi movq $-1, %rsi movq %rsp, %rdx xorl %r8d,%r8d xorl %r9d,%r9d # clone now call do_fork movq %rax,RAX(%rsp) xorl %edi,%edi /* * It isn't worth to check for reschedule here, * so internally to the x86_64 port you can rely on kernel_thread() * not to reschedule the child before returning, this avoids the need * of hacks for example to fork off the per-CPU idle tasks. * [Hopefully no generic code relies on the reschedule -AK] */ RESTORE_ALL UNFAKE_STACK_FRAME ret CFI_ENDPROC END(kernel_thread) ENTRY(child_rip) ENTRY(kernel_thread_helper) pushq $0 # fake return address CFI_STARTPROC /* * Here we are in the child and the registers are set as they were * at kernel_thread() invocation in the parent. */ movq %rdi, %rax movq %rsi, %rdi call *%rax call *%rsi # exit mov %eax, %edi call do_exit ud2 # padding for call trace CFI_ENDPROC END(child_rip) END(kernel_thread_helper) /* * execve(). This function needs to use IRET, not SYSRET, to set up all state properly. Loading arch/x86/kernel/ioport.c +4 −24 Original line number Diff line number Diff line Loading @@ -103,9 +103,10 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) * on system-call entry - see also fork() and the signal handling * code. */ static int do_iopl(unsigned int level, struct pt_regs *regs) long sys_iopl(unsigned int level, struct pt_regs *regs) { unsigned int old = (regs->flags >> 12) & 3; struct thread_struct *t = ¤t->thread; if (level > 3) return -EINVAL; Loading @@ -115,29 +116,8 @@ static int do_iopl(unsigned int level, struct pt_regs *regs) return -EPERM; } regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12); return 0; } #ifdef CONFIG_X86_32 long sys_iopl(struct pt_regs *regs) { unsigned int level = regs->bx; struct thread_struct *t = ¤t->thread; int rc; rc = do_iopl(level, regs); if (rc < 0) goto out; t->iopl = level << 12; set_iopl_mask(t->iopl); out: return rc; } #else asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs) { return do_iopl(level, regs); return 0; } #endif arch/x86/kernel/process.c +70 −0 Original line number Diff line number Diff line Loading @@ -255,6 +255,76 @@ int sys_vfork(struct pt_regs *regs) NULL, NULL); } long sys_clone(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid, void __user *child_tid, struct pt_regs *regs) { if (!newsp) newsp = regs->sp; return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); } /* * This gets run with %si containing the * function to call, and %di containing * the "args". */ extern void kernel_thread_helper(void); /* * Create a kernel thread */ int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); regs.si = (unsigned long) fn; regs.di = (unsigned long) arg; #ifdef CONFIG_X86_32 regs.ds = __USER_DS; regs.es = __USER_DS; regs.fs = __KERNEL_PERCPU; regs.gs = __KERNEL_STACK_CANARY; #endif regs.orig_ax = -1; regs.ip = (unsigned long) kernel_thread_helper; regs.cs = __KERNEL_CS | get_kernel_rpl(); regs.flags = X86_EFLAGS_IF | 0x2; /* Ok, create the new process.. */ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); } EXPORT_SYMBOL(kernel_thread); /* * sys_execve() executes a new program. */ long sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp, struct pt_regs *regs) { long error; char *filename; filename = getname(name); error = PTR_ERR(filename); if (IS_ERR(filename)) return error; error = do_execve(filename, argv, envp, regs); #ifdef CONFIG_X86_32 if (error == 0) { /* Make sure we don't return using sysenter.. */ set_thread_flag(TIF_IRET); } #endif putname(filename); return error; } /* * Idle related variables and functions Loading Loading
arch/x86/include/asm/syscalls.h +10 −22 Original line number Diff line number Diff line Loading @@ -18,16 +18,24 @@ /* Common in X86_32 and X86_64 */ /* kernel/ioport.c */ asmlinkage long sys_ioperm(unsigned long, unsigned long, int); long sys_iopl(unsigned int, struct pt_regs *); /* kernel/process.c */ int sys_fork(struct pt_regs *); int sys_vfork(struct pt_regs *); long sys_execve(char __user *, char __user * __user *, char __user * __user *, struct pt_regs *); long sys_clone(unsigned long, unsigned long, void __user *, void __user *, struct pt_regs *); /* kernel/ldt.c */ asmlinkage int sys_modify_ldt(int, void __user *, unsigned long); /* kernel/signal.c */ long sys_rt_sigreturn(struct pt_regs *); long sys_sigaltstack(const stack_t __user *, stack_t __user *, struct pt_regs *); /* kernel/tls.c */ asmlinkage int sys_set_thread_area(struct user_desc __user *); Loading @@ -35,18 +43,11 @@ asmlinkage int sys_get_thread_area(struct user_desc __user *); /* X86_32 only */ #ifdef CONFIG_X86_32 /* kernel/ioport.c */ long sys_iopl(struct pt_regs *); /* kernel/process_32.c */ int sys_clone(struct pt_regs *); int sys_execve(struct pt_regs *); /* kernel/signal.c */ asmlinkage int sys_sigsuspend(int, int, old_sigset_t); asmlinkage int sys_sigaction(int, const struct old_sigaction __user *, struct old_sigaction __user *); int sys_sigaltstack(struct pt_regs *); unsigned long sys_sigreturn(struct pt_regs *); /* kernel/sys_i386_32.c */ Loading @@ -64,28 +65,15 @@ asmlinkage int sys_uname(struct old_utsname __user *); asmlinkage int sys_olduname(struct oldold_utsname __user *); /* kernel/vm86_32.c */ int sys_vm86old(struct pt_regs *); int sys_vm86(struct pt_regs *); int sys_vm86old(struct vm86_struct __user *, struct pt_regs *); int sys_vm86(unsigned long, unsigned long, struct pt_regs *); #else /* CONFIG_X86_32 */ /* X86_64 only */ /* kernel/ioport.c */ asmlinkage long sys_iopl(unsigned int, struct pt_regs *); /* kernel/process_64.c */ asmlinkage long sys_clone(unsigned long, unsigned long, void __user *, void __user *, struct pt_regs *); asmlinkage long sys_execve(char __user *, char __user * __user *, char __user * __user *, struct pt_regs *); long sys_arch_prctl(int, unsigned long); /* kernel/signal.c */ asmlinkage long sys_sigaltstack(const stack_t __user *, stack_t __user *, struct pt_regs *); /* kernel/sys_x86_64.c */ struct new_utsname; Loading
arch/x86/kernel/entry_32.S +52 −17 Original line number Diff line number Diff line Loading @@ -725,22 +725,61 @@ END(syscall_badsys) /* * System calls that need a pt_regs pointer. */ #define PTREGSCALL(name) \ #define PTREGSCALL0(name) \ ALIGN; \ ptregs_##name: \ leal 4(%esp),%eax; \ jmp sys_##name; PTREGSCALL(iopl) PTREGSCALL(fork) PTREGSCALL(clone) PTREGSCALL(vfork) PTREGSCALL(execve) PTREGSCALL(sigaltstack) PTREGSCALL(sigreturn) PTREGSCALL(rt_sigreturn) PTREGSCALL(vm86) PTREGSCALL(vm86old) #define PTREGSCALL1(name) \ ALIGN; \ ptregs_##name: \ leal 4(%esp),%edx; \ movl (PT_EBX+4)(%esp),%eax; \ jmp sys_##name; #define PTREGSCALL2(name) \ ALIGN; \ ptregs_##name: \ leal 4(%esp),%ecx; \ movl (PT_ECX+4)(%esp),%edx; \ movl (PT_EBX+4)(%esp),%eax; \ jmp sys_##name; #define PTREGSCALL3(name) \ ALIGN; \ ptregs_##name: \ leal 4(%esp),%eax; \ pushl %eax; \ movl PT_EDX(%eax),%ecx; \ movl PT_ECX(%eax),%edx; \ movl PT_EBX(%eax),%eax; \ call sys_##name; \ addl $4,%esp; \ ret PTREGSCALL1(iopl) PTREGSCALL0(fork) PTREGSCALL0(vfork) PTREGSCALL3(execve) PTREGSCALL2(sigaltstack) PTREGSCALL0(sigreturn) PTREGSCALL0(rt_sigreturn) PTREGSCALL2(vm86) PTREGSCALL1(vm86old) /* Clone is an oddball. The 4th arg is in %edi */ ALIGN; ptregs_clone: leal 4(%esp),%eax pushl %eax pushl PT_EDI(%eax) movl PT_EDX(%eax),%ecx movl PT_ECX(%eax),%edx movl PT_EBX(%eax),%eax call sys_clone addl $8,%esp ret .macro FIXUP_ESPFIX_STACK /* Loading Loading @@ -1008,12 +1047,8 @@ END(spurious_interrupt_bug) ENTRY(kernel_thread_helper) pushl $0 # fake return address for unwinder CFI_STARTPROC movl %edx,%eax push %edx CFI_ADJUST_CFA_OFFSET 4 call *%ebx push %eax CFI_ADJUST_CFA_OFFSET 4 movl %edi,%eax call *%esi call do_exit ud2 # padding for call trace CFI_ENDPROC Loading
arch/x86/kernel/entry_64.S +3 −46 Original line number Diff line number Diff line Loading @@ -1166,63 +1166,20 @@ bad_gs: jmp 2b .previous /* * Create a kernel thread. * * C extern interface: * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) * * asm input arguments: * rdi: fn, rsi: arg, rdx: flags */ ENTRY(kernel_thread) CFI_STARTPROC FAKE_STACK_FRAME $child_rip SAVE_ALL # rdi: flags, rsi: usp, rdx: will be &pt_regs movq %rdx,%rdi orq kernel_thread_flags(%rip),%rdi movq $-1, %rsi movq %rsp, %rdx xorl %r8d,%r8d xorl %r9d,%r9d # clone now call do_fork movq %rax,RAX(%rsp) xorl %edi,%edi /* * It isn't worth to check for reschedule here, * so internally to the x86_64 port you can rely on kernel_thread() * not to reschedule the child before returning, this avoids the need * of hacks for example to fork off the per-CPU idle tasks. * [Hopefully no generic code relies on the reschedule -AK] */ RESTORE_ALL UNFAKE_STACK_FRAME ret CFI_ENDPROC END(kernel_thread) ENTRY(child_rip) ENTRY(kernel_thread_helper) pushq $0 # fake return address CFI_STARTPROC /* * Here we are in the child and the registers are set as they were * at kernel_thread() invocation in the parent. */ movq %rdi, %rax movq %rsi, %rdi call *%rax call *%rsi # exit mov %eax, %edi call do_exit ud2 # padding for call trace CFI_ENDPROC END(child_rip) END(kernel_thread_helper) /* * execve(). This function needs to use IRET, not SYSRET, to set up all state properly. Loading
arch/x86/kernel/ioport.c +4 −24 Original line number Diff line number Diff line Loading @@ -103,9 +103,10 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) * on system-call entry - see also fork() and the signal handling * code. */ static int do_iopl(unsigned int level, struct pt_regs *regs) long sys_iopl(unsigned int level, struct pt_regs *regs) { unsigned int old = (regs->flags >> 12) & 3; struct thread_struct *t = ¤t->thread; if (level > 3) return -EINVAL; Loading @@ -115,29 +116,8 @@ static int do_iopl(unsigned int level, struct pt_regs *regs) return -EPERM; } regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12); return 0; } #ifdef CONFIG_X86_32 long sys_iopl(struct pt_regs *regs) { unsigned int level = regs->bx; struct thread_struct *t = ¤t->thread; int rc; rc = do_iopl(level, regs); if (rc < 0) goto out; t->iopl = level << 12; set_iopl_mask(t->iopl); out: return rc; } #else asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs) { return do_iopl(level, regs); return 0; } #endif
arch/x86/kernel/process.c +70 −0 Original line number Diff line number Diff line Loading @@ -255,6 +255,76 @@ int sys_vfork(struct pt_regs *regs) NULL, NULL); } long sys_clone(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid, void __user *child_tid, struct pt_regs *regs) { if (!newsp) newsp = regs->sp; return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); } /* * This gets run with %si containing the * function to call, and %di containing * the "args". */ extern void kernel_thread_helper(void); /* * Create a kernel thread */ int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); regs.si = (unsigned long) fn; regs.di = (unsigned long) arg; #ifdef CONFIG_X86_32 regs.ds = __USER_DS; regs.es = __USER_DS; regs.fs = __KERNEL_PERCPU; regs.gs = __KERNEL_STACK_CANARY; #endif regs.orig_ax = -1; regs.ip = (unsigned long) kernel_thread_helper; regs.cs = __KERNEL_CS | get_kernel_rpl(); regs.flags = X86_EFLAGS_IF | 0x2; /* Ok, create the new process.. */ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); } EXPORT_SYMBOL(kernel_thread); /* * sys_execve() executes a new program. */ long sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp, struct pt_regs *regs) { long error; char *filename; filename = getname(name); error = PTR_ERR(filename); if (IS_ERR(filename)) return error; error = do_execve(filename, argv, envp, regs); #ifdef CONFIG_X86_32 if (error == 0) { /* Make sure we don't return using sysenter.. */ set_thread_flag(TIF_IRET); } #endif putname(filename); return error; } /* * Idle related variables and functions Loading