Changeset View
Changeset View
Standalone View
Standalone View
sys/amd64/linux32/linux32_sysvec.c
Show First 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
#include <amd64/linux32/linux32_proto.h> | #include <amd64/linux32/linux32_proto.h> | ||||
#include <compat/linux/linux_emul.h> | #include <compat/linux/linux_emul.h> | ||||
#include <compat/linux/linux_futex.h> | #include <compat/linux/linux_futex.h> | ||||
#include <compat/linux/linux_ioctl.h> | #include <compat/linux/linux_ioctl.h> | ||||
#include <compat/linux/linux_mib.h> | #include <compat/linux/linux_mib.h> | ||||
#include <compat/linux/linux_misc.h> | #include <compat/linux/linux_misc.h> | ||||
#include <compat/linux/linux_signal.h> | #include <compat/linux/linux_signal.h> | ||||
#include <compat/linux/linux_util.h> | #include <compat/linux/linux_util.h> | ||||
#include <compat/linux/linux_vdso.h> | |||||
MODULE_VERSION(linux, 1); | MODULE_VERSION(linux, 1); | ||||
MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); | MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); | ||||
#define AUXARGS_ENTRY_32(pos, id, val) \ | #define AUXARGS_ENTRY_32(pos, id, val) \ | ||||
do { \ | do { \ | ||||
suword32(pos++, id); \ | suword32(pos++, id); \ | ||||
Show All 12 Lines | |||||
* to syscall 0. This is slightly less bogus than using | * to syscall 0. This is slightly less bogus than using | ||||
* ldebug(sigreturn). | * ldebug(sigreturn). | ||||
*/ | */ | ||||
#define LINUX_SYS_linux_rt_sendsig 0 | #define LINUX_SYS_linux_rt_sendsig 0 | ||||
#define LINUX_SYS_linux_sendsig 0 | #define LINUX_SYS_linux_sendsig 0 | ||||
const char *linux_platform = "i686"; | const char *linux_platform = "i686"; | ||||
static int linux_szplatform; | static int linux_szplatform; | ||||
extern char linux_sigcode[]; | static int linux_szsigcode; | ||||
extern int linux_szsigcode; | static vm_object_t linux_shared_page_obj; | ||||
static char *linux_shared_page_mapping; | |||||
extern char _binary_linux32_locore_o_start; | |||||
extern char _binary_linux32_locore_o_end; | |||||
extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; | extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; | ||||
SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); | SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); | ||||
SET_DECLARE(linux_device_handler_set, struct linux_device_handler); | SET_DECLARE(linux_device_handler_set, struct linux_device_handler); | ||||
static int elf_linux_fixup(register_t **stack_base, | static int elf_linux_fixup(register_t **stack_base, | ||||
struct image_params *iparams); | struct image_params *iparams); | ||||
static register_t *linux_copyout_strings(struct image_params *imgp); | static register_t *linux_copyout_strings(struct image_params *imgp); | ||||
static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); | static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); | ||||
static void exec_linux_setregs(struct thread *td, | static void exec_linux_setregs(struct thread *td, | ||||
struct image_params *imgp, u_long stack); | struct image_params *imgp, u_long stack); | ||||
static void linux32_fixlimit(struct rlimit *rl, int which); | static void linux32_fixlimit(struct rlimit *rl, int which); | ||||
static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel); | static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel); | ||||
static void linux_vdso_install(void *param); | |||||
static void linux_vdso_deinstall(void *param); | |||||
static eventhandler_tag linux_exec_tag; | static eventhandler_tag linux_exec_tag; | ||||
static eventhandler_tag linux_thread_dtor_tag; | static eventhandler_tag linux_thread_dtor_tag; | ||||
/* | /* | ||||
* Linux syscalls return negative errno's, we do positive and map them | * Linux syscalls return negative errno's, we do positive and map them | ||||
* Reference: | * Reference: | ||||
* FreeBSD: src/sys/sys/errno.h | * FreeBSD: src/sys/sys/errno.h | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | |||||
struct linux32_ps_strings { | struct linux32_ps_strings { | ||||
u_int32_t ps_argvstr; /* first of 0 or more argument strings */ | u_int32_t ps_argvstr; /* first of 0 or more argument strings */ | ||||
u_int ps_nargvstr; /* the number of argument strings */ | u_int ps_nargvstr; /* the number of argument strings */ | ||||
u_int32_t ps_envstr; /* first of 0 or more environment strings */ | u_int32_t ps_envstr; /* first of 0 or more environment strings */ | ||||
u_int ps_nenvstr; /* the number of environment strings */ | u_int ps_nenvstr; /* the number of environment strings */ | ||||
}; | }; | ||||
LINUX_VDSO_SYM_INTPTR(linux32_sigcode); | |||||
LINUX_VDSO_SYM_INTPTR(linux32_rt_sigcode); | |||||
LINUX_VDSO_SYM_INTPTR(linux32_vsyscall); | |||||
/* | /* | ||||
* If FreeBSD & Linux have a difference of opinion about what a trap | * If FreeBSD & Linux have a difference of opinion about what a trap | ||||
* means, deal with it here. | * means, deal with it here. | ||||
* | * | ||||
* MPSAFE | * MPSAFE | ||||
*/ | */ | ||||
static int | static int | ||||
translate_traps(int signal, int trap_code) | translate_traps(int signal, int trap_code) | ||||
Show All 23 Lines | elf_linux_fixup(register_t **stack_base, struct image_params *imgp) | ||||
uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform); | uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform); | ||||
KASSERT(curthread->td_proc == imgp->proc, | KASSERT(curthread->td_proc == imgp->proc, | ||||
("unsafe elf_linux_fixup(), should be curproc")); | ("unsafe elf_linux_fixup(), should be curproc")); | ||||
base = (Elf32_Addr *)*stack_base; | base = (Elf32_Addr *)*stack_base; | ||||
args = (Elf32_Auxargs *)imgp->auxargs; | args = (Elf32_Auxargs *)imgp->auxargs; | ||||
pos = base + (imgp->args->argc + imgp->args->envc + 2); | pos = base + (imgp->args->argc + imgp->args->envc + 2); | ||||
AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO_EHDR, | |||||
imgp->proc->p_sysent->sv_shared_page_base); | |||||
AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO, linux32_vsyscall); | |||||
AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature); | AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature); | ||||
/* | /* | ||||
* Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, | * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, | ||||
* as it has appeared in the 2.4.0-rc7 first time. | * as it has appeared in the 2.4.0-rc7 first time. | ||||
* Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), | * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), | ||||
* glibc falls back to the hard-coded CLK_TCK value when aux entry | * glibc falls back to the hard-coded CLK_TCK value when aux entry | ||||
* is not present. | * is not present. | ||||
Show All 22 Lines | elf_linux_fixup(register_t **stack_base, struct image_params *imgp) | ||||
imgp->auxargs = NULL; | imgp->auxargs = NULL; | ||||
base--; | base--; | ||||
suword32(base, (uint32_t)imgp->args->argc); | suword32(base, (uint32_t)imgp->args->argc); | ||||
*stack_base = (register_t *)base; | *stack_base = (register_t *)base; | ||||
return (0); | return (0); | ||||
} | } | ||||
extern unsigned long linux_sznonrtsigcode; | |||||
static void | static void | ||||
linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) | linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) | ||||
{ | { | ||||
struct thread *td = curthread; | struct thread *td = curthread; | ||||
struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||
struct sigacts *psp; | struct sigacts *psp; | ||||
struct trapframe *regs; | struct trapframe *regs; | ||||
struct l_rt_sigframe *fp, frame; | struct l_rt_sigframe *fp, frame; | ||||
Show All 38 Lines | #endif | ||||
frame.sf_sig = sig; | frame.sf_sig = sig; | ||||
frame.sf_siginfo = PTROUT(&fp->sf_si); | frame.sf_siginfo = PTROUT(&fp->sf_si); | ||||
frame.sf_ucontext = PTROUT(&fp->sf_sc); | frame.sf_ucontext = PTROUT(&fp->sf_sc); | ||||
/* Fill in POSIX parts */ | /* Fill in POSIX parts */ | ||||
ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig); | ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig); | ||||
/* | /* | ||||
* Build the signal context to be used by sigreturn. | * Build the signal context to be used by sigreturn | ||||
* and libgcc unwind. | |||||
*/ | */ | ||||
frame.sf_sc.uc_flags = 0; /* XXX ??? */ | frame.sf_sc.uc_flags = 0; /* XXX ??? */ | ||||
frame.sf_sc.uc_link = 0; /* XXX ??? */ | frame.sf_sc.uc_link = 0; /* XXX ??? */ | ||||
frame.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); | frame.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); | ||||
frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; | frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; | ||||
frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) | frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) | ||||
? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; | ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); | bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); | ||||
frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; | frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; | ||||
frame.sf_sc.uc_mcontext.sc_edi = regs->tf_rdi; | frame.sf_sc.uc_mcontext.sc_edi = regs->tf_rdi; | ||||
frame.sf_sc.uc_mcontext.sc_esi = regs->tf_rsi; | frame.sf_sc.uc_mcontext.sc_esi = regs->tf_rsi; | ||||
frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_rbp; | frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_rbp; | ||||
frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_rbx; | frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_rbx; | ||||
frame.sf_sc.uc_mcontext.sc_esp = regs->tf_rsp; | |||||
frame.sf_sc.uc_mcontext.sc_edx = regs->tf_rdx; | frame.sf_sc.uc_mcontext.sc_edx = regs->tf_rdx; | ||||
frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_rcx; | frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_rcx; | ||||
frame.sf_sc.uc_mcontext.sc_eax = regs->tf_rax; | frame.sf_sc.uc_mcontext.sc_eax = regs->tf_rax; | ||||
frame.sf_sc.uc_mcontext.sc_eip = regs->tf_rip; | frame.sf_sc.uc_mcontext.sc_eip = regs->tf_rip; | ||||
frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; | frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; | ||||
frame.sf_sc.uc_mcontext.sc_gs = regs->tf_gs; | frame.sf_sc.uc_mcontext.sc_gs = regs->tf_gs; | ||||
frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; | frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; | ||||
frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; | frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; | ||||
Show All 25 Lines | #endif | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
sigexit(td, SIGILL); | sigexit(td, SIGILL); | ||||
} | } | ||||
/* | /* | ||||
* Build context to run handler in. | * Build context to run handler in. | ||||
*/ | */ | ||||
regs->tf_rsp = PTROUT(fp); | regs->tf_rsp = PTROUT(fp); | ||||
regs->tf_rip = p->p_sysent->sv_sigcode_base + linux_sznonrtsigcode; | regs->tf_rip = linux32_rt_sigcode; | ||||
regs->tf_rflags &= ~(PSL_T | PSL_D); | regs->tf_rflags &= ~(PSL_T | PSL_D); | ||||
regs->tf_cs = _ucode32sel; | regs->tf_cs = _ucode32sel; | ||||
regs->tf_ss = _udatasel; | regs->tf_ss = _udatasel; | ||||
regs->tf_ds = _udatasel; | regs->tf_ds = _udatasel; | ||||
regs->tf_es = _udatasel; | regs->tf_es = _udatasel; | ||||
regs->tf_fs = _ufssel; | regs->tf_fs = _ufssel; | ||||
regs->tf_gs = _ugssel; | regs->tf_gs = _ugssel; | ||||
regs->tf_flags = TF_HASSEGS; | regs->tf_flags = TF_HASSEGS; | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | #endif | ||||
frame.sf_sc.sc_gs = regs->tf_gs; | frame.sf_sc.sc_gs = regs->tf_gs; | ||||
frame.sf_sc.sc_fs = regs->tf_fs; | frame.sf_sc.sc_fs = regs->tf_fs; | ||||
frame.sf_sc.sc_es = regs->tf_es; | frame.sf_sc.sc_es = regs->tf_es; | ||||
frame.sf_sc.sc_ds = regs->tf_ds; | frame.sf_sc.sc_ds = regs->tf_ds; | ||||
frame.sf_sc.sc_edi = regs->tf_rdi; | frame.sf_sc.sc_edi = regs->tf_rdi; | ||||
frame.sf_sc.sc_esi = regs->tf_rsi; | frame.sf_sc.sc_esi = regs->tf_rsi; | ||||
frame.sf_sc.sc_ebp = regs->tf_rbp; | frame.sf_sc.sc_ebp = regs->tf_rbp; | ||||
frame.sf_sc.sc_ebx = regs->tf_rbx; | frame.sf_sc.sc_ebx = regs->tf_rbx; | ||||
frame.sf_sc.sc_esp = regs->tf_rsp; | |||||
frame.sf_sc.sc_edx = regs->tf_rdx; | frame.sf_sc.sc_edx = regs->tf_rdx; | ||||
frame.sf_sc.sc_ecx = regs->tf_rcx; | frame.sf_sc.sc_ecx = regs->tf_rcx; | ||||
frame.sf_sc.sc_eax = regs->tf_rax; | frame.sf_sc.sc_eax = regs->tf_rax; | ||||
frame.sf_sc.sc_eip = regs->tf_rip; | frame.sf_sc.sc_eip = regs->tf_rip; | ||||
frame.sf_sc.sc_cs = regs->tf_cs; | frame.sf_sc.sc_cs = regs->tf_cs; | ||||
frame.sf_sc.sc_eflags = regs->tf_rflags; | frame.sf_sc.sc_eflags = regs->tf_rflags; | ||||
frame.sf_sc.sc_esp_at_signal = regs->tf_rsp; | frame.sf_sc.sc_esp_at_signal = regs->tf_rsp; | ||||
frame.sf_sc.sc_ss = regs->tf_ss; | frame.sf_sc.sc_ss = regs->tf_ss; | ||||
Show All 12 Lines | if (copyout(&frame, fp, sizeof(frame)) != 0) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
sigexit(td, SIGILL); | sigexit(td, SIGILL); | ||||
} | } | ||||
/* | /* | ||||
* Build context to run handler in. | * Build context to run handler in. | ||||
*/ | */ | ||||
regs->tf_rsp = PTROUT(fp); | regs->tf_rsp = PTROUT(fp); | ||||
regs->tf_rip = p->p_sysent->sv_sigcode_base; | regs->tf_rip = linux32_sigcode; | ||||
regs->tf_rflags &= ~(PSL_T | PSL_D); | regs->tf_rflags &= ~(PSL_T | PSL_D); | ||||
regs->tf_cs = _ucode32sel; | regs->tf_cs = _ucode32sel; | ||||
regs->tf_ss = _udatasel; | regs->tf_ss = _udatasel; | ||||
regs->tf_ds = _udatasel; | regs->tf_ds = _udatasel; | ||||
regs->tf_es = _udatasel; | regs->tf_es = _udatasel; | ||||
regs->tf_fs = _ufssel; | regs->tf_fs = _ufssel; | ||||
regs->tf_gs = _ugssel; | regs->tf_gs = _ugssel; | ||||
regs->tf_flags = TF_HASSEGS; | regs->tf_flags = TF_HASSEGS; | ||||
▲ Show 20 Lines • Show All 462 Lines • ▼ Show 20 Lines | struct sysentvec elf_linux_sysvec = { | ||||
.sv_mask = 0, | .sv_mask = 0, | ||||
.sv_sigsize = LINUX_SIGTBLSZ, | .sv_sigsize = LINUX_SIGTBLSZ, | ||||
.sv_sigtbl = bsd_to_linux_signal, | .sv_sigtbl = bsd_to_linux_signal, | ||||
.sv_errsize = ELAST + 1, | .sv_errsize = ELAST + 1, | ||||
.sv_errtbl = bsd_to_linux_errno, | .sv_errtbl = bsd_to_linux_errno, | ||||
.sv_transtrap = translate_traps, | .sv_transtrap = translate_traps, | ||||
.sv_fixup = elf_linux_fixup, | .sv_fixup = elf_linux_fixup, | ||||
.sv_sendsig = linux_sendsig, | .sv_sendsig = linux_sendsig, | ||||
.sv_sigcode = linux_sigcode, | .sv_sigcode = &_binary_linux32_locore_o_start, | ||||
.sv_szsigcode = &linux_szsigcode, | .sv_szsigcode = &linux_szsigcode, | ||||
.sv_prepsyscall = NULL, | .sv_prepsyscall = NULL, | ||||
.sv_name = "Linux ELF32", | .sv_name = "Linux ELF32", | ||||
.sv_coredump = elf32_coredump, | .sv_coredump = elf32_coredump, | ||||
.sv_imgact_try = exec_linux_imgact_try, | .sv_imgact_try = exec_linux_imgact_try, | ||||
.sv_minsigstksz = LINUX_MINSIGSTKSZ, | .sv_minsigstksz = LINUX_MINSIGSTKSZ, | ||||
.sv_pagesize = PAGE_SIZE, | .sv_pagesize = PAGE_SIZE, | ||||
.sv_minuser = VM_MIN_ADDRESS, | .sv_minuser = VM_MIN_ADDRESS, | ||||
Show All 9 Lines | struct sysentvec elf_linux_sysvec = { | ||||
.sv_set_syscall_retval = cpu_set_syscall_retval, | .sv_set_syscall_retval = cpu_set_syscall_retval, | ||||
.sv_fetch_syscall_args = linux32_fetch_syscall_args, | .sv_fetch_syscall_args = linux32_fetch_syscall_args, | ||||
.sv_syscallnames = NULL, | .sv_syscallnames = NULL, | ||||
.sv_shared_page_base = LINUX32_SHAREDPAGE, | .sv_shared_page_base = LINUX32_SHAREDPAGE, | ||||
.sv_shared_page_len = PAGE_SIZE, | .sv_shared_page_len = PAGE_SIZE, | ||||
.sv_schedtail = linux_schedtail, | .sv_schedtail = linux_schedtail, | ||||
.sv_thread_detach = linux_thread_detach | .sv_thread_detach = linux_thread_detach | ||||
}; | }; | ||||
INIT_SYSENTVEC(elf_sysvec, &elf_linux_sysvec); | |||||
static void | |||||
linux_vdso_install(void *param) | |||||
{ | |||||
linux_szsigcode = (&_binary_linux32_locore_o_end - | |||||
&_binary_linux32_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, LINUX32_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 char GNU_ABI_VENDOR[] = "GNU"; | ||||
static int GNULINUX_ABI_DESC = 0; | static int GNULINUX_ABI_DESC = 0; | ||||
static boolean_t | static boolean_t | ||||
linux32_trans_osrel(const Elf_Note *note, int32_t *osrel) | linux32_trans_osrel(const Elf_Note *note, int32_t *osrel) | ||||
{ | { | ||||
const Elf32_Word *desc; | const Elf32_Word *desc; | ||||
▲ Show 20 Lines • Show All 131 Lines • Show Last 20 Lines |