diff --git a/arch/i386/boot/compressed/relocs.c b/arch/i386/boot/compressed/relocs.c index b0e21c3cee5c..2d77ee728f92 100644 --- a/arch/i386/boot/compressed/relocs.c +++ b/arch/i386/boot/compressed/relocs.c @@ -31,6 +31,7 @@ static const char* safe_abs_relocs[] = { "__kernel_rt_sigreturn", "__kernel_sigreturn", "SYSENTER_RETURN", + "VDSO_NOTE_MASK", "xen_irq_disable_direct_reloc", "xen_save_fl_direct_reloc", }; diff --git a/arch/i386/kernel/vsyscall-note.S b/arch/i386/kernel/vsyscall-note.S index 271f16a8ca01..07c0daf78237 100644 --- a/arch/i386/kernel/vsyscall-note.S +++ b/arch/i386/kernel/vsyscall-note.S @@ -14,7 +14,6 @@ ELFNOTE_START(Linux, 0, "a") ELFNOTE_END #ifdef CONFIG_XEN - /* * Add a special note telling glibc's dynamic linker a fake hardware * flavor that it will use to choose the search path for libraries in the @@ -28,15 +27,19 @@ ELFNOTE_END * It should contain: * hwcap 1 nosegneg * to match the mapping of bit to name that we give here. + * + * At runtime, the fake hardware feature will be considered to be present + * if its bit is set in the mask word. So, we start with the mask 0, and + * at boot time we set VDSO_NOTE_NONEGSEG_BIT if running under Xen. */ -/* Bit used for the pseudo-hwcap for non-negative segments. We use - bit 1 to avoid bugs in some versions of glibc when bit 0 is - used; the choice is otherwise arbitrary. */ -#define VDSO_NOTE_NONEGSEG_BIT 1 +#include "../xen/vdso.h" /* Defines VDSO_NOTE_NONEGSEG_BIT. */ + .globl VDSO_NOTE_MASK ELFNOTE_START(GNU, 2, "a") - .long 1, 1< #include "xen-ops.h" +#include "vdso.h" /* These are code, but not functions. Defined in entry.S */ extern const char xen_hypervisor_callback[]; @@ -55,6 +56,18 @@ static void xen_idle(void) } } +/* + * Set the bit indicating "nosegneg" library variants should be used. + */ +static void fiddle_vdso(void) +{ + extern u32 VDSO_NOTE_MASK; /* See ../kernel/vsyscall-note.S. */ + extern char vsyscall_int80_start; + u32 *mask = (u32 *) ((unsigned long) &VDSO_NOTE_MASK - VDSO_PRELINK + + &vsyscall_int80_start); + *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; +} + void __init xen_arch_setup(void) { struct physdev_set_iopl set_iopl; @@ -93,4 +106,6 @@ void __init xen_arch_setup(void) #endif paravirt_disable_iospace(); + + fiddle_vdso(); } diff --git a/arch/i386/xen/vdso.h b/arch/i386/xen/vdso.h new file mode 100644 index 000000000000..861fedfe5230 --- /dev/null +++ b/arch/i386/xen/vdso.h @@ -0,0 +1,4 @@ +/* Bit used for the pseudo-hwcap for non-negative segments. We use + bit 1 to avoid bugs in some versions of glibc when bit 0 is + used; the choice is otherwise arbitrary. */ +#define VDSO_NOTE_NONEGSEG_BIT 1