Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ab1eebe7 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branch 'x86/asm' into x86/urgent



Merge reason: it's stable so lets push it upstream.

Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parents 186a2502 df59e7bf
Loading
Loading
Loading
Loading
+10 −22
Original line number Diff line number Diff line
@@ -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 *);
@@ -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 */
@@ -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;

+52 −17
Original line number Diff line number Diff line
@@ -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
/*
@@ -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
+3 −46
Original line number Diff line number Diff line
@@ -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.
+4 −24
Original line number Diff line number Diff line
@@ -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 = &current->thread;

	if (level > 3)
		return -EINVAL;
@@ -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 = &current->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
+70 −0
Original line number Diff line number Diff line
@@ -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(&regs, 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, &regs, 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