Commit 6a52e4b1 authored by Jeremy Fitzhardinge's avatar Jeremy Fitzhardinge Committed by Ingo Molnar

x86_64: further cleanup of 32-bit compat syscall mechanisms

AMD only supports "syscall" from 32-bit compat usermode.
Intel and Centaur(?) only support "sysenter" from 32-bit compat usermode.

Set the X86 feature bits accordingly, and set up the vdso in
accordance with those bits.  On the offchance we run on in a 64-bit
environment which supports neither syscall nor sysenter from 32-bit
mode, then fall back to the int $0x80 vdso.
Signed-off-by: default avatarJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
parent 71415c6a
...@@ -115,6 +115,8 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) ...@@ -115,6 +115,8 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
/* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */ /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
if (c->x86_power & (1<<8)) if (c->x86_power & (1<<8))
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
set_cpu_cap(c, X86_FEATURE_SYSCALL32);
} }
static void __cpuinit init_amd(struct cpuinfo_x86 *c) static void __cpuinit init_amd(struct cpuinfo_x86 *c)
......
...@@ -317,9 +317,6 @@ static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c) ...@@ -317,9 +317,6 @@ static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
c->x86_phys_bits = eax & 0xff; c->x86_phys_bits = eax & 0xff;
} }
/* Assume all 64-bit CPUs support 32-bit syscall */
set_cpu_cap(c, X86_FEATURE_SYSCALL32);
if (c->x86_vendor != X86_VENDOR_UNKNOWN && if (c->x86_vendor != X86_VENDOR_UNKNOWN &&
cpu_devs[c->x86_vendor]->c_early_init) cpu_devs[c->x86_vendor]->c_early_init)
cpu_devs[c->x86_vendor]->c_early_init(c); cpu_devs[c->x86_vendor]->c_early_init(c);
......
...@@ -62,7 +62,7 @@ $(obj)/%-syms.lds: $(obj)/%.so.dbg FORCE ...@@ -62,7 +62,7 @@ $(obj)/%-syms.lds: $(obj)/%.so.dbg FORCE
# Build multiple 32-bit vDSO images to choose from at boot time. # Build multiple 32-bit vDSO images to choose from at boot time.
# #
obj-$(VDSO32-y) += vdso32-syms.lds obj-$(VDSO32-y) += vdso32-syms.lds
vdso32.so-$(CONFIG_X86_32) += int80 vdso32.so-$(VDSO32-y) += int80
vdso32.so-$(CONFIG_COMPAT) += syscall vdso32.so-$(CONFIG_COMPAT) += syscall
vdso32.so-$(VDSO32-y) += sysenter vdso32.so-$(VDSO32-y) += sysenter
......
...@@ -193,17 +193,12 @@ static __init void relocate_vdso(Elf32_Ehdr *ehdr) ...@@ -193,17 +193,12 @@ static __init void relocate_vdso(Elf32_Ehdr *ehdr)
} }
} }
/*
* These symbols are defined by vdso32.S to mark the bounds
* of the ELF DSO images included therein.
*/
extern const char vdso32_default_start, vdso32_default_end;
extern const char vdso32_sysenter_start, vdso32_sysenter_end;
static struct page *vdso32_pages[1]; static struct page *vdso32_pages[1];
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
#define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SYSENTER32)) #define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SYSENTER32))
#define vdso32_syscall() (boot_cpu_has(X86_FEATURE_SYSCALL32))
/* May not be __init: called during resume */ /* May not be __init: called during resume */
void syscall32_cpu_init(void) void syscall32_cpu_init(void)
...@@ -226,6 +221,7 @@ static inline void map_compat_vdso(int map) ...@@ -226,6 +221,7 @@ static inline void map_compat_vdso(int map)
#else /* CONFIG_X86_32 */ #else /* CONFIG_X86_32 */
#define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SEP)) #define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SEP))
#define vdso32_syscall() (0)
void enable_sep_cpu(void) void enable_sep_cpu(void)
{ {
...@@ -296,12 +292,15 @@ int __init sysenter_setup(void) ...@@ -296,12 +292,15 @@ int __init sysenter_setup(void)
gate_vma_init(); gate_vma_init();
#endif #endif
if (!vdso32_sysenter()) { if (vdso32_syscall()) {
vsyscall = &vdso32_default_start; vsyscall = &vdso32_syscall_start;
vsyscall_len = &vdso32_default_end - &vdso32_default_start; vsyscall_len = &vdso32_syscall_end - &vdso32_syscall_start;
} else { } else if (vdso32_sysenter()){
vsyscall = &vdso32_sysenter_start; vsyscall = &vdso32_sysenter_start;
vsyscall_len = &vdso32_sysenter_end - &vdso32_sysenter_start; vsyscall_len = &vdso32_sysenter_end - &vdso32_sysenter_start;
} else {
vsyscall = &vdso32_int80_start;
vsyscall_len = &vdso32_int80_end - &vdso32_int80_start;
} }
memcpy(syscall_page, vsyscall, vsyscall_len); memcpy(syscall_page, vsyscall, vsyscall_len);
......
...@@ -2,14 +2,17 @@ ...@@ -2,14 +2,17 @@
__INITDATA __INITDATA
.globl vdso32_default_start, vdso32_default_end .globl vdso32_int80_start, vdso32_int80_end
vdso32_default_start: vdso32_int80_start:
#ifdef CONFIG_X86_32
.incbin "arch/x86/vdso/vdso32-int80.so" .incbin "arch/x86/vdso/vdso32-int80.so"
#else vdso32_int80_end:
.globl vdso32_syscall_start, vdso32_syscall_end
vdso32_syscall_start:
#ifdef CONFIG_COMPAT
.incbin "arch/x86/vdso/vdso32-syscall.so" .incbin "arch/x86/vdso/vdso32-syscall.so"
#endif #endif
vdso32_default_end: vdso32_syscall_end:
.globl vdso32_sysenter_start, vdso32_sysenter_end .globl vdso32_sysenter_start, vdso32_sysenter_end
vdso32_sysenter_start: vdso32_sysenter_start:
......
...@@ -83,12 +83,16 @@ static void xen_idle(void) ...@@ -83,12 +83,16 @@ static void xen_idle(void)
/* /*
* Set the bit indicating "nosegneg" library variants should be used. * Set the bit indicating "nosegneg" library variants should be used.
* We only need to bother in pure 32-bit mode; compat 32-bit processes
* can have un-truncated segments, so wrapping around is allowed.
*/ */
static void __init fiddle_vdso(void) static void __init fiddle_vdso(void)
{ {
#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) #ifdef CONFIG_X86_32
extern const char vdso32_default_start; u32 *mask;
u32 *mask = VDSO32_SYMBOL(&vdso32_default_start, NOTE_MASK); mask = VDSO32_SYMBOL(&vdso32_int80_start, NOTE_MASK);
*mask |= 1 << VDSO_NOTE_NONEGSEG_BIT;
mask = VDSO32_SYMBOL(&vdso32_sysenter_start, NOTE_MASK);
*mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT;
#endif #endif
} }
......
...@@ -36,4 +36,12 @@ extern const char VDSO32_PRELINK[]; ...@@ -36,4 +36,12 @@ extern const char VDSO32_PRELINK[];
extern void __user __kernel_sigreturn; extern void __user __kernel_sigreturn;
extern void __user __kernel_rt_sigreturn; extern void __user __kernel_rt_sigreturn;
/*
* These symbols are defined by vdso32.S to mark the bounds
* of the ELF DSO images included therein.
*/
extern const char vdso32_int80_start, vdso32_int80_end;
extern const char vdso32_syscall_start, vdso32_syscall_end;
extern const char vdso32_sysenter_start, vdso32_sysenter_end;
#endif /* asm-x86/vdso.h */ #endif /* asm-x86/vdso.h */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment