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

Commit d1a797f3 authored by H. Peter Anvin's avatar H. Peter Anvin
Browse files

x32: Handle process creation



Allow an x32 process to be started.

Originally-by: default avatarH. J. Lu <hjl.tools@gmail.com>
Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
parent c5a37394
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
 */
#include <linux/types.h>
#include <linux/sched.h>
#include <asm/processor.h>
#include <asm/user32.h>
#include <asm/unistd.h>

@@ -187,7 +188,20 @@ struct compat_shmid64_ds {
/*
 * The type of struct elf_prstatus.pr_reg in compatible core dumps.
 */
#ifdef CONFIG_X86_X32_ABI
typedef struct user_regs_struct compat_elf_gregset_t;

#define PR_REG_SIZE(S) (test_thread_flag(TIF_IA32) ? 68 : 216)
#define PRSTATUS_SIZE(S) (test_thread_flag(TIF_IA32) ? 144 : 296)
#define SET_PR_FPVALID(S,V) \
  do { *(int *) (((void *) &((S)->pr_reg)) + PR_REG_SIZE(0)) = (V); } \
  while (0)

#define COMPAT_USE_64BIT_TIME \
	(!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT))
#else
typedef struct user_regs_struct32 compat_elf_gregset_t;
#endif

/*
 * A pointer passed in from user mode. This should not
@@ -209,8 +223,16 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)

static inline void __user *arch_compat_alloc_user_space(long len)
{
	struct pt_regs *regs = task_pt_regs(current);
	return (void __user *)regs->sp - len;
	compat_uptr_t sp;

	if (test_thread_flag(TIF_IA32)) {
		sp = task_pt_regs(current)->sp;
	} else {
		/* -128 for the x32 ABI redzone */
		sp = percpu_read(old_rsp) - 128;
	}

	return (void __user *)round_down(sp - len, 16);
}

static inline bool is_compat_task(void)
+21 −4
Original line number Diff line number Diff line
@@ -156,7 +156,12 @@ do { \
#define elf_check_arch(x)			\
	((x)->e_machine == EM_X86_64)

#define compat_elf_check_arch(x)	elf_check_arch_ia32(x)
#define compat_elf_check_arch(x)		\
	(elf_check_arch_ia32(x) || (x)->e_machine == EM_X86_64)

#if __USER32_DS != __USER_DS
# error "The following code assumes __USER32_DS == __USER_DS"
#endif

static inline void elf_common_init(struct thread_struct *t,
				   struct pt_regs *regs, const u16 ds)
@@ -179,8 +184,9 @@ static inline void elf_common_init(struct thread_struct *t,
void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp);
#define compat_start_thread start_thread_ia32

void set_personality_ia32(void);
#define COMPAT_SET_PERSONALITY(ex) set_personality_ia32()
void set_personality_ia32(bool);
#define COMPAT_SET_PERSONALITY(ex)			\
	set_personality_ia32((ex).e_machine == EM_X86_64)

#define COMPAT_ELF_PLATFORM			("i686")

@@ -296,9 +302,20 @@ do { \
			    (unsigned long)current->mm->context.vdso);	\
} while (0)

#define ARCH_DLINFO_X32							\
do {									\
	if (vdso_enabled)						\
		NEW_AUX_ENT(AT_SYSINFO_EHDR,				\
			    (unsigned long)current->mm->context.vdso);	\
} while (0)

#define AT_SYSINFO		32

#define COMPAT_ARCH_DLINFO	ARCH_DLINFO_IA32(sysctl_vsyscall32)
#define COMPAT_ARCH_DLINFO						\
if (test_thread_flag(TIF_X32))						\
	ARCH_DLINFO_X32;						\
else									\
	ARCH_DLINFO_IA32(sysctl_vsyscall32)

#define COMPAT_ELF_ET_DYN_BASE	(TASK_UNMAPPED_BASE + 0x1000000)

+3 −1
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@
#include <asm/apic.h>
#include <asm/stacktrace.h>
#include <asm/nmi.h>
#include <asm/compat.h>
#include <asm/smp.h>
#include <asm/alternative.h>

@@ -1595,6 +1594,9 @@ perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
}

#ifdef CONFIG_COMPAT

#include <asm/compat.h>

static inline int
perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
{
+15 −0
Original line number Diff line number Diff line
@@ -763,6 +763,21 @@ ENTRY(stub_x32_rt_sigreturn)
	CFI_ENDPROC
END(stub_x32_rt_sigreturn)

ENTRY(stub_x32_execve)
	CFI_STARTPROC
	addq $8, %rsp
	PARTIAL_FRAME 0
	SAVE_REST
	FIXUP_TOP_OF_STACK %r11
	movq %rsp, %rcx
	call sys32_execve
	RESTORE_TOP_OF_STACK %r11
	movq %rax,RAX(%rsp)
	RESTORE_REST
	jmp int_ret_from_sys_call
	CFI_ENDPROC
END(stub_x32_execve)

#endif

/*
+16 −7
Original line number Diff line number Diff line
@@ -364,7 +364,9 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp)
{
	start_thread_common(regs, new_ip, new_sp,
			    __USER32_CS, __USER32_DS, __USER32_DS);
			    test_thread_flag(TIF_X32)
			    ? __USER_CS : __USER32_CS,
			    __USER_DS, __USER_DS);
}
#endif

@@ -508,6 +510,7 @@ void set_personality_64bit(void)

	/* Make sure to be in 64bit mode */
	clear_thread_flag(TIF_IA32);
	clear_thread_flag(TIF_X32);
	clear_thread_flag(TIF_ADDR32);
	clear_thread_flag(TIF_X32);

@@ -522,23 +525,29 @@ void set_personality_64bit(void)
	current->personality &= ~READ_IMPLIES_EXEC;
}

void set_personality_ia32(void)
void set_personality_ia32(bool x32)
{
	/* inherit personality from parent */

	/* Make sure to be in 32bit mode */
	set_thread_flag(TIF_IA32);
	set_thread_flag(TIF_ADDR32);
	clear_thread_flag(TIF_X32);
	current->personality |= force_personality32;

	/* Mark the associated mm as containing 32-bit tasks. */
	if (current->mm)
		current->mm->context.ia32_compat = 1;

	if (x32) {
		clear_thread_flag(TIF_IA32);
		set_thread_flag(TIF_X32);
		current->personality &= ~READ_IMPLIES_EXEC;
	} else {
		set_thread_flag(TIF_IA32);
		clear_thread_flag(TIF_X32);
		current->personality |= force_personality32;
		/* Prepare the first "return" to user space */
		current_thread_info()->status |= TS_COMPAT;
	}
}

unsigned long get_wchan(struct task_struct *p)
{