Index: sys/kern/kern_umtx.c =================================================================== --- sys/kern/kern_umtx.c +++ sys/kern/kern_umtx.c @@ -219,7 +219,7 @@ struct timespec end; }; -#if defined(COMPAT_FREEBSD32) +#if defined(COMPAT_FREEBSD32) || defined(__LP64__) #define NEED_UMTX32 #endif @@ -4142,6 +4142,36 @@ } #ifdef NEED_UMTX32 +#if defined(__amd64__) +struct timespecx32 { + int64_t tv_sec; + int32_t tv_nsec; +}; + +struct umtx_timex32 { + struct timespecx32 timeout; + uint32_t flags; + uint32_t clockid; +}; + +#define timespeci386 timespec32 +#define umtx_timei386 umtx_time32 +#else +struct timespeci386 { + int32_t tv_sec; + int32_t tv_nsec; +}; + +struct umtx_timei386 { + struct timespeci386 timeout; + uint32_t flags; + uint32_t clockid; +}; + +#define timespecx32 timespec32 +#define umtx_xtimex32 umtx_time32 +#endif + struct umtx_time32 { struct timespec32 timeout; uint32_t flags; @@ -4155,12 +4185,12 @@ }; static inline int -umtx_copyin_timeout32(const void *addr, struct timespec *tsp) +umtx_copyin_timeouti386(const void *addr, struct timespec *tsp) { - struct timespec32 ts32; + struct timespeci386 ts32; int error; - error = copyin(addr, &ts32, sizeof(struct timespec32)); + error = copyin(addr, &ts32, sizeof(struct timespeci386)); if (error == 0) { if (ts32.tv_sec < 0 || ts32.tv_nsec >= 1000000000 || @@ -4175,17 +4205,63 @@ } static inline int -umtx_copyin_umtx_time32(const void *addr, size_t size, struct _umtx_time *tp) +umtx_copyin_umtx_timei386(const void *addr, size_t size, struct _umtx_time *tp) { - struct umtx_time32 t32; + struct umtx_timei386 t32; int error; t32.clockid = CLOCK_REALTIME; t32.flags = 0; - if (size <= sizeof(struct timespec32)) - error = copyin(addr, &t32.timeout, sizeof(struct timespec32)); - else - error = copyin(addr, &t32, sizeof(struct umtx_time32)); + if (size <= sizeof(struct timespeci386)) { + error = copyin(addr, &t32.timeout, sizeof(struct timespeci386)); + } else { + error = copyin(addr, &t32, sizeof(struct umtx_timei386)); + } + if (error != 0) + return (error); + if (t32.timeout.tv_sec < 0 || + t32.timeout.tv_nsec >= 1000000000 || t32.timeout.tv_nsec < 0) + return (EINVAL); + tp->_timeout.tv_sec = t32.timeout.tv_sec; + tp->_timeout.tv_nsec = t32.timeout.tv_nsec; + tp->_flags = t32.flags; + tp->_clockid = t32.clockid; + return (0); +} + +static inline int +umtx_copyin_timeoutx32(const void *addr, struct timespec *tsp) +{ + struct timespecx32 ts32; + int error; + + error = copyin(addr, &ts32, sizeof(struct timespecx32)); + if (error == 0) { + if (ts32.tv_sec < 0 || + ts32.tv_nsec >= 1000000000 || + ts32.tv_nsec < 0) + error = EINVAL; + else { + tsp->tv_sec = ts32.tv_sec; + tsp->tv_nsec = ts32.tv_nsec; + } + } + return (error); +} + +static inline int +umtx_copyin_umtx_timex32(const void *addr, size_t size, struct _umtx_time *tp) +{ + struct umtx_timex32 t32; + int error; + + t32.clockid = CLOCK_REALTIME; + t32.flags = 0; + if (size <= sizeof(struct timespecx32)) { + error = copyin(addr, &t32.timeout, sizeof(struct timespecx32)); + } else { + error = copyin(addr, &t32, sizeof(struct umtx_timex32)); + } if (error != 0) return (error); if (t32.timeout.tv_sec < 0 || @@ -4218,9 +4294,23 @@ } static int -umtx_copyout_timeout32(void *addr, size_t sz, struct timespec *tsp) +umtx_copyout_timeoutx32(void *addr, size_t sz, struct timespec *tsp) { - struct timespec32 remain32 = { + struct timespecx32 remain32 = { + .tv_sec = tsp->tv_sec, + .tv_nsec = tsp->tv_nsec, + }; + + KASSERT(sz >= sizeof(struct timespec32), + ("_umtx_copyops specifies incorrect sizes")); + + return (copyout(&remain32, addr, sizeof(struct timespec32))); +} + +static int +umtx_copyout_timeouti386(void *addr, size_t sz, struct timespec *tsp) +{ + struct timespeci386 remain32 = { .tv_sec = tsp->tv_sec, .tv_nsec = tsp->tv_nsec, }; @@ -4280,15 +4370,32 @@ }; #ifdef NEED_UMTX32 -struct _umtx_copyops umtx_native_ops32 = { - .copyin_timeout = umtx_copyin_timeout32, - .copyin_umtx_time = umtx_copyin_umtx_time32, +struct _umtx_copyops umtx_native_opsx32 = { + .copyin_timeout = umtx_copyin_timeoutx32, + .copyin_umtx_time = umtx_copyin_umtx_timex32, .copyin_robust_lists = umtx_copyin_robust_lists32, - .copyout_timeout = umtx_copyout_timeout32, - .timespec_sz = sizeof(struct timespec32), - .umtx_time_sz = sizeof(struct umtx_time32), + .copyout_timeout = umtx_copyout_timeoutx32, + .timespec_sz = sizeof(struct timespecx32), + .umtx_time_sz = sizeof(struct umtx_timex32), }; -#endif + +struct _umtx_copyops umtx_native_opsi386 = { + .copyin_timeout = umtx_copyin_timeouti386, + .copyin_umtx_time = umtx_copyin_umtx_timei386, + .copyin_robust_lists = umtx_copyin_robust_lists32, + .copyout_timeout = umtx_copyout_timeouti386, + .timespec_sz = sizeof(struct timespeci386), + .umtx_time_sz = sizeof(struct umtx_timei386), +}; + +#ifdef __amd64__ +#define umtx_native_ops32 umtx_native_opsi386 +#else +#define umtx_native_ops32 umtx_native_opsx86 +#endif /* __amd64__ */ +#endif /* NEED_UMTX32 */ + +#define UMTX_OP__FLAGS (UMTX_OP__32BIT | UMTX_OP__32BIT_I386) static int kern__umtx_op(struct thread *td, void *obj, int op, unsigned long val, @@ -4296,7 +4403,7 @@ { struct _umtx_op_args uap = { .obj = obj, - .op = op, + .op = op & ~UMTX_OP__FLAGS, .val = val, .uaddr1 = uaddr1, .uaddr2 = uaddr2 @@ -4313,6 +4420,18 @@ struct _umtx_copyops *umtx_ops; umtx_ops = &umtx_native_ops; +#ifdef __LP64__ + if ((uap->op & UMTX_OP__32BIT) != 0) { + if ((uap->op & UMTX_OP__32BIT_I386) != 0) + umtx_ops = &umtx_native_opsi386; + else + umtx_ops = &umtx_native_opsx32; + } +#else + /* We consider UMTX_OP__32BIT a nop on ILP32. */ + if ((uap->op & UMTX_OP__32BIT_I386) != 0) + umtx_ops = &umtx_native_opsi386; +#endif return (kern__umtx_op(td, uap->obj, uap->op, uap->val, uap->uaddr1, uap->uaddr2, umtx_ops)); } Index: sys/sys/umtx.h =================================================================== --- sys/sys/umtx.h +++ sys/sys/umtx.h @@ -101,6 +101,9 @@ #define UMTX_OP_SHM 25 #define UMTX_OP_ROBUST_LISTS 26 +#define UMTX_OP__32BIT 0x80000000 +#define UMTX_OP__32BIT_I386 0x40000000 + /* Flags for UMTX_OP_CV_WAIT */ #define CVWAIT_CHECK_UNPARKING 0x01 #define CVWAIT_ABSTIME 0x02