/* * Set that machine state for performing an upcall that starts * the entry function with the given argument. */ void cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg, stack_t *stack) { /* * Do any extra cleaning that needs to be done. * The thread may have optional components * that are not present in a fresh thread. * This may be a recycled thread so make it look * as though it's newly allocated. */ cpu_thread_clean(td); #ifdef COMPAT_FREEBSD32 if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { /* * Set the trap frame to point at the beginning of the entry * function. */ td->td_frame->tf_rbp = 0; td->td_frame->tf_rsp = (((uintptr_t)stack->ss_sp + stack->ss_size - 4) & ~0x0f) - 4; td->td_frame->tf_rip = (uintptr_t)entry; /* Return address sentinel value to stop stack unwinding. */ suword32((void *)td->td_frame->tf_rsp, 0); /* Pass the argument to the entry point. */ suword32((void *)(td->td_frame->tf_rsp + sizeof(int32_t)), (uint32_t)(uintptr_t)arg); return; } #endif /* * Set the trap frame to point at the beginning of the uts * function. */ td->td_frame->tf_rbp = 0; td->td_frame->tf_rsp = ((register_t)stack->ss_sp + stack->ss_size) & ~0x0f; td->td_frame->tf_rsp -= 8; td->td_frame->tf_rip = (register_t)entry; td->td_frame->tf_ds = _udatasel; td->td_frame->tf_es = _udatasel; td->td_frame->tf_fs = _ufssel; td->td_frame->tf_gs = _ugssel; td->td_frame->tf_flags = TF_HASSEGS; /* Return address sentinel value to stop stack unwinding. */ suword((void *)td->td_frame->tf_rsp, 0); /* Pass the argument to the entry point. */ td->td_frame->tf_rdi = (register_t)arg; }
/* ARGSUSED */ int ufs_fioisbusy(struct vnode *vp, int *isbusy, struct cred *cr) { int is_it_busy; /* * The caller holds one reference, there may be one in the dnlc * so we need to flush it. */ if (vp->v_count > 1) dnlc_purge_vp(vp); /* * Since we've just flushed the dnlc and we hold a reference * to this vnode, then anything but 1 means busy (this had * BETTER not be zero!). Also, it's possible for someone to * have this file mmap'ed with no additional reference count. */ ASSERT(vp->v_count > 0); if ((vp->v_count == 1) && (VTOI(vp)->i_mapcnt == 0)) is_it_busy = 0; else is_it_busy = 1; if (suword32(isbusy, is_it_busy)) return (EFAULT); return (0); }
enum ftt_type _fp_write_word( uint32_t *address, /* FPU data address. */ uint32_t value, /* Word value to write. */ fp_simd_type *pfpsd) /* Pointer to fpu simulator data. */ { if (((uintptr_t)address & 0x3) != 0) return (ftt_alignment); /* Must be word-aligned. */ if (get_udatamodel() == DATAMODEL_ILP32) { /* * If this is a 32-bit program, chop the address accordingly. * The intermediate uintptr_t casts prevent warnings under a * certain compiler, and the temporary 32 bit storage is * intended to force proper code generation and break up what * would otherwise be a quadruple cast. */ caddr32_t address32 = (caddr32_t)(uintptr_t)address; address = (uint32_t *)(uintptr_t)address32; } if (suword32(address, value) == -1) { pfpsd->fp_trapaddr = (caddr_t)address; pfpsd->fp_traprw = S_WRITE; return (ftt_fault); } return (ftt_none); }
static int elf_linux_fixup(register_t **stack_base, struct image_params *imgp) { Elf32_Auxargs *args; Elf32_Addr *base; Elf32_Addr *pos; struct linux32_ps_strings *arginfo; arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS; KASSERT(curthread->td_proc == imgp->proc, ("unsafe elf_linux_fixup(), should be curproc")); base = (Elf32_Addr *)*stack_base; args = (Elf32_Auxargs *)imgp->auxargs; 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); /* * 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. * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), * glibc falls back to the hard-coded CLK_TCK value when aux entry * is not present. * Also see linux_times() implementation. */ if (linux_kernver(curthread) >= LINUX_KERNVER_2004000) AUXARGS_ENTRY_32(pos, LINUX_AT_CLKTCK, stclohz); AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr); AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent); AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum); AUXARGS_ENTRY_32(pos, AT_PAGESZ, args->pagesz); AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags); AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry); AUXARGS_ENTRY_32(pos, AT_BASE, args->base); AUXARGS_ENTRY_32(pos, LINUX_AT_SECURE, 0); AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); AUXARGS_ENTRY_32(pos, LINUX_AT_PLATFORM, PTROUT(linux_platform)); AUXARGS_ENTRY(pos, LINUX_AT_RANDOM, PTROUT(imgp->canary)); if (imgp->execpathp != 0) AUXARGS_ENTRY(pos, LINUX_AT_EXECFN, PTROUT(imgp->execpathp)); if (args->execfd != -1) AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd); AUXARGS_ENTRY_32(pos, AT_NULL, 0); free(imgp->auxargs, M_TEMP); imgp->auxargs = NULL; base--; suword32(base, (uint32_t)imgp->args->argc); *stack_base = (register_t *)base; return (0); }
static inline int suword_lwpid(void *addr, lwpid_t lwpid) { int error; if (SV_CURPROC_FLAG(SV_LP64)) error = suword(addr, lwpid); else error = suword32(addr, lwpid); return (error); }
int suword32_nowatch(void *addr, uint32_t value) { int watched, ret; watched = watch_disable_addr(addr, sizeof (value), S_WRITE); ret = suword32(addr, value); if (watched) watch_enable_addr(addr, sizeof (value), S_WRITE); return (ret); }
int freebsd32_cap_ioctls_get(struct thread *td, struct freebsd32_cap_ioctls_get_args *uap) { struct filedesc *fdp; struct filedescent *fdep; uint32_t *cmds32; u_long *cmds; size_t maxcmds; int error, fd; u_int i; fd = uap->fd; cmds32 = uap->cmds; maxcmds = uap->maxcmds; AUDIT_ARG_FD(fd); fdp = td->td_proc->p_fd; FILEDESC_SLOCK(fdp); if (fget_locked(fdp, fd) == NULL) { error = EBADF; goto out; } /* * If all ioctls are allowed (fde_nioctls == -1 && fde_ioctls == NULL) * the only sane thing we can do is to not populate the given array and * return CAP_IOCTLS_ALL (actually, INT_MAX). */ fdep = &fdp->fd_ofiles[fd]; cmds = fdep->fde_ioctls; if (cmds32 != NULL && cmds != NULL) { for (i = 0; i < MIN(fdep->fde_nioctls, maxcmds); i++) { error = suword32(&cmds32[i], cmds[i]); if (error != 0) goto out; } } if (fdep->fde_nioctls == -1) td->td_retval[0] = INT_MAX; else td->td_retval[0] = fdep->fde_nioctls; error = 0; out: FILEDESC_SUNLOCK(fdp); return (error); }
/* ARGSUSED */ int ufs_fiogdio( struct vnode *vp, /* file's vnode */ uint_t *diop, /* dio state returned here */ int flag, /* flag from ufs_ioctl */ struct cred *cr) /* credentials from ufs_ioctl */ { struct ufsvfs *ufsvfsp = VTOI(vp)->i_ufsvfs; /* * forcibly unmounted */ if (ufsvfsp == NULL) return (EIO); if (suword32(diop, ufsvfsp->vfs_dio)) return (EFAULT); return (0); }
void linux_thread_detach(struct thread *td) { struct linux_sys_futex_args cup; struct linux_emuldata *em; int *child_clear_tid; int error; em = em_find(td); KASSERT(em != NULL, ("thread_detach: emuldata not found.\n")); LINUX_CTR1(thread_detach, "thread(%d)", em->em_tid); release_futexes(td, em); child_clear_tid = em->child_clear_tid; if (child_clear_tid != NULL) { LINUX_CTR2(thread_detach, "thread(%d) %p", em->em_tid, child_clear_tid); error = suword32(child_clear_tid, 0); if (error != 0) return; cup.uaddr = child_clear_tid; cup.op = LINUX_FUTEX_WAKE; cup.val = 1; /* wake one */ cup.timeout = NULL; cup.uaddr2 = NULL; cup.val3 = 0; error = linux_sys_futex(td, &cup); /* * this cannot happen at the moment and if this happens it * probably means there is a user space bug */ if (error != 0) linux_msg(td, "futex stuff in thread_detach failed."); } }
/* * System call to access CPU performance counters. */ static int cpc(int cmd, id_t lwpid, void *udata1, void *udata2, void *udata3) { kthread_t *t; int error; int size; const char *str; int code; /* * This CPC syscall should only be loaded if it found a PCBE to use. */ ASSERT(pcbe_ops != NULL); if (curproc->p_agenttp == curthread) { /* * Only if /proc is invoking this system call from * the agent thread do we allow the caller to examine * the contexts of other lwps in the process. And * because we know we're the agent, we know we don't * have to grab p_lock because no-one else can change * the state of the process. */ if ((t = idtot(curproc, lwpid)) == NULL || t == curthread) return (set_errno(ESRCH)); ASSERT(t->t_tid == lwpid && ttolwp(t) != NULL); } else t = curthread; if (t->t_cpc_set == NULL && (cmd == CPC_SAMPLE || cmd == CPC_RELE)) return (set_errno(EINVAL)); switch (cmd) { case CPC_BIND: /* * udata1 = pointer to packed nvlist buffer * udata2 = size of packed nvlist buffer * udata3 = User addr to return error subcode in. */ rw_enter(&kcpc_cpuctx_lock, RW_READER); if (kcpc_cpuctx || dtrace_cpc_in_use) { rw_exit(&kcpc_cpuctx_lock); return (set_errno(EAGAIN)); } if (kcpc_hw_lwp_hook() != 0) { rw_exit(&kcpc_cpuctx_lock); return (set_errno(EACCES)); } /* * An LWP may only have one set bound to it at a time; if there * is a set bound to this LWP already, we unbind it here. */ if (t->t_cpc_set != NULL) (void) kcpc_unbind(t->t_cpc_set); ASSERT(t->t_cpc_set == NULL); if ((error = kcpc_copyin_set(&t->t_cpc_set, udata1, (size_t)udata2)) != 0) { rw_exit(&kcpc_cpuctx_lock); return (set_errno(error)); } if ((error = kcpc_verify_set(t->t_cpc_set)) != 0) { rw_exit(&kcpc_cpuctx_lock); kcpc_free_set(t->t_cpc_set); t->t_cpc_set = NULL; if (copyout(&error, udata3, sizeof (error)) == -1) return (set_errno(EFAULT)); return (set_errno(EINVAL)); } if ((error = kcpc_bind_thread(t->t_cpc_set, t, &code)) != 0) { rw_exit(&kcpc_cpuctx_lock); kcpc_free_set(t->t_cpc_set); t->t_cpc_set = NULL; /* * EINVAL and EACCES are the only errors with more * specific subcodes. */ if ((error == EINVAL || error == EACCES) && copyout(&code, udata3, sizeof (code)) == -1) return (set_errno(EFAULT)); return (set_errno(error)); } rw_exit(&kcpc_cpuctx_lock); return (0); case CPC_SAMPLE: /* * udata1 = pointer to user's buffer * udata2 = pointer to user's hrtime * udata3 = pointer to user's tick */ /* * We only allow thread-bound sets to be sampled via the * syscall, so if this set has a CPU-bound context, return an * error. */ if (t->t_cpc_set->ks_ctx->kc_cpuid != -1) return (set_errno(EINVAL)); if ((error = kcpc_sample(t->t_cpc_set, udata1, udata2, udata3)) != 0) return (set_errno(error)); return (0); case CPC_PRESET: case CPC_RESTART: /* * These are valid only if this lwp has a bound set. */ if (t->t_cpc_set == NULL) return (set_errno(EINVAL)); if (cmd == CPC_PRESET) { /* * The preset is shipped up to us from userland in two * parts. This lets us handle 64-bit values from 32-bit * and 64-bit applications in the same manner. * * udata1 = index of request to preset * udata2 = new 64-bit preset (most sig. 32 bits) * udata3 = new 64-bit preset (least sig. 32 bits) */ if ((error = kcpc_preset(t->t_cpc_set, (intptr_t)udata1, ((uint64_t)(uintptr_t)udata2 << 32ULL) | (uint64_t)(uintptr_t)udata3)) != 0) return (set_errno(error)); } else { /* * udata[1-3] = unused */ if ((error = kcpc_restart(t->t_cpc_set)) != 0) return (set_errno(error)); } return (0); case CPC_ENABLE: case CPC_DISABLE: udata1 = 0; /*FALLTHROUGH*/ case CPC_USR_EVENTS: case CPC_SYS_EVENTS: if (t != curthread || t->t_cpc_set == NULL) return (set_errno(EINVAL)); /* * Provided for backwards compatibility with CPCv1. * * Stop the counters and record the current counts. Use the * counts as the preset to rebind a new set with the requests * reconfigured as requested. * * udata1: 1 == enable; 0 == disable * udata{2,3}: unused */ rw_enter(&kcpc_cpuctx_lock, RW_READER); if ((error = kcpc_enable(t, cmd, (int)(uintptr_t)udata1)) != 0) { rw_exit(&kcpc_cpuctx_lock); return (set_errno(error)); } rw_exit(&kcpc_cpuctx_lock); return (0); case CPC_NPIC: return (cpc_ncounters); case CPC_CAPS: return (pcbe_ops->pcbe_caps); case CPC_EVLIST_SIZE: case CPC_LIST_EVENTS: /* * udata1 = pointer to user's int or buffer * udata2 = picnum * udata3 = unused */ if ((uintptr_t)udata2 >= cpc_ncounters) return (set_errno(EINVAL)); size = strlen( pcbe_ops->pcbe_list_events((uintptr_t)udata2)) + 1; if (cmd == CPC_EVLIST_SIZE) { if (suword32(udata1, size) == -1) return (set_errno(EFAULT)); } else { if (copyout( pcbe_ops->pcbe_list_events((uintptr_t)udata2), udata1, size) == -1) return (set_errno(EFAULT)); } return (0); case CPC_ATTRLIST_SIZE: case CPC_LIST_ATTRS: /* * udata1 = pointer to user's int or buffer * udata2 = unused * udata3 = unused * * attrlist size is length of PCBE-supported attributes, plus * room for "picnum\0" plus an optional ',' separator char. */ str = pcbe_ops->pcbe_list_attrs(); size = strlen(str) + sizeof (SEPARATOR ATTRLIST) + 1; if (str[0] != '\0') /* * A ',' separator character is necessary. */ size += 1; if (cmd == CPC_ATTRLIST_SIZE) { if (suword32(udata1, size) == -1) return (set_errno(EFAULT)); } else { /* * Copyout the PCBE attributes, and then append the * generic attribute list (with separator if necessary). */ if (copyout(str, udata1, strlen(str)) == -1) return (set_errno(EFAULT)); if (str[0] != '\0') { if (copyout(SEPARATOR ATTRLIST, ((char *)udata1) + strlen(str), strlen(SEPARATOR ATTRLIST) + 1) == -1) return (set_errno(EFAULT)); } else if (copyout(ATTRLIST, (char *)udata1 + strlen(str), strlen(ATTRLIST) + 1) == -1) return (set_errno(EFAULT)); } return (0); case CPC_IMPL_NAME: case CPC_CPUREF: /* * udata1 = pointer to user's buffer * udata2 = unused * udata3 = unused */ if (cmd == CPC_IMPL_NAME) { str = pcbe_ops->pcbe_impl_name(); ASSERT(strlen(str) < CPC_MAX_IMPL_NAME); } else { str = pcbe_ops->pcbe_cpuref(); ASSERT(strlen(str) < CPC_MAX_CPUREF); } if (copyout(str, udata1, strlen(str) + 1) != 0) return (set_errno(EFAULT)); return (0); case CPC_INVALIDATE: kcpc_invalidate(t); return (0); case CPC_RELE: if ((error = kcpc_unbind(t->t_cpc_set)) != 0) return (set_errno(error)); return (0); default: return (set_errno(EINVAL)); } }
/* * XXX copied from ia32_sysvec.c. */ static register_t * linux_copyout_strings(struct image_params *imgp) { int argc, envc; u_int32_t *vectp; char *stringp, *destp; u_int32_t *stack_base; struct linux32_ps_strings *arginfo; /* * Calculate string base and vector table pointers. * Also deal with signal trampoline code for this exec type. */ arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS; destp = (caddr_t)arginfo - SPARE_USRSPACE - linux_szplatform - roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); /* * Install LINUX_PLATFORM */ copyout(linux_platform, ((caddr_t)arginfo - linux_szplatform), linux_szplatform); /* * If we have a valid auxargs ptr, prepare some room * on the stack. */ if (imgp->auxargs) { /* * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for * lower compatibility. */ imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size : (LINUX_AT_COUNT * 2); /* * The '+ 2' is for the null pointers at the end of each of * the arg and env vector sets,and imgp->auxarg_size is room * for argument of Runtime loader. */ vectp = (u_int32_t *) (destp - (imgp->args->argc + imgp->args->envc + 2 + imgp->auxarg_size) * sizeof(u_int32_t)); } else /* * The '+ 2' is for the null pointers at the end of each of * the arg and env vector sets */ vectp = (u_int32_t *)(destp - (imgp->args->argc + imgp->args->envc + 2) * sizeof(u_int32_t)); /* * vectp also becomes our initial stack base */ stack_base = vectp; stringp = imgp->args->begin_argv; argc = imgp->args->argc; envc = imgp->args->envc; /* * Copy out strings - arguments and environment. */ copyout(stringp, destp, ARG_MAX - imgp->args->stringspace); /* * Fill in "ps_strings" struct for ps, w, etc. */ suword32(&arginfo->ps_argvstr, (uint32_t)(intptr_t)vectp); suword32(&arginfo->ps_nargvstr, argc); /* * Fill in argument portion of vector table. */ for (; argc > 0; --argc) { suword32(vectp++, (uint32_t)(intptr_t)destp); while (*stringp++ != 0) destp++; destp++; } /* a null vector table pointer separates the argp's from the envp's */ suword32(vectp++, 0); suword32(&arginfo->ps_envstr, (uint32_t)(intptr_t)vectp); suword32(&arginfo->ps_nenvstr, envc); /* * Fill in environment portion of vector table. */ for (; envc > 0; --envc) { suword32(vectp++, (uint32_t)(intptr_t)destp); while (*stringp++ != 0) destp++; destp++; } /* end of vector table is a null pointer */ suword32(vectp, 0); return ((register_t *)stack_base); }
/* XXX may be freebsd32 MI */ static register_t * ia32_copyout_strings(struct image_params *imgp) { int argc, envc; u_int32_t *vectp; char *stringp, *destp; u_int32_t *stack_base; struct freebsd32_ps_strings *arginfo; size_t execpath_len; int szsigcode; /* * Calculate string base and vector table pointers. * Also deal with signal trampoline code for this exec type. */ if (imgp->execpath != NULL && imgp->auxargs != NULL) execpath_len = strlen(imgp->execpath) + 1; else execpath_len = 0; arginfo = (struct freebsd32_ps_strings *)FREEBSD32_PS_STRINGS; szsigcode = *(imgp->proc->p_sysent->sv_szsigcode); destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE - roundup(execpath_len, sizeof(char *)) - roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); /* * install sigcode */ if (szsigcode) copyout(imgp->proc->p_sysent->sv_sigcode, ((caddr_t)arginfo - szsigcode), szsigcode); /* * Copy the image path for the rtld. */ if (execpath_len != 0) { imgp->execpathp = (uintptr_t)arginfo - szsigcode - execpath_len; copyout(imgp->execpath, (void *)imgp->execpathp, execpath_len); } /* * If we have a valid auxargs ptr, prepare some room * on the stack. */ if (imgp->auxargs) { /* * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for * lower compatibility. */ imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size : (AT_COUNT * 2); /* * The '+ 2' is for the null pointers at the end of each of * the arg and env vector sets,and imgp->auxarg_size is room * for argument of Runtime loader. */ vectp = (u_int32_t *) (destp - (imgp->args->argc + imgp->args->envc + 2 + imgp->auxarg_size + execpath_len) * sizeof(u_int32_t)); } else /* * The '+ 2' is for the null pointers at the end of each of * the arg and env vector sets */ vectp = (u_int32_t *) (destp - (imgp->args->argc + imgp->args->envc + 2) * sizeof(u_int32_t)); /* * vectp also becomes our initial stack base */ stack_base = vectp; stringp = imgp->args->begin_argv; argc = imgp->args->argc; envc = imgp->args->envc; /* * Copy out strings - arguments and environment. */ copyout(stringp, destp, ARG_MAX - imgp->args->stringspace); /* * Fill in "ps_strings" struct for ps, w, etc. */ suword32(&arginfo->ps_argvstr, (u_int32_t)(intptr_t)vectp); suword32(&arginfo->ps_nargvstr, argc); /* * Fill in argument portion of vector table. */ for (; argc > 0; --argc) { suword32(vectp++, (u_int32_t)(intptr_t)destp); while (*stringp++ != 0) destp++; destp++; } /* a null vector table pointer separates the argp's from the envp's */ suword32(vectp++, 0); suword32(&arginfo->ps_envstr, (u_int32_t)(intptr_t)vectp); suword32(&arginfo->ps_nenvstr, envc); /* * Fill in environment portion of vector table. */ for (; envc > 0; --envc) { suword32(vectp++, (u_int32_t)(intptr_t)destp); while (*stringp++ != 0) destp++; destp++; } /* end of vector table is a null pointer */ suword32(vectp, 0); return ((register_t *)stack_base); }
static int lwp_getprivate(klwp_t *lwp, int which, uintptr_t base) { pcb_t *pcb = &lwp->lwp_pcb; struct regs *rp = lwptoregs(lwp); uintptr_t sbase; int error = 0; ASSERT(lwptot(lwp) == curthread); kpreempt_disable(); switch (which) { #if defined(__amd64) case _LWP_FSBASE: if ((sbase = pcb->pcb_fsbase) != 0) { if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) { if (pcb->pcb_rupdate == 1) { if (pcb->pcb_fs == 0) break; } else { if (rp->r_fs == 0) break; } } else { if (pcb->pcb_rupdate == 1) { if (pcb->pcb_fs == LWPFS_SEL) break; } else { if (rp->r_fs == LWPFS_SEL) break; } } } error = EINVAL; break; case _LWP_GSBASE: if ((sbase = pcb->pcb_gsbase) != 0) { if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) { if (pcb->pcb_rupdate == 1) { if (pcb->pcb_gs == 0) break; } else { if (rp->r_gs == 0) break; } } else { if (pcb->pcb_rupdate == 1) { if (pcb->pcb_gs == LWPGS_SEL) break; } else { if (rp->r_gs == LWPGS_SEL) break; } } } error = EINVAL; break; #elif defined(__i386) case _LWP_FSBASE: if (rp->r_fs == LWPFS_SEL) { sbase = USEGD_GETBASE(&pcb->pcb_fsdesc); break; } error = EINVAL; break; case _LWP_GSBASE: if (rp->r_gs == LWPGS_SEL) { sbase = USEGD_GETBASE(&pcb->pcb_gsdesc); break; } error = EINVAL; break; #endif /* __i386 */ default: error = ENOTSUP; break; } kpreempt_enable(); if (error != 0) return (error); if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) { if (sulword((void *)base, sbase) == -1) error = EFAULT; #if defined(_SYSCALL32_IMPL) } else { if (suword32((void *)base, (uint32_t)sbase) == -1) error = EFAULT; #endif } return (error); }
/* * XXX copied from ia32_sysvec.c. */ static register_t * linux_copyout_strings(struct image_params *imgp) { int argc, envc; u_int32_t *vectp; char *stringp, *destp; u_int32_t *stack_base; struct linux32_ps_strings *arginfo; char canary[LINUX_AT_RANDOM_LEN]; size_t execpath_len; /* * Calculate string base and vector table pointers. */ if (imgp->execpath != NULL && imgp->auxargs != NULL) execpath_len = strlen(imgp->execpath) + 1; else execpath_len = 0; arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS; destp = (caddr_t)arginfo - SPARE_USRSPACE - roundup(sizeof(canary), sizeof(char *)) - roundup(execpath_len, sizeof(char *)) - roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); if (execpath_len != 0) { imgp->execpathp = (uintptr_t)arginfo - execpath_len; copyout(imgp->execpath, (void *)imgp->execpathp, execpath_len); } /* * Prepare the canary for SSP. */ arc4rand(canary, sizeof(canary), 0); imgp->canary = (uintptr_t)arginfo - roundup(execpath_len, sizeof(char *)) - roundup(sizeof(canary), sizeof(char *)); copyout(canary, (void *)imgp->canary, sizeof(canary)); /* * If we have a valid auxargs ptr, prepare some room * on the stack. */ if (imgp->auxargs) { /* * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for * lower compatibility. */ imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size : (LINUX_AT_COUNT * 2); /* * The '+ 2' is for the null pointers at the end of each of * the arg and env vector sets,and imgp->auxarg_size is room * for argument of Runtime loader. */ vectp = (u_int32_t *) (destp - (imgp->args->argc + imgp->args->envc + 2 + imgp->auxarg_size) * sizeof(u_int32_t)); } else /* * The '+ 2' is for the null pointers at the end of each of * the arg and env vector sets */ vectp = (u_int32_t *)(destp - (imgp->args->argc + imgp->args->envc + 2) * sizeof(u_int32_t)); /* * vectp also becomes our initial stack base */ stack_base = vectp; stringp = imgp->args->begin_argv; argc = imgp->args->argc; envc = imgp->args->envc; /* * Copy out strings - arguments and environment. */ copyout(stringp, destp, ARG_MAX - imgp->args->stringspace); /* * Fill in "ps_strings" struct for ps, w, etc. */ suword32(&arginfo->ps_argvstr, (uint32_t)(intptr_t)vectp); suword32(&arginfo->ps_nargvstr, argc); /* * Fill in argument portion of vector table. */ for (; argc > 0; --argc) { suword32(vectp++, (uint32_t)(intptr_t)destp); while (*stringp++ != 0) destp++; destp++; } /* a null vector table pointer separates the argp's from the envp's */ suword32(vectp++, 0); suword32(&arginfo->ps_envstr, (uint32_t)(intptr_t)vectp); suword32(&arginfo->ps_nenvstr, envc); /* * Fill in environment portion of vector table. */ for (; envc > 0; --envc) { suword32(vectp++, (uint32_t)(intptr_t)destp); while (*stringp++ != 0) destp++; destp++; } /* end of vector table is a null pointer */ suword32(vectp, 0); return ((register_t *)stack_base); }