Skip to content

Commit

Permalink
x86_64: further cleanup of 32-bit compat syscall mechanisms
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jeremy Fitzhardinge authored and Ingo Molnar committed Jul 16, 2008
1 parent 71415c6 commit 6a52e4b
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 22 deletions.
2 changes: 2 additions & 0 deletions arch/x86/kernel/cpu/amd_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 0 additions & 3 deletions arch/x86/kernel/cpu/common_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/vdso/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
19 changes: 9 additions & 10 deletions arch/x86/vdso/vdso32-setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 8 additions & 5 deletions arch/x86/vdso/vdso32.S
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 7 additions & 3 deletions arch/x86/xen/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
8 changes: 8 additions & 0 deletions include/asm-x86/vdso.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit 6a52e4b

Please sign in to comment.