aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/compat.h26
-rw-r--r--arch/x86/include/asm/elf.h25
-rw-r--r--arch/x86/kernel/cpu/perf_event.c4
-rw-r--r--arch/x86/kernel/entry_64.S15
-rw-r--r--arch/x86/kernel/process_64.c23
5 files changed, 79 insertions, 14 deletions
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index 7938b84e4506..e7f68b49c01a 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -6,6 +6,7 @@
6 */ 6 */
7#include <linux/types.h> 7#include <linux/types.h>
8#include <linux/sched.h> 8#include <linux/sched.h>
9#include <asm/processor.h>
9#include <asm/user32.h> 10#include <asm/user32.h>
10#include <asm/unistd.h> 11#include <asm/unistd.h>
11 12
@@ -187,7 +188,20 @@ struct compat_shmid64_ds {
187/* 188/*
188 * The type of struct elf_prstatus.pr_reg in compatible core dumps. 189 * The type of struct elf_prstatus.pr_reg in compatible core dumps.
189 */ 190 */
191#ifdef CONFIG_X86_X32_ABI
192typedef struct user_regs_struct compat_elf_gregset_t;
193
194#define PR_REG_SIZE(S) (test_thread_flag(TIF_IA32) ? 68 : 216)
195#define PRSTATUS_SIZE(S) (test_thread_flag(TIF_IA32) ? 144 : 296)
196#define SET_PR_FPVALID(S,V) \
197 do { *(int *) (((void *) &((S)->pr_reg)) + PR_REG_SIZE(0)) = (V); } \
198 while (0)
199
200#define COMPAT_USE_64BIT_TIME \
201 (!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT))
202#else
190typedef struct user_regs_struct32 compat_elf_gregset_t; 203typedef struct user_regs_struct32 compat_elf_gregset_t;
204#endif
191 205
192/* 206/*
193 * A pointer passed in from user mode. This should not 207 * 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)
209 223
210static inline void __user *arch_compat_alloc_user_space(long len) 224static inline void __user *arch_compat_alloc_user_space(long len)
211{ 225{
212 struct pt_regs *regs = task_pt_regs(current); 226 compat_uptr_t sp;
213 return (void __user *)regs->sp - len; 227
228 if (test_thread_flag(TIF_IA32)) {
229 sp = task_pt_regs(current)->sp;
230 } else {
231 /* -128 for the x32 ABI redzone */
232 sp = percpu_read(old_rsp) - 128;
233 }
234
235 return (void __user *)round_down(sp - len, 16);
214} 236}
215 237
216static inline bool is_compat_task(void) 238static inline bool is_compat_task(void)
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 410fa6a219f6..83aabea95dd7 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -156,7 +156,12 @@ do { \
156#define elf_check_arch(x) \ 156#define elf_check_arch(x) \
157 ((x)->e_machine == EM_X86_64) 157 ((x)->e_machine == EM_X86_64)
158 158
159#define compat_elf_check_arch(x) elf_check_arch_ia32(x) 159#define compat_elf_check_arch(x) \
160 (elf_check_arch_ia32(x) || (x)->e_machine == EM_X86_64)
161
162#if __USER32_DS != __USER_DS
163# error "The following code assumes __USER32_DS == __USER_DS"
164#endif
160 165
161static inline void elf_common_init(struct thread_struct *t, 166static inline void elf_common_init(struct thread_struct *t,
162 struct pt_regs *regs, const u16 ds) 167 struct pt_regs *regs, const u16 ds)
@@ -179,8 +184,9 @@ static inline void elf_common_init(struct thread_struct *t,
179void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp); 184void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp);
180#define compat_start_thread start_thread_ia32 185#define compat_start_thread start_thread_ia32
181 186
182void set_personality_ia32(void); 187void set_personality_ia32(bool);
183#define COMPAT_SET_PERSONALITY(ex) set_personality_ia32() 188#define COMPAT_SET_PERSONALITY(ex) \
189 set_personality_ia32((ex).e_machine == EM_X86_64)
184 190
185#define COMPAT_ELF_PLATFORM ("i686") 191#define COMPAT_ELF_PLATFORM ("i686")
186 192
@@ -296,9 +302,20 @@ do { \
296 (unsigned long)current->mm->context.vdso); \ 302 (unsigned long)current->mm->context.vdso); \
297} while (0) 303} while (0)
298 304
305#define ARCH_DLINFO_X32 \
306do { \
307 if (vdso_enabled) \
308 NEW_AUX_ENT(AT_SYSINFO_EHDR, \
309 (unsigned long)current->mm->context.vdso); \
310} while (0)
311
299#define AT_SYSINFO 32 312#define AT_SYSINFO 32
300 313
301#define COMPAT_ARCH_DLINFO ARCH_DLINFO_IA32(sysctl_vsyscall32) 314#define COMPAT_ARCH_DLINFO \
315if (test_thread_flag(TIF_X32)) \
316 ARCH_DLINFO_X32; \
317else \
318 ARCH_DLINFO_IA32(sysctl_vsyscall32)
302 319
303#define COMPAT_ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000) 320#define COMPAT_ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000)
304 321
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 5adce1040b11..63c0e058a405 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -28,7 +28,6 @@
28#include <asm/apic.h> 28#include <asm/apic.h>
29#include <asm/stacktrace.h> 29#include <asm/stacktrace.h>
30#include <asm/nmi.h> 30#include <asm/nmi.h>
31#include <asm/compat.h>
32#include <asm/smp.h> 31#include <asm/smp.h>
33#include <asm/alternative.h> 32#include <asm/alternative.h>
34 33
@@ -1595,6 +1594,9 @@ perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
1595} 1594}
1596 1595
1597#ifdef CONFIG_COMPAT 1596#ifdef CONFIG_COMPAT
1597
1598#include <asm/compat.h>
1599
1598static inline int 1600static inline int
1599perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry) 1601perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
1600{ 1602{
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 53dc821f0a62..9e036f0ce5e0 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -763,6 +763,21 @@ ENTRY(stub_x32_rt_sigreturn)
763 CFI_ENDPROC 763 CFI_ENDPROC
764END(stub_x32_rt_sigreturn) 764END(stub_x32_rt_sigreturn)
765 765
766ENTRY(stub_x32_execve)
767 CFI_STARTPROC
768 addq $8, %rsp
769 PARTIAL_FRAME 0
770 SAVE_REST
771 FIXUP_TOP_OF_STACK %r11
772 movq %rsp, %rcx
773 call sys32_execve
774 RESTORE_TOP_OF_STACK %r11
775 movq %rax,RAX(%rsp)
776 RESTORE_REST
777 jmp int_ret_from_sys_call
778 CFI_ENDPROC
779END(stub_x32_execve)
780
766#endif 781#endif
767 782
768/* 783/*
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 5fe2fbaa56ba..a0701da2bd18 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -364,7 +364,9 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
364void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp) 364void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp)
365{ 365{
366 start_thread_common(regs, new_ip, new_sp, 366 start_thread_common(regs, new_ip, new_sp,
367 __USER32_CS, __USER32_DS, __USER32_DS); 367 test_thread_flag(TIF_X32)
368 ? __USER_CS : __USER32_CS,
369 __USER_DS, __USER_DS);
368} 370}
369#endif 371#endif
370 372
@@ -508,6 +510,7 @@ void set_personality_64bit(void)
508 510
509 /* Make sure to be in 64bit mode */ 511 /* Make sure to be in 64bit mode */
510 clear_thread_flag(TIF_IA32); 512 clear_thread_flag(TIF_IA32);
513 clear_thread_flag(TIF_X32);
511 clear_thread_flag(TIF_ADDR32); 514 clear_thread_flag(TIF_ADDR32);
512 clear_thread_flag(TIF_X32); 515 clear_thread_flag(TIF_X32);
513 516
@@ -522,22 +525,28 @@ void set_personality_64bit(void)
522 current->personality &= ~READ_IMPLIES_EXEC; 525 current->personality &= ~READ_IMPLIES_EXEC;
523} 526}
524 527
525void set_personality_ia32(void) 528void set_personality_ia32(bool x32)
526{ 529{
527 /* inherit personality from parent */ 530 /* inherit personality from parent */
528 531
529 /* Make sure to be in 32bit mode */ 532 /* Make sure to be in 32bit mode */
530 set_thread_flag(TIF_IA32);
531 set_thread_flag(TIF_ADDR32); 533 set_thread_flag(TIF_ADDR32);
532 clear_thread_flag(TIF_X32);
533 current->personality |= force_personality32;
534 534
535 /* Mark the associated mm as containing 32-bit tasks. */ 535 /* Mark the associated mm as containing 32-bit tasks. */
536 if (current->mm) 536 if (current->mm)
537 current->mm->context.ia32_compat = 1; 537 current->mm->context.ia32_compat = 1;
538 538
539 /* Prepare the first "return" to user space */ 539 if (x32) {
540 current_thread_info()->status |= TS_COMPAT; 540 clear_thread_flag(TIF_IA32);
541 set_thread_flag(TIF_X32);
542 current->personality &= ~READ_IMPLIES_EXEC;
543 } else {
544 set_thread_flag(TIF_IA32);
545 clear_thread_flag(TIF_X32);
546 current->personality |= force_personality32;
547 /* Prepare the first "return" to user space */
548 current_thread_info()->status |= TS_COMPAT;
549 }
541} 550}
542 551
543unsigned long get_wchan(struct task_struct *p) 552unsigned long get_wchan(struct task_struct *p)