diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h index cea86873b25f..f740d89695df 100644 --- a/sys/compat/freebsd32/freebsd32.h +++ b/sys/compat/freebsd32/freebsd32.h @@ -103,4 +103,18 @@ struct statfs32 { int32_t f_spare[2]; }; +struct thr_param32 { + uint32_t start_func; + uint32_t arg; + uint32_t stack_base; + uint32_t stack_size; + uint32_t tls_base; + uint32_t tls_size; + uint32_t child_tid; + uint32_t parent_tid; + int32_t flags; + uint32_t rtp; + uint32_t spare[3]; +}; + #endif /* !_COMPAT_FREEBSD32_FREEBSD32_H_ */ diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 8076d23c2ec9..2c5668782ab6 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -67,7 +67,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include +#include #include #include #include @@ -2121,6 +2123,60 @@ freebsd32_clock_getres(struct thread *td, return (error); } +int +freebsd32_thr_new(struct thread *td, + struct freebsd32_thr_new_args *uap) +{ + struct thr_param32 param32; + struct thr_param param; + int error; + + if (uap->param_size < 0 || + uap->param_size > sizeof(struct thr_param32)) + return (EINVAL); + bzero(¶m, sizeof(struct thr_param)); + bzero(¶m32, sizeof(struct thr_param32)); + error = copyin(uap->param, ¶m32, uap->param_size); + if (error != 0) + return (error); + param.start_func = PTRIN(param32.start_func); + param.arg = PTRIN(param32.arg); + param.stack_base = PTRIN(param32.stack_base); + param.stack_size = param32.stack_size; + param.tls_base = PTRIN(param32.tls_base); + param.tls_size = param32.tls_size; + param.child_tid = PTRIN(param32.child_tid); + param.parent_tid = PTRIN(param32.parent_tid); + param.flags = param32.flags; + param.rtp = PTRIN(param32.rtp); + param.spare[0] = PTRIN(param32.spare[0]); + param.spare[1] = PTRIN(param32.spare[1]); + param.spare[2] = PTRIN(param32.spare[2]); + + return (kern_thr_new(td, ¶m)); +} + +int +freebsd32_thr_suspend(struct thread *td, struct freebsd32_thr_suspend_args *uap) +{ + struct timespec32 ts32; + struct timespec ts, *tsp; + int error; + + error = 0; + tsp = NULL; + if (uap->timeout != NULL) { + error = copyin((const void *)uap->timeout, (void *)&ts32, + sizeof(struct timespec32)); + if (error != 0) + return (error); + ts.tv_sec = ts32.tv_sec; + ts.tv_nsec = ts32.tv_nsec; + tsp = &ts; + } + return (kern_thr_suspend(td, tsp)); +} + #if 0 int diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 93e63e98f735..7afe985a47a9 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -715,8 +715,7 @@ 428 AUE_NULL UNIMPL __acl_aclcheck_link ; XXX implement 429 AUE_SIGWAIT UNIMPL sigwait -430 AUE_NULL NOPROTO { int thr_create(ucontext_t *ctx, long *id, \ - int flag s); } +430 AUE_NULL UNIMPL thr_create; 431 AUE_NULL NOPROTO { void thr_exit(long *state); } 432 AUE_NULL NOPROTO { int thr_self(long *id); } 433 AUE_NULL NOPROTO { int thr_kill(long id, int sig); } @@ -728,8 +727,8 @@ 439 AUE_EXTATTR_LIST_LINK UNIMPL extattr_list_link 440 AUE_NULL UNIMPL kse_switchin 441 AUE_NULL UNIMPL ksem_timedwait -442 AUE_NULL NOPROTO { int thr_suspend( \ - const struct timespec *timeout); } +442 AUE_NULL STD { int freebsd32_thr_suspend( \ + const struct timespec32 *timeout); } 443 AUE_NULL NOPROTO { int thr_wake(long id); } 444 AUE_MODUNLOAD NOPROTO { int kldunloadf(int fileid, int flags); } 445 AUE_AUDIT UNIMPL audit @@ -744,7 +743,9 @@ 454 AUE_NULL STD { int freebsd32_umtx_op(void *obj, int op,\ uintptr_t val, void *uaddr, \ void *uaddr2); } -455 AUE_NULL UNIMPL thr_new +455 AUE_NULL STD { int freebsd32_thr_new( \ + struct thr_param32 *param, \ + int param_size); } 456 AUE_NULL NOPROTO { int sigqueue(pid_t pid, int signum, \ void *value); } 457 AUE_NULL UNIMPL kmq_open diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c index 5624d9db7ea1..7b65fbba60d8 100644 --- a/sys/kern/kern_thr.c +++ b/sys/kern/kern_thr.c @@ -27,6 +27,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_compat.h" #include "opt_posix.h" #include #include @@ -51,6 +52,26 @@ __FBSDID("$FreeBSD$"); #include +#ifdef COMPAT_IA32 + +extern struct sysentvec ia32_freebsd_sysvec; + +static inline int +suword_lwpid(void *addr, lwpid_t lwpid) +{ + int error; + + if (curproc->p_sysent != &ia32_freebsd_sysvec) + error = suword(addr, lwpid); + else + error = suword32(addr, lwpid); + return (error); +} + +#else +#define suword_lwpid suword +#endif + extern int max_threads_per_proc; static int create_thread(struct thread *td, mcontext_t *ctx, @@ -83,22 +104,30 @@ thr_new(struct thread *td, struct thr_new_args *uap) /* struct thr_param * */ { struct thr_param param; + int error; + + if (uap->param_size < 0 || uap->param_size > sizeof(param)) + return (EINVAL); + bzero(¶m, sizeof(param)); + if ((error = copyin(uap->param, ¶m, uap->param_size))) + return (error); + return (kern_thr_new(td, ¶m)); +} + +int +kern_thr_new(struct thread *td, struct thr_param *param) +{ struct rtprio rtp, *rtpp; int error; - if (uap->param_size < sizeof(param)) - return (EINVAL); - bzero(¶m, sizeof(param)); - if ((error = copyin(uap->param, ¶m, sizeof(param)))) - return (error); rtpp = NULL; - if (param.rtp != 0) { - error = copyin(param.rtp, &rtp, sizeof(struct rtprio)); + if (param->rtp != 0) { + error = copyin(param->rtp, &rtp, sizeof(struct rtprio)); rtpp = &rtp; } - error = create_thread(td, NULL, param.start_func, param.arg, - param.stack_base, param.stack_size, param.tls_base, - param.child_tid, param.parent_tid, param.flags, + error = create_thread(td, NULL, param->start_func, param->arg, + param->stack_base, param->stack_size, param->tls_base, + param->child_tid, param->parent_tid, param->flags, rtpp); return (error); } @@ -158,12 +187,13 @@ create_thread(struct thread *td, mcontext_t *ctx, */ id = newtd->td_tid; if ((child_tid != NULL && - (error = copyout(&id, child_tid, sizeof(long)))) || + suword_lwpid(child_tid, newtd->td_tid)) || (parent_tid != NULL && - (error = copyout(&id, parent_tid, sizeof(long))))) { - thread_free(newtd); - return (error); + suword_lwpid(parent_tid, newtd->td_tid))) { + thread_free(newtd); + return (EFAULT); } + bzero(&newtd->td_startzero, __rangeof(struct thread, td_startzero, td_endzero)); bcopy(&td->td_startcopy, &newtd->td_startcopy, @@ -231,13 +261,11 @@ int thr_self(struct thread *td, struct thr_self_args *uap) /* long *id */ { - long id; int error; - id = td->td_tid; - if ((error = copyout(&id, uap->id, sizeof(long)))) - return (error); - + error = suword_lwpid(uap->id, (unsigned)td->td_tid); + if (error == -1) + return (EFAULT); return (0); } @@ -251,7 +279,7 @@ thr_exit(struct thread *td, struct thr_exit_args *uap) /* Signal userland that it can free the stack. */ if ((void *)uap->state != NULL) { - suword((void *)uap->state, 1); + suword_lwpid(uap->state, 1); kern_umtx_wake(td, uap->state, INT_MAX); } @@ -320,23 +348,34 @@ int thr_suspend(struct thread *td, struct thr_suspend_args *uap) /* const struct timespec *timeout */ { - struct timespec ts; - struct timeval tv; + struct timespec ts, *tsp; int error; - int hz; - hz = 0; error = 0; + tsp = NULL; if (uap->timeout != NULL) { error = copyin((const void *)uap->timeout, (void *)&ts, sizeof(struct timespec)); if (error != 0) return (error); - if (ts.tv_nsec < 0 || ts.tv_nsec > 1000000000) + tsp = &ts; + } + + return (kern_thr_suspend(td, tsp)); +} + +int +kern_thr_suspend(struct thread *td, struct timespec *tsp) +{ + struct timeval tv; + int error = 0, hz = 0; + + if (tsp != NULL) { + if (tsp->tv_nsec < 0 || tsp->tv_nsec > 1000000000) return (EINVAL); - if (ts.tv_sec == 0 && ts.tv_nsec == 0) + if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) return (ETIMEDOUT); - TIMESPEC_TO_TIMEVAL(&tv, &ts); + TIMESPEC_TO_TIMEVAL(&tv, tsp); hz = tvtohz(&tv); } PROC_LOCK(td->td_proc); diff --git a/sys/sys/thr.h b/sys/sys/thr.h index bd2723e8feb9..216ef6fc210e 100644 --- a/sys/sys/thr.h +++ b/sys/sys/thr.h @@ -64,6 +64,10 @@ int thr_kill(long id, int sig); int thr_suspend(const struct timespec *timeout); int thr_wake(long id); int thr_set_name(long id, const char *name); +#else +struct thread; +int kern_thr_new(struct thread *td, struct thr_param *param); +int kern_thr_suspend(struct thread *, struct timespec *); #endif /* !_KERNEL */ #endif /* ! _SYS_THR_H_ */