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: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
parent
71415c6a08
commit
6a52e4b1cd
7 changed files with 35 additions and 22 deletions
|
@ -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 */
|
||||
if (c->x86_power & (1<<8))
|
||||
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
|
||||
|
||||
set_cpu_cap(c, X86_FEATURE_SYSCALL32);
|
||||
}
|
||||
|
||||
static void __cpuinit init_amd(struct cpuinfo_x86 *c)
|
||||
|
|
|
@ -317,9 +317,6 @@ static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
|
|||
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 &&
|
||||
cpu_devs[c->x86_vendor]->c_early_init)
|
||||
cpu_devs[c->x86_vendor]->c_early_init(c);
|
||||
|
|
|
@ -62,7 +62,7 @@ $(obj)/%-syms.lds: $(obj)/%.so.dbg FORCE
|
|||
# Build multiple 32-bit vDSO images to choose from at boot time.
|
||||
#
|
||||
obj-$(VDSO32-y) += vdso32-syms.lds
|
||||
vdso32.so-$(CONFIG_X86_32) += int80
|
||||
vdso32.so-$(VDSO32-y) += int80
|
||||
vdso32.so-$(CONFIG_COMPAT) += syscall
|
||||
vdso32.so-$(VDSO32-y) += sysenter
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
||||
#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 */
|
||||
void syscall32_cpu_init(void)
|
||||
|
@ -226,6 +221,7 @@ static inline void map_compat_vdso(int map)
|
|||
#else /* CONFIG_X86_32 */
|
||||
|
||||
#define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SEP))
|
||||
#define vdso32_syscall() (0)
|
||||
|
||||
void enable_sep_cpu(void)
|
||||
{
|
||||
|
@ -296,12 +292,15 @@ int __init sysenter_setup(void)
|
|||
gate_vma_init();
|
||||
#endif
|
||||
|
||||
if (!vdso32_sysenter()) {
|
||||
vsyscall = &vdso32_default_start;
|
||||
vsyscall_len = &vdso32_default_end - &vdso32_default_start;
|
||||
} else {
|
||||
if (vdso32_syscall()) {
|
||||
vsyscall = &vdso32_syscall_start;
|
||||
vsyscall_len = &vdso32_syscall_end - &vdso32_syscall_start;
|
||||
} else if (vdso32_sysenter()){
|
||||
vsyscall = &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);
|
||||
|
|
|
@ -2,14 +2,17 @@
|
|||
|
||||
__INITDATA
|
||||
|
||||
.globl vdso32_default_start, vdso32_default_end
|
||||
vdso32_default_start:
|
||||
#ifdef CONFIG_X86_32
|
||||
.globl vdso32_int80_start, vdso32_int80_end
|
||||
vdso32_int80_start:
|
||||
.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"
|
||||
#endif
|
||||
vdso32_default_end:
|
||||
vdso32_syscall_end:
|
||||
|
||||
.globl vdso32_sysenter_start, vdso32_sysenter_end
|
||||
vdso32_sysenter_start:
|
||||
|
|
|
@ -83,12 +83,16 @@ static void xen_idle(void)
|
|||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
|
||||
extern const char vdso32_default_start;
|
||||
u32 *mask = VDSO32_SYMBOL(&vdso32_default_start, NOTE_MASK);
|
||||
#ifdef CONFIG_X86_32
|
||||
u32 *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;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -36,4 +36,12 @@ extern const char VDSO32_PRELINK[];
|
|||
extern void __user __kernel_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 */
|
||||
|
|
Loading…
Reference in a new issue