Clean up and unify the vDSO
Subsystems (7)
v3 cover Clean up and unify the vDSO
This rewrites a bunch of the vdso code. After these patches, the vvar and hpet pages are mapped directly after the vdso text on all five vdso variants. The fixmaps are gone on 64-bit systems.
It would be possible to build the x32 vdso the normal way on top of these patches.
I haven't touched the pvclock code. I'd want to understand why it exists, why it isn't using rdtsc, and why it has two rdtsc_barrier calls before rearranging it. In a discussion with Marcello Tosatti, I think we concluded that the kvmclock code could be significantly simplified and sped up without breaking anything, but I want to save that for later.
This should apply to -linus or to tip/x86/vdso. It's also here:
https://git.kernel.org/cgit/linux/kernel/git/luto/linux.git/log/?h=vdso/cleanups
Changes from v2:
- Fixed the 32-bit build. Hopefully I didn't screw up bisection.
Changes from v1:
- Rebased
- I think Gold is working (this is a side effect of the rebase)
Andy Lutomirski (6):
x86: Clean up 32-bit vs 64-bit vdso params
x86: Move syscall and sysenter setup into kernel/cpu/common.c
x86: Reimplement vdso.so preparation in build-time C
x86: Move the 32-bit vdso special pages after the text
x86: Move the vvar and hpet mappings next to the 64-bit vDSO
x86: Remove vestiges of VDSO_PRELINK and some outdated comments
arch/x86/ia32/ia32_signal.c | 8 +- arch/x86/include/asm/elf.h | 35 +++--- arch/x86/include/asm/fixmap.h | 10 +- arch/x86/include/asm/mmu.h | 2 +- arch/x86/include/asm/proto.h | 2 - arch/x86/include/asm/vdso.h | 74 +++++------- arch/x86/include/asm/vdso32.h | 11 -- arch/x86/include/asm/vvar.h | 20 +--- arch/x86/include/uapi/asm/vsyscall.h | 7 +- arch/x86/kernel/cpu/common.c | 33 ++++++ arch/x86/kernel/hpet.c | 3 - arch/x86/kernel/signal.c | 6 +- arch/x86/kernel/vsyscall_64.c | 15 +-- arch/x86/mm/fault.c | 5 +- arch/x86/mm/init_64.c | 13 +- arch/x86/um/vdso/vma.c | 2 +- arch/x86/vdso/.gitignore | 5 +- arch/x86/vdso/Makefile | 90 +++++--------- arch/x86/vdso/vclock_gettime.c | 26 ++-- arch/x86/vdso/vdso-layout.lds.S | 40 ++++--- arch/x86/vdso/vdso.S | 3 - arch/x86/vdso/vdso.lds.S | 7 +- arch/x86/vdso/vdso2c.c | 156 ++++++++++++++++++++++++ arch/x86/vdso/vdso2c.h | 154 ++++++++++++++++++++++++ arch/x86/vdso/vdso32-setup.c | 196 ++++--------------------------- arch/x86/vdso/vdso32.S | 9 -- arch/x86/vdso/vdso32/vdso32.lds.S | 15 +-- arch/x86/vdso/vdsox32.S | 3 - arch/x86/vdso/vdsox32.lds.S | 7 +- arch/x86/vdso/vma.c | 222 +++++++++++++++++++---------------- arch/x86/xen/mmu.c | 8 +- arch/x86/xen/setup.c | 11 +- kernel/sysctl.c | 5 + 33 files changed, 647 insertions(+), 556 deletions(-) delete mode 100644 arch/x86/include/asm/vdso32.h delete mode 100644 arch/x86/vdso/vdso.S create mode 100644 arch/x86/vdso/vdso2c.c create mode 100644 arch/x86/vdso/vdso2c.h delete mode 100644 arch/x86/vdso/vdso32.S delete mode 100644 arch/x86/vdso/vdsox32.S
Signature · 1 line
1.9.0
PATCH v3 1/6 x86: Clean up 32-bit vs 64-bit vdso params
Rather than using 'vdso_enabled' and an awful #define, just call the parameters vdso32_enabled and vdso64_enabled.
--- arch/x86/include/asm/elf.h | 20 +++++++++++++------- arch/x86/um/vdso/vma.c | 2 +- arch/x86/vdso/vdso32-setup.c | 19 ++++++++----------- arch/x86/vdso/vma.c | 6 +++--- kernel/sysctl.c | 5 +++++ 5 files changed, 30 insertions(+), 22 deletions(-)
arch/x86/include/asm/elf.h +13 -7
@@ -75,7 +75,12 @@ typedef struct user_fxsr_struct elf_fpxregset_t;#include <asm/vdso.h> -extern unsigned int vdso_enabled; +#ifdef CONFIG_X86_64 +extern unsigned int vdso64_enabled; +#endif +#if defined(CONFIG_X86_32 ) || defined(CONFIG_COMPAT ) +extern unsigned int vdso32_enabled; +#endif /* * This is used to ensure we don't load something for the wrong architecture.
@@ -269,9 +274,9 @@ extern int force_personality32;struct task_struct ; -#define ARCH_DLINFO_IA32 (vdso_enabled) \ +#define ARCH_DLINFO_IA32 \ do { \ - if (vdso_enabled) { \ + if (vdso32_enabled) { \ NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \ NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \ } \
@@ -281,7 +286,7 @@ do { \#define STACK_RND_MASK (0x7ff) -#define ARCH_DLINFO ARCH_DLINFO_IA32(vdso_enabled) +#define ARCH_DLINFO ARCH_DLINFO_IA32/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
@@ -292,14 +297,15 @@ do { \#define ARCH_DLINFO \ do { \ - if (vdso_enabled) \ + if (vdso64_enabled) \ NEW_AUX_ENT(AT_SYSINFO_EHDR, \ (unsigned long)current->mm->context.vdso); \ } while (0) +/* As a historical oddity, the x32 and x86_64 vDSOs are controlled together. */ #define ARCH_DLINFO_X32 \ do { \ - if (vdso_enabled) \ + if (vdso64_enabled) \ NEW_AUX_ENT(AT_SYSINFO_EHDR, \ (unsigned long)current->mm->context.vdso); \ } while (0)
@@ -310,7 +316,7 @@ do { \if (test_thread_flag (TIF_X32 )) \ARCH_DLINFO_X32 ; \else \ - ARCH_DLINFO_IA32(sysctl_vsyscall32) + ARCH_DLINFO_IA32#define COMPAT_ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000)
arch/x86/um/vdso/vma.c +1 -1
@@ -12,7 +12,7 @@#include <asm/page.h> #include <linux/init.h> -unsigned int __read_mostly vdso_enabled =1 ; +static unsigned int __read_mostly vdso_enabled =1 ;unsigned long um_vdso_addr;extern unsigned long task_size;
arch/x86/vdso/vdso32-setup.c +8 -11
@@ -37,7 +37,6 @@#endif #ifdef CONFIG_X86_64 -#define vdso_enabled sysctl_vsyscall32#define arch_setup_additional_pages syscall32_setup_pages#endif
@@ -45,13 +44,13 @@* Should the kernel map a VDSO page into processes and pass its * address down to glibc upon exec()? */ -unsigned int __read_mostly vdso_enabled =VDSO_DEFAULT ; +unsigned int __read_mostly vdso32_enabled =VDSO_DEFAULT ; -static int __init vdso_setup (char *s) +static int __init vdso32_setup (char *s) { - vdso_enabled =simple_strtoul (s,NULL ,0 ); + vdso32_enabled =simple_strtoul (s,NULL ,0 ); -if (vdso_enabled >1 ) +if (vdso32_enabled >1 )pr_warn ("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled\n" );return 1 ;
@@ -62,12 +61,10 @@ static int __init vdso_setup(char *s)* behavior on both 64-bit and 32-bit kernels. * On 32-bit kernels, vdso=[012] means the same thing. */ -__setup ("vdso32=" , vdso_setup); +__setup ("vdso32=" , vdso32_setup);#ifdef CONFIG_X86_32 -__setup_param ("vdso=" , vdso32_setup, vdso_setup,0 ); - -EXPORT_SYMBOL_GPL (vdso_enabled); +__setup_param ("vdso=" , vdso_setup, vdso32_setup,0 );#endif static struct page **vdso32_pages;
@@ -160,7 +157,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)return x32_setup_additional_pages (bprm, uses_interp);#endif -if (vdso_enabled !=1 )/* Other values all mean "disabled" */ +if (vdso32_enabled !=1 )/* Other values all mean "disabled" */ return 0 ;down_write (&mm->mmap_sem);
@@ -244,7 +241,7 @@ subsys_initcall(sysenter_setup);static struct ctl_table abi_table2[] = { { .procname ="vsyscall32" , - .data = &sysctl_vsyscall32, + .data = &vdso32_enabled, .maxlen =sizeof (int ), .mode =0644 , .proc_handler = proc_dointvec
arch/x86/vdso/vma.c +3 -3
@@ -17,7 +17,7 @@#include <asm/page.h> #if defined(CONFIG_X86_64 ) -unsigned int __read_mostly vdso_enabled =1 ; +unsigned int __read_mostly vdso64_enabled =1 ;DECLARE_VDSO_IMAGE (vdso);extern unsigned short vdso_sync_cpuid;
@@ -160,7 +160,7 @@ static int setup_additional_pages(struct linux_binprm *bprm,unsigned long addr;int ret; -if (!vdso_enabled) +if (!vdso64_enabled)return 0 ;down_write (&mm->mmap_sem);
@@ -203,7 +203,7 @@ int x32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)static __init int vdso_setup (char *s) { - vdso_enabled =simple_strtoul (s,NULL ,0 ); + vdso64_enabled =simple_strtoul (s,NULL ,0 );return 0 ; }__setup ("vdso=" , vdso_setup);
kernel/sysctl.c +5 -0
@@ -1418,8 +1418,13 @@ static struct ctl_table vm_table[] = { (defined (CONFIG_SUPERH ) &&defined (CONFIG_VSYSCALL )) { .procname ="vdso_enabled" , +#ifdef CONFIG_X86_32 + .data = &vdso32_enabled, + .maxlen = sizeof(vdso32_enabled), +#else .data = &vdso_enabled, .maxlen = sizeof(vdso_enabled), +#endif .mode =0644 , .proc_handler = proc_dointvec, .extra1 = &zero,
Signature · 1 line
1.9.0
PATCH v3 2/6 x86: Move syscall and sysenter setup into kernel/cpu/common.c
In reply to Andy LutomirskiThis just moves code around.
--- arch/x86/include/asm/proto.h | 2 -- arch/x86/kernel/cpu/common.c | 32 ++++++++++++++++++++++++++++++++ arch/x86/vdso/vdso32-setup.c | 30 ------------------------------ 3 files changed, 32 insertions(+), 32 deletions(-)
arch/x86/include/asm/proto.h +0 -2
@@ -12,8 +12,6 @@ void ia32_syscall(void);void ia32_cstar_target (void );void ia32_sysenter_target (void ); -void syscall32_cpu_init (void ); -void x86_configure_nx (void );void x86_report_nx (void );
arch/x86/kernel/cpu/common.c +32 -0
@@ -953,6 +953,38 @@ static void vgetcpu_set_mode(void) else vgetcpu_mode = VGETCPU_LSL; } + +/* May not be __init: called during resume */ +static void syscall32_cpu_init (void ) +{ +/* Load these always in case some future AMD CPU supports +SYSENTER from compat mode too. */ +wrmsrl_safe (MSR_IA32_SYSENTER_CS , (u64 )__KERNEL_CS); +wrmsrl_safe (MSR_IA32_SYSENTER_ESP ,0ULL ); +wrmsrl_safe (MSR_IA32_SYSENTER_EIP , (u64 )ia32_sysenter_target); + +wrmsrl (MSR_CSTAR , ia32_cstar_target); +} +#endif + +#ifdef CONFIG_X86_32 +void enable_sep_cpu (void ) +{ +int cpu =get_cpu (); +struct tss_struct *tss = &per_cpu (init_tss, cpu); + +if (!boot_cpu_has (X86_FEATURE_SEP )) { +put_cpu (); +return ; + } + + tss->x86_tss.ss1 = __KERNEL_CS; + tss->x86_tss.sp1 =sizeof (struct tss_struct ) + (unsigned long ) tss; +wrmsr (MSR_IA32_SYSENTER_CS , __KERNEL_CS,0 ); +wrmsr (MSR_IA32_SYSENTER_ESP , tss->x86_tss.sp1,0 ); +wrmsr (MSR_IA32_SYSENTER_EIP , (unsigned long ) ia32_sysenter_target,0 ); +put_cpu (); +}#endif void __init identify_boot_cpu (void )
arch/x86/vdso/vdso32-setup.c +0 -30
@@ -75,41 +75,11 @@ static unsigned vdso32_size;#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 ) -{ -/* Load these always in case some future AMD CPU supports -SYSENTER from compat mode too. */ -wrmsrl_safe (MSR_IA32_SYSENTER_CS , (u64 )__KERNEL_CS); -wrmsrl_safe (MSR_IA32_SYSENTER_ESP ,0ULL ); -wrmsrl_safe (MSR_IA32_SYSENTER_EIP , (u64 )ia32_sysenter_target); - -wrmsrl (MSR_CSTAR , ia32_cstar_target); -} -#else /* CONFIG_X86_32 */ #define vdso32_sysenter () (boot_cpu_has(X86_FEATURE_SEP))#define vdso32_syscall () (0) -void enable_sep_cpu (void ) -{ -int cpu =get_cpu (); -struct tss_struct *tss = &per_cpu (init_tss, cpu); - -if (!boot_cpu_has (X86_FEATURE_SEP )) { -put_cpu (); -return ; - } - - tss->x86_tss.ss1 = __KERNEL_CS; - tss->x86_tss.sp1 =sizeof (struct tss_struct ) + (unsigned long ) tss; -wrmsr (MSR_IA32_SYSENTER_CS , __KERNEL_CS,0 ); -wrmsr (MSR_IA32_SYSENTER_ESP , tss->x86_tss.sp1,0 ); -wrmsr (MSR_IA32_SYSENTER_EIP , (unsigned long ) ia32_sysenter_target,0 ); -put_cpu (); -} -#endif /* CONFIG_X86_64 */ int __init sysenter_setup (void )
Signature · 1 line
1.9.0
H. Peter Anvin
reviewerRe: [PATCH v3 2/6] x86: Move syscall and sysenter setup into kernel/cpu/common.c
Quoted 3 lines · Andy Lutomirski
This just moves code around.
Signed-off-by Andy Lutomirski <[email protected]>
One more thing: please explain *why* here.
-hpa
PATCH v3 3/6 x86: Reimplement vdso.so preparation in build-time C
In reply to Andy LutomirskiCurrently, vdso.so files are prepared and analyzed by a combination of objcopy, nm, some linker script tricks, and some simple ELF parsers in the kernel. Replace all of that with plain C code that runs at build time.
All five vdso images now generate .c files that are compiled and linked in to the kernel image.
This should cause only one userspace-visible change: the loaded vDSO images are stripped more heavily than they used to be. Everything outside the loadable segment is dropped. In particular, this causes the section table and section name strings to be missing. This should be fine: real dynamic loaders don't load or inspect these tables anyway. The result is roughly equivalent to eu-strip's --strip-sections option.
The purpose of this change is to enable the vvar and hpet mappings to be moved to the page following the vDSO load segment. Currently, it is possible for the section table to extend into the page after the load segment, so, if we map it, it risks overlapping the vvar or hpet page. This happens whenever the load segment is just under a multiple of PAGE_SIZE.
The only real subtlety here is that the old code had a C file with inline assembler that did 'call VDSO32_vsyscall' and a linker script that defined 'VDSO32_vsyscall = __kernel_vsyscall'. This most likely worked by accident: the linker script entry defines a symbol associated with an address as opposed to an alias for the real dynamic symbol __kernel_vsyscall. That caused ld to relocate the reference at link time instead of leaving an interposable dynamic relocation. Since the VDSO32_vsyscall hack is no longer needed, I now use 'call __kernel_vsyscall', and I added -Bsymbolic to make it work. vdso2c will generate an error and abort the build if the resulting image contains any dynamic relocations, so we won't silently generate bad vdso images.
(Dynamic relocations are a problem because nothing will even attempt to relocate the vdso.)
--- arch/x86/ia32/ia32_signal.c | 8 +-- arch/x86/include/asm/elf.h | 7 +- arch/x86/include/asm/mmu.h | 2 +- arch/x86/include/asm/vdso.h | 70 +++++++------------ arch/x86/kernel/signal.c | 6 +- arch/x86/mm/init_64.c | 3 +- arch/x86/vdso/.gitignore | 5 +- arch/x86/vdso/Makefile | 90 +++++++++--------------- arch/x86/vdso/vclock_gettime.c | 4 +- arch/x86/vdso/vdso.S | 3 - arch/x86/vdso/vdso2c.c | 142 ++++++++++++++++++++++++++++++++++++++ arch/x86/vdso/vdso2c.h | 137 ++++++++++++++++++++++++++++++++++++ arch/x86/vdso/vdso32-setup.c | 50 ++++++-------- arch/x86/vdso/vdso32.S | 9 --- arch/x86/vdso/vdso32/vdso32.lds.S | 10 --- arch/x86/vdso/vdsox32.S | 3 - arch/x86/vdso/vma.c | 100 +++++---------------------- arch/x86/xen/setup.c | 11 ++- 18 files changed, 400 insertions(+), 260 deletions(-) delete mode 100644 arch/x86/vdso/vdso.S create mode 100644 arch/x86/vdso/vdso2c.c create mode 100644 arch/x86/vdso/vdso2c.h delete mode 100644 arch/x86/vdso/vdso32.S delete mode 100644 arch/x86/vdso/vdsox32.S
arch/x86/ia32/ia32_signal.c +4 -4
@@ -383,8 +383,8 @@ int ia32_setup_frame(int sig, struct ksignal *ksig, }else {/* Return stub is in 32bit vsyscall page */ if (current->mm->context.vdso) - restorer =VDSO32_SYMBOL (current->mm->context.vdso, - sigreturn); + restorer = current->mm->context.vdso + + selected_vdso32->sym___kernel_sigreturn;else restorer = &frame->retcode; }
@@ -462,8 +462,8 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,if (ksig->ka.sa.sa_flags &SA_RESTORER ) restorer = ksig->ka.sa.sa_restorer;else - restorer =VDSO32_SYMBOL (current->mm->context.vdso, - rt_sigreturn); + restorer = current->mm->context.vdso + + selected_vdso32->sym___kernel_rt_sigreturn;put_user_ex (ptr_to_compat (restorer), &frame->pretcode);/*
arch/x86/include/asm/elf.h +4 -3
@@ -299,7 +299,7 @@ do { \do { \if (vdso64_enabled) \NEW_AUX_ENT (AT_SYSINFO_EHDR , \ - (unsigned long )current->mm->context.vdso); \ + (unsigned long __force )current->mm->context.vdso); \ }while (0 )/* As a historical oddity, the x32 and x86_64 vDSOs are controlled together. */
@@ -307,7 +307,7 @@ do { \do { \if (vdso64_enabled) \NEW_AUX_ENT (AT_SYSINFO_EHDR , \ - (unsigned long )current->mm->context.vdso); \ + (unsigned long __force )current->mm->context.vdso); \ } while (0)#define AT_SYSINFO 32
@@ -325,7 +325,8 @@ else \#define VDSO_CURRENT_BASE ((unsigned long)current->mm->context.vdso)#define VDSO_ENTRY \ - ((unsigned long)VDSO32_SYMBOL(VDSO_CURRENT_BASE, vsyscall)) + ((unsigned long)current->mm->context.vdso + \ + selected_vdso32->sym___kernel_vsyscall)struct linux_binprm ;
arch/x86/include/asm/mmu.h +1 -1
@@ -18,7 +18,7 @@ typedef struct {#endif struct mutex lock; -void *vdso; +void __user *vdso; } mm_context_t;#ifdef CONFIG_SMP
arch/x86/include/asm/vdso.h +25 -45
88 lines not on this page · raw message
arch/x86/kernel/signal.c +4 -2
@@ -298,7 +298,8 @@ __setup_frame(int sig, struct ksignal *ksig, sigset_t *set, }if (current->mm->context.vdso) - restorer =VDSO32_SYMBOL (current->mm->context.vdso, sigreturn); + restorer = current->mm->context.vdso + + selected_vdso32->sym___kernel_sigreturn;else restorer = &frame->retcode;if (ksig->ka.sa.sa_flags &SA_RESTORER )
@@ -361,7 +362,8 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,save_altstack_ex (&frame->uc.uc_stack, regs->sp);/* Set up to return from userspace. */ - restorer =VDSO32_SYMBOL (current->mm->context.vdso, rt_sigreturn); + restorer = current->mm->context.vdso + + selected_vdso32->sym___kernel_sigreturn;if (ksig->ka.sa.sa_flags &SA_RESTORER ) restorer = ksig->ka.sa.sa_restorer;put_user_ex (restorer, &frame->pretcode);
arch/x86/mm/init_64.c +2 -1
@@ -1223,7 +1223,8 @@ int in_gate_area_no_mm(unsigned long addr)const char *arch_vma_name (struct vm_area_struct *vma) { -if (vma->vm_mm && vma->vm_start == (long )vma->vm_mm->context.vdso) +if (vma->vm_mm && vma->vm_start == + (long __force )vma->vm_mm->context.vdso)return "[vdso]" ;if (vma == &gate_vma)return "[vsyscall]" ;
arch/x86/vdso/.gitignore +2 -3
@@ -1,8 +1,7 @@ vdso.lds -vdso-syms.lds vdsox32.lds -vdsox32-syms.lds -vdso32-syms.lds vdso32-syscall-syms.lds vdso32-sysenter-syms.lds vdso32-int80-syms.lds +vdso-image-*.c +vdso2c
arch/x86/vdso/Makefile +32 -58
152 lines not on this page · raw message
arch/x86/vdso/vclock_gettime.c +2 -2
@@ -154,7 +154,7 @@ notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) asm("mov %%ebx, %%edx \n" "mov %2, %%ebx \n" -"call VDSO32_vsyscall \n" +"call __kernel_vsyscall \n" "mov %%edx, %%ebx \n" :"=a" (ret) : "0" (__NR_clock_gettime), "g" (clock), "c" (ts)
@@ -169,7 +169,7 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz) asm("mov %%ebx, %%edx \n" "mov %2, %%ebx \n" -"call VDSO32_vsyscall \n" +"call __kernel_vsyscall \n" "mov %%edx, %%ebx \n" :"=a" (ret) : "0" (__NR_gettimeofday), "g" (tv), "c" (tz)
arch/x86/vdso/vdso.S deleted +0 -3
@@ -1,3 +0,0 @@ -#include <asm/vdso.h> - -DEFINE_VDSO_IMAGE(vdso, "arch/x86/vdso/vdso.so")
arch/x86/vdso/vdso2c.c new file +142 -0
142 lines not on this page · raw message
arch/x86/vdso/vdso2c.h new file +137 -0
137 lines not on this page · raw message
arch/x86/vdso/vdso32-setup.c +20 -30
97 lines not on this page · raw message
arch/x86/vdso/vdso32.S deleted +0 -9
@@ -1,9 +0,0 @@ -#include <asm/vdso.h> - -DEFINE_VDSO_IMAGE(vdso32_int80, "arch/x86/vdso/vdso32-int80.so") - -#ifdef CONFIG_COMPAT -DEFINE_VDSO_IMAGE(vdso32_syscall, "arch/x86/vdso/vdso32-syscall.so") -#endif - -DEFINE_VDSO_IMAGE(vdso32_sysenter, "arch/x86/vdso/vdso32-sysenter.so")
arch/x86/vdso/vdso32/vdso32.lds.S +0 -10
@@ -38,13 +38,3 @@ VERSION local: *; }; } - -/* - * Symbols we define here called VDSO* get their values into vdso32-syms.h. - */ -VDSO32_vsyscall = __kernel_vsyscall; -VDSO32_sigreturn = __kernel_sigreturn; -VDSO32_rt_sigreturn = __kernel_rt_sigreturn; -VDSO32_clock_gettime = clock_gettime; -VDSO32_gettimeofday = gettimeofday; -VDSO32_time = time;
arch/x86/vdso/vdsox32.S deleted +0 -3
@@ -1,3 +0,0 @@ -#include <asm/vdso.h> - -DEFINE_VDSO_IMAGE(vdsox32, "arch/x86/vdso/vdsox32.so")
arch/x86/vdso/vma.c +16 -84
137 lines not on this page · raw message
arch/x86/xen/setup.c +9 -2
@@ -516,10 +516,17 @@ char * __init xen_memory_setup(void)static void __init fiddle_vdso (void ) {#ifdef CONFIG_X86_32 +/* +* This could be called before selected_vdso32 is initialized, so +* just fiddle with both possible images. vdso_image_32_syscall +* can't be selected, since it only exists on 64-bit systems. +*/ u32 *mask; - mask =VDSO32_SYMBOL (&vdso32_int80_start,NOTE_MASK ); + mask = vdso_image_32_int80.data + + vdso_image_32_int80.sym_VDSO32_NOTE_MASK; *mask |=1 <<VDSO_NOTE_NONEGSEG_BIT ; - mask =VDSO32_SYMBOL (&vdso32_sysenter_start,NOTE_MASK ); + mask = vdso_image_32_sysenter.data + + vdso_image_32_sysenter.sym_VDSO32_NOTE_MASK; *mask |=1 <<VDSO_NOTE_NONEGSEG_BIT ;#endif }
Signature · 1 line
1.9.0
PATCH v3 4/6 x86: Move the 32-bit vdso special pages after the text
In reply to Andy LutomirskiThis unifies the vdso mapping code and teaches it how to map special pages at addresses corresponding to symbols in the vdso image. The new code is used for all vdso variants, but so far only the 32-bit variants use the new vvar page position.
--- arch/x86/include/asm/elf.h | 8 +-- arch/x86/include/asm/vdso.h | 4 ++ arch/x86/include/asm/vdso32.h | 11 ---- arch/x86/vdso/vdso-layout.lds.S | 42 ++++++++----- arch/x86/vdso/vdso2c.c | 14 +++++ arch/x86/vdso/vdso2c.h | 17 ++++++ arch/x86/vdso/vdso32-setup.c | 115 +----------------------------------- arch/x86/vdso/vma.c | 128 +++++++++++++++++++++++++++++++++------- 8 files changed, 173 insertions(+), 166 deletions(-) delete mode 100644 arch/x86/include/asm/vdso32.h
arch/x86/include/asm/elf.h +3 -5
@@ -333,11 +333,9 @@ struct linux_binprm;#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1extern int arch_setup_additional_pages (struct linux_binprm *bprm,int uses_interp); -extern int x32_setup_additional_pages (struct linux_binprm *bprm, -int uses_interp); - -extern int syscall32_setup_pages (struct linux_binprm *,int exstack); -#define compat_arch_setup_additional_pages syscall32_setup_pages +extern int compat_arch_setup_additional_pages (struct linux_binprm *bprm, +int uses_interp); +#define compat_arch_setup_additional_pages compat_arch_setup_additional_pagesextern unsigned long arch_randomize_brk (struct mm_struct *mm);#define arch_randomize_brk arch_randomize_brk
arch/x86/include/asm/vdso.h +4 -0
@@ -14,6 +14,10 @@ struct vdso_image {unsigned long alt, alt_len; +unsigned long sym_end_mapping;/* Total size of the mapping */ + +unsigned long sym_vvar_page; +unsigned long sym_hpet_page;unsigned long sym_VDSO32_NOTE_MASK;unsigned long sym___kernel_sigreturn;unsigned long sym___kernel_rt_sigreturn;
arch/x86/include/asm/vdso32.h deleted +0 -11
@@ -1,11 +0,0 @@ -#ifndef _ASM_X86_VDSO32_H -#define _ASM_X86_VDSO32_H - -#define VDSO_BASE_PAGE 0 -#define VDSO_VVAR_PAGE 1 -#define VDSO_HPET_PAGE 2 -#define VDSO_PAGES 3 -#define VDSO_PREV_PAGES 2 -#define VDSO_OFFSET (x) ((x) * PAGE_SIZE) - -#endif
arch/x86/vdso/vdso-layout.lds.S +26 -16
60 lines not on this page · raw message
arch/x86/vdso/vdso2c.c +14 -0
@@ -15,7 +15,21 @@#include <linux/types.h> /* Symbols that we need in vdso2c. */ +enum { + sym_vvar_page, + sym_hpet_page, + sym_end_mapping, +}; + +const int special_pages[] = { + sym_vvar_page, + sym_hpet_page, +}; +char const *const required_syms[] = { + [sym_vvar_page] ="vvar_page" , + [sym_hpet_page] ="hpet_page" , + [sym_end_mapping] ="end_mapping" ,"VDSO32_NOTE_MASK" ,"VDSO32_SYSENTER_RETURN" ,"__kernel_vsyscall" ,
arch/x86/vdso/vdso2c.h +17 -0
@@ -87,6 +87,23 @@ static int GOFUNC(void *addr, size_t len, FILE *outfile, const char *name) } } +/* Validate mapping addresses. */ +for (i =0 ; i <sizeof (special_pages) /sizeof (special_pages[0 ]); i++) { +if (!syms[i]) +continue ;/* The mapping isn't used; ignore it. */ + +if (syms[i] %4096 ) +fail ("%s must be a multiple of 4096\n" , + required_syms[i]); +if (syms[i] < data_size) +fail ("%s must be after the text mapping\n" , + required_syms[i]); +if (syms[sym_end_mapping] < syms[i] +4096 ) +fail ("%s overruns end_mapping\n" , required_syms[i]); + } +if (syms[sym_end_mapping] %4096 ) +fail ("end_mapping must be a multiple of 4096\n" ); +/* Remove sections. */ hdr->e_shoff =0 ; hdr->e_shentsize =0 ;
arch/x86/vdso/vdso32-setup.c +3 -112
136 lines not on this page · raw message
arch/x86/vdso/vma.c +106 -22
189 lines not on this page · raw message
Signature · 1 line
1.9.0
PATCH v3 5/6 x86: Move the vvar and hpet mappings next to the 64-bit vDSO
In reply to Andy LutomirskiThis makes the 64-bit and x32 vdsos use the same mechanism as the 32-bit vdso. Most of the churn is deleting all the old fixmap code.
--- arch/x86/include/asm/fixmap.h | 10 +++------- arch/x86/include/asm/vvar.h | 20 +------------------- arch/x86/include/uapi/asm/vsyscall.h | 7 +------ arch/x86/kernel/cpu/common.c | 1 + arch/x86/kernel/hpet.c | 3 --- arch/x86/kernel/vsyscall_64.c | 15 ++++----------- arch/x86/mm/fault.c | 5 +++-- arch/x86/mm/init_64.c | 10 +++++----- arch/x86/vdso/vclock_gettime.c | 22 +++++----------------- arch/x86/vdso/vdso-layout.lds.S | 2 -- arch/x86/xen/mmu.c | 8 +++----- 11 files changed, 26 insertions(+), 77 deletions(-)
arch/x86/include/asm/fixmap.h +3 -7
@@ -24,7 +24,7 @@#include <linux/threads.h> #include <asm/kmap_types.h> #else -#include <asm/vsyscall.h> +#include <uapi/asm/vsyscall.h> #endif /*
@@ -41,7 +41,7 @@extern unsigned long __FIXADDR_TOP;#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP)#else -#define FIXADDR_TOP (VSYSCALL_END-PAGE_SIZE) +#define FIXADDR_TOP (VSYSCALL_ADDR)#endif
@@ -68,11 +68,7 @@ enum fixed_addresses {#ifdef CONFIG_X86_32 FIX_HOLE, #else -VSYSCALL_LAST_PAGE , -VSYSCALL_FIRST_PAGE =VSYSCALL_LAST_PAGE - + ((VSYSCALL_END -VSYSCALL_START ) >>PAGE_SHIFT ) -1 , -VVAR_PAGE , -VSYSCALL_HPET , + VSYSCALL_PAGE,#ifdef CONFIG_PARAVIRT_CLOCK PVCLOCK_FIXMAP_BEGIN , PVCLOCK_FIXMAP_END = PVCLOCK_FIXMAP_BEGIN+PVCLOCK_VSYSCALL_NR_PAGES-1,
arch/x86/include/asm/vvar.h +1 -19
@@ -29,31 +29,13 @@#else -#ifdef BUILD_VDSO32 +extern char __vvar_page;#define DECLARE_VVAR (offset, type, name) \ extern type vvar_ ## name __attribute__((visibility("hidden")));#define VVAR (name) (vvar_ ## name) -#else - -extern char __vvar_page; - -/* Base address of vvars. This is not ABI. */ -#ifdef CONFIG_X86_64 -#define VVAR_ADDRESS (-10*1024*1024 - 4096) -#else -#define VVAR_ADDRESS (&__vvar_page) -#endif - -#define DECLARE_VVAR (offset, type, name) \ - static type const * const vvaraddr_ ## name = \ - (void *)(VVAR_ADDRESS + (offset)); - -#define VVAR (name) (*vvaraddr_ ## name) -#endif -#define DEFINE_VVAR (type, name) \ type name \ __attribute__((section(".vvar_" #name), aligned(16))) __visible
arch/x86/include/uapi/asm/vsyscall.h +1 -6
@@ -7,11 +7,6 @@ enum vsyscall_num { __NR_vgetcpu, }; -#define VSYSCALL_START (-10UL << 20) -#define VSYSCALL_SIZE 1024 -#define VSYSCALL_END (-2UL << 20) -#define VSYSCALL_MAPPED_PAGES 1 -#define VSYSCALL_ADDR (vsyscall_nr) (VSYSCALL_START+VSYSCALL_SIZE*(vsyscall_nr)) - +#define VSYSCALL_ADDR (-10UL << 20)#endif /* _UAPI_ASM_X86_VSYSCALL_H */
arch/x86/kernel/cpu/common.c +1 -0
@@ -20,6 +20,7 @@#include <asm/processor.h> #include <asm/debugreg.h> #include <asm/sections.h> +#include <asm/vsyscall.h> #include <linux/topology.h> #include <linux/cpumask.h> #include <asm/pgtable.h>
arch/x86/kernel/hpet.c +0 -3
@@ -74,9 +74,6 @@ static inline void hpet_writel(unsigned int d, unsigned int a)static inline void hpet_set_mapping (void ) { hpet_virt_address =ioremap_nocache (hpet_address,HPET_MMAP_SIZE ); -#ifdef CONFIG_X86_64 -__set_fixmap (VSYSCALL_HPET , hpet_address,PAGE_KERNEL_VVAR_NOCACHE ); -#endif }static inline void hpet_clear_mapping (void )
arch/x86/kernel/vsyscall_64.c +4 -11
@@ -91,7 +91,7 @@ static int addr_to_vsyscall_nr(unsigned long addr) {int nr; -if ((addr & ~0xC00UL ) !=VSYSCALL_START ) +if ((addr & ~0xC00UL ) !=VSYSCALL_ADDR )return -EINVAL ; nr = (addr &0xC00UL ) >>10 ;
@@ -330,24 +330,17 @@ void __init map_vsyscall(void) {extern char __vsyscall_page;unsigned long physaddr_vsyscall =__pa_symbol (&__vsyscall_page); -unsigned long physaddr_vvar_page =__pa_symbol (&__vvar_page); -__set_fixmap (VSYSCALL_FIRST_PAGE , physaddr_vsyscall, +__set_fixmap (VSYSCALL_PAGE , physaddr_vsyscall, vsyscall_mode ==NATIVE ?PAGE_KERNEL_VSYSCALL :PAGE_KERNEL_VVAR ); -BUILD_BUG_ON ((unsigned long )__fix_to_virt (VSYSCALL_FIRST_PAGE ) != - (unsigned long )VSYSCALL_START ); - -__set_fixmap (VVAR_PAGE , physaddr_vvar_page,PAGE_KERNEL_VVAR ); -BUILD_BUG_ON ((unsigned long )__fix_to_virt (VVAR_PAGE ) != - (unsigned long )VVAR_ADDRESS ); +BUILD_BUG_ON ((unsigned long )__fix_to_virt (VSYSCALL_PAGE ) != + (unsigned long )VSYSCALL_ADDR ); }static int __init vsyscall_init (void ) { -BUG_ON (VSYSCALL_ADDR (0 ) !=__fix_to_virt (VSYSCALL_FIRST_PAGE )); -cpu_notifier_register_begin ();on_each_cpu (cpu_vsyscall_init,NULL ,1 );
arch/x86/mm/fault.c +3 -2
@@ -18,7 +18,8 @@#include <asm/traps.h> /* dotraplinkage, ... */ #include <asm/pgalloc.h> /* pgd_*(), ... */ #include <asm/kmemcheck.h> /* kmemcheck_*(), ... */ -#include <asm/fixmap.h> /* VSYSCALL_START */ +#include <asm/fixmap.h> /* VSYSCALL_ADDR */ +#include <asm/vsyscall.h> /* emulate_vsyscall */ #define CREATE_TRACE_POINTS #include <asm/trace/exceptions.h>
@@ -771,7 +772,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,* emulation. */ if (unlikely ((error_code &PF_INSTR ) && - ((address & ~0xfff ) ==VSYSCALL_START ))) { + ((address & ~0xfff ) ==VSYSCALL_ADDR ))) {if (emulate_vsyscall (regs, address))return ; }
arch/x86/mm/init_64.c +5 -5
@@ -1055,8 +1055,8 @@ void __init mem_init(void) after_bootmem =1 ;/* Register memory areas for /proc/kcore */ -kclist_add (&kcore_vsyscall, (void *)VSYSCALL_START , -VSYSCALL_END -VSYSCALL_START ,KCORE_OTHER ); +kclist_add (&kcore_vsyscall, (void *)VSYSCALL_ADDR , +PAGE_SIZE ,KCORE_OTHER );mem_init_print_info (NULL ); }
@@ -1186,8 +1186,8 @@ int kern_addr_valid(unsigned long addr)* not need special handling anymore: */ static struct vm_area_struct gate_vma = { - .vm_start =VSYSCALL_START , - .vm_end =VSYSCALL_START + (VSYSCALL_MAPPED_PAGES *PAGE_SIZE ), + .vm_start =VSYSCALL_ADDR , + .vm_end =VSYSCALL_ADDR +PAGE_SIZE , .vm_page_prot =PAGE_READONLY_EXEC , .vm_flags =VM_READ |VM_EXEC };
@@ -1218,7 +1218,7 @@ int in_gate_area(struct mm_struct *mm, unsigned long addr)*/ int in_gate_area_no_mm (unsigned long addr) { -return (addr >=VSYSCALL_START ) && (addr <VSYSCALL_END ); +return (addr &PAGE_MASK ) ==VSYSCALL_ADDR ; }const char *arch_vma_name (struct vm_area_struct *vma)
arch/x86/vdso/vclock_gettime.c +5 -17
@@ -30,9 +30,12 @@ extern int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz);extern time_t __vdso_time (time_t *t);#ifdef CONFIG_HPET_TIMER -static inline u32 read_hpet_counter (const volatile void *addr) +extern u8 hpet_page + __attribute__((visibility("hidden"))); + +static notrace cycle_t vread_hpet(void) { -return *(const volatile u32 *) (addr +HPET_COUNTER ); +return *(const volatile u32 *)(&hpet_page +HPET_COUNTER ); }#endif
@@ -43,11 +46,6 @@ static inline u32 read_hpet_counter(const volatile void *addr)#include <asm/fixmap.h> #include <asm/pvclock.h> -static notrace cycle_t vread_hpet(void) -{ -return read_hpet_counter ((const void *)fix_to_virt (VSYSCALL_HPET )); -} - notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) {long ret;
@@ -137,16 +135,6 @@ static notrace cycle_t vread_pvclock(int *mode)#else -extern u8 hpet_page - __attribute__((visibility("hidden"))); - -#ifdef CONFIG_HPET_TIMER -static notrace cycle_t vread_hpet(void) -{ -return read_hpet_counter ((const void *)(&hpet_page)); -} -#endif - notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) {long ret;
arch/x86/vdso/vdso-layout.lds.S +0 -2
@@ -47,7 +47,6 @@ SECTIONS .text : { *(.text*) } :text =0x90909090, -#ifdef BUILD_VDSO32 /* * The remainder of the vDSO consists of special pages that are * shared between the kernel and userspace. It needs to be at the
@@ -69,7 +68,6 @@ SECTIONS hpet_page = .; . = . + PAGE_SIZE; -#endif . = ALIGN(PAGE_SIZE); end_mapping = .;
arch/x86/xen/mmu.c +3 -5
@@ -1494,7 +1494,7 @@ static int xen_pgd_alloc(struct mm_struct *mm) page->private = (unsigned long )user_pgd;if (user_pgd !=NULL ) { - user_pgd[pgd_index (VSYSCALL_START )] = + user_pgd[pgd_index (VSYSCALL_ADDR )] =__pgd (__pa (level3_user_vsyscall) | _PAGE_TABLE); ret =0 ; }
@@ -2062,8 +2062,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) case FIX_KMAP_BEGIN ... FIX_KMAP_END:# endif #else - case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE: -case VVAR_PAGE : +case VSYSCALL_PAGE :#endif case FIX_TEXT_POKE0 :case FIX_TEXT_POKE1 :
@@ -2104,8 +2103,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)#ifdef CONFIG_X86_64 /* Replicate changes to map the vsyscall page into the user pagetable vsyscall mapping. */ -if ((idx >=VSYSCALL_LAST_PAGE && idx <=VSYSCALL_FIRST_PAGE ) || - idx ==VVAR_PAGE ) { +if (idx ==VSYSCALL_PAGE ) {unsigned long vaddr =__fix_to_virt (idx);set_pte_vaddr_pud (level3_user_vsyscall, vaddr, pte); }
Signature · 1 line
1.9.0
PATCH v3 6/6 x86: Remove vestiges of VDSO_PRELINK and some outdated comments
In reply to Andy LutomirskiThese definitions had no effect.
--- arch/x86/vdso/vdso.lds.S | 7 +------ arch/x86/vdso/vdso32/vdso32.lds.S | 5 +---- arch/x86/vdso/vdsox32.lds.S | 7 +------ 3 files changed, 3 insertions(+), 16 deletions(-)
arch/x86/vdso/vdso.lds.S +1 -6
@@ -1,14 +1,11 @@ /* * Linker script for 64-bit vDSO. * We #include the file to define the layout details. - * Here we only choose the prelinked virtual address. * * This file defines the version script giving the user-exported symbols in - * the DSO. We can define local symbols here called VDSO* to make their - * values visible using the asm-x86/vdso.h macros from the kernel proper. + * the DSO. */ -#define VDSO_PRELINK 0xffffffffff700000 #include "vdso-layout.lds.S" /*
@@ -28,5 +25,3 @@ VERSION { local: *; }; } - -VDSO64_PRELINK = VDSO_PRELINK;
arch/x86/vdso/vdso32/vdso32.lds.S +1 -4
@@ -1,17 +1,14 @@ /* * Linker script for 32-bit vDSO. * We #include the file to define the layout details. - * Here we only choose the prelinked virtual address. * * This file defines the version script giving the user-exported symbols in - * the DSO. We can define local symbols here called VDSO* to make their - * values visible using the asm-x86/vdso.h macros from the kernel proper. + * the DSO. */ #include <asm/page.h> #define BUILD_VDSO32 -#define VDSO_PRELINK 0 #include "../vdso-layout.lds.S"
arch/x86/vdso/vdsox32.lds.S +1 -6
@@ -1,14 +1,11 @@ /* * Linker script for x32 vDSO. * We #include the file to define the layout details. - * Here we only choose the prelinked virtual address. * * This file defines the version script giving the user-exported symbols in - * the DSO. We can define local symbols here called VDSO* to make their - * values visible using the asm-x86/vdso.h macros from the kernel proper. + * the DSO. */ -#define VDSO_PRELINK 0 #include "vdso-layout.lds.S" /*
@@ -24,5 +21,3 @@ VERSION { local: *; }; } - -VDSOX32_PRELINK = VDSO_PRELINK;
Signature · 1 line
1.9.0