diff options
Diffstat (limited to 'sys/i386/linux/linux_sysvec.c')
-rw-r--r-- | sys/i386/linux/linux_sysvec.c | 65 |
1 files changed, 54 insertions, 11 deletions
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c index 970bd05..730e7ef 100644 --- a/sys/i386/linux/linux_sysvec.c +++ b/sys/i386/linux/linux_sysvec.c @@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$"); #include <compat/linux/linux_misc.h> #include <compat/linux/linux_signal.h> #include <compat/linux/linux_util.h> +#include <compat/linux/linux_vdso.h> MODULE_VERSION(linux, 1); @@ -93,8 +94,11 @@ MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); #define LINUX_PS_STRINGS (LINUX_USRSTACK - sizeof(struct ps_strings)) -extern char linux_sigcode[]; -extern int linux_szsigcode; +static int linux_szsigcode; +static vm_object_t linux_shared_page_obj; +static char *linux_shared_page_mapping; +extern char _binary_linux_locore_o_start; +extern char _binary_linux_locore_o_end; extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; @@ -110,6 +114,8 @@ static void exec_linux_setregs(struct thread *td, struct image_params *imgp, u_long stack); static register_t *linux_copyout_strings(struct image_params *imgp); static boolean_t linux_trans_osrel(const Elf_Note *note, int32_t *osrel); +static void linux_vdso_install(void *param); +static void linux_vdso_deinstall(void *param); static int linux_szplatform; const char *linux_platform; @@ -199,6 +205,10 @@ static int _bsd_to_linux_trapcode[] = { _bsd_to_linux_trapcode[(code)]: \ LINUX_T_UNKNOWN) +LINUX_VDSO_SYM_INTPTR(linux_sigcode); +LINUX_VDSO_SYM_INTPTR(linux_rt_sigcode); +LINUX_VDSO_SYM_INTPTR(linux_vsyscall); + /* * If FreeBSD & Linux have a difference of opinion about what a trap * means, deal with it here. @@ -255,6 +265,9 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp) args = (Elf32_Auxargs *)imgp->auxargs; pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2); + AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO_EHDR, + imgp->proc->p_sysent->sv_shared_page_base); + AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO, linux_vsyscall); AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature); /* @@ -399,10 +412,6 @@ linux_copyout_strings(struct image_params *imgp) return (stack_base); } - - -extern unsigned long linux_sznonrtsigcode; - static void linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { @@ -478,6 +487,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) frame.sf_sc.uc_mcontext.sc_esi = regs->tf_esi; frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_ebp; frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_ebx; + frame.sf_sc.uc_mcontext.sc_esp = regs->tf_esp; frame.sf_sc.uc_mcontext.sc_edx = regs->tf_edx; frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_ecx; frame.sf_sc.uc_mcontext.sc_eax = regs->tf_eax; @@ -515,7 +525,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) * Build context to run handler in. */ regs->tf_esp = (int)fp; - regs->tf_eip = p->p_sysent->sv_sigcode_base + linux_sznonrtsigcode; + regs->tf_eip = linux_rt_sigcode; regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D); regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; @@ -606,6 +616,7 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) frame.sf_sc.sc_esi = regs->tf_esi; frame.sf_sc.sc_ebp = regs->tf_ebp; frame.sf_sc.sc_ebx = regs->tf_ebx; + frame.sf_sc.sc_esp = regs->tf_esp; frame.sf_sc.sc_edx = regs->tf_edx; frame.sf_sc.sc_ecx = regs->tf_ecx; frame.sf_sc.sc_eax = regs->tf_eax; @@ -634,7 +645,7 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) * Build context to run handler in. */ regs->tf_esp = (int)fp; - regs->tf_eip = p->p_sysent->sv_sigcode_base; + regs->tf_eip = linux_sigcode; regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D); regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; @@ -950,7 +961,7 @@ struct sysentvec linux_sysvec = { .sv_transtrap = translate_traps, .sv_fixup = linux_fixup, .sv_sendsig = linux_sendsig, - .sv_sigcode = linux_sigcode, + .sv_sigcode = &_binary_linux_locore_o_start, .sv_szsigcode = &linux_szsigcode, .sv_prepsyscall = NULL, .sv_name = "Linux a.out", @@ -989,7 +1000,7 @@ struct sysentvec elf_linux_sysvec = { .sv_transtrap = translate_traps, .sv_fixup = elf_linux_fixup, .sv_sendsig = linux_sendsig, - .sv_sigcode = linux_sigcode, + .sv_sigcode = &_binary_linux_locore_o_start, .sv_szsigcode = &linux_szsigcode, .sv_prepsyscall = NULL, .sv_name = "Linux ELF", @@ -1015,7 +1026,39 @@ struct sysentvec elf_linux_sysvec = { .sv_schedtail = linux_schedtail, .sv_thread_detach = linux_thread_detach, }; -INIT_SYSENTVEC(elf_sysvec, &elf_linux_sysvec); + +static void +linux_vdso_install(void *param) +{ + + linux_szsigcode = (&_binary_linux_locore_o_end - + &_binary_linux_locore_o_start); + + if (linux_szsigcode > elf_linux_sysvec.sv_shared_page_len) + panic("Linux invalid vdso size\n"); + + __elfN(linux_vdso_fixup)(&elf_linux_sysvec); + + linux_shared_page_obj = __elfN(linux_shared_page_init) + (&linux_shared_page_mapping); + + __elfN(linux_vdso_reloc)(&elf_linux_sysvec, LINUX_SHAREDPAGE); + + bcopy(elf_linux_sysvec.sv_sigcode, linux_shared_page_mapping, + linux_szsigcode); + elf_linux_sysvec.sv_shared_page_obj = linux_shared_page_obj; +} +SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC, SI_ORDER_ANY, + (sysinit_cfunc_t)linux_vdso_install, NULL); + +static void +linux_vdso_deinstall(void *param) +{ + + __elfN(linux_shared_page_fini)(linux_shared_page_obj); +}; +SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST, + (sysinit_cfunc_t)linux_vdso_deinstall, NULL); static char GNU_ABI_VENDOR[] = "GNU"; static int GNULINUX_ABI_DESC = 0; |