@@ -124,19 +124,19 @@ static inline abi_long do_freebsd_gettimeofday(abi_ulong arg1, abi_ulong arg2)
struct timeval tv;
struct timezone tz, *target_tz; /* XXX */
- if (arg2 != 0) {
- if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) {
- return -TARGET_EFAULT;
- }
- __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
- __get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
- unlock_user_struct(target_tz, arg2, 1);
- }
ret = get_errno(gettimeofday(&tv, arg2 != 0 ? &tz : NULL));
if (!is_error(ret)) {
if (h2t_freebsd_timeval(&tv, arg1)) {
return -TARGET_EFAULT;
}
+ if (arg2 != 0) {
+ if (!lock_user_struct(VERIFY_WRITE, target_tz, arg2, 0)) {
+ return -TARGET_EFAULT;
+ }
+ __put_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
+ __put_user(tz.tz_dsttime, &target_tz->tz_dsttime);
+ unlock_user_struct(target_tz, arg2, 1);
+ }
}
return ret;
@@ -149,12 +149,12 @@ static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2)
struct timezone tz, *target_tz; /* XXX */
if (arg2 != 0) {
- if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) {
+ if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 1)) {
return -TARGET_EFAULT;
}
__get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
__get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
- unlock_user_struct(target_tz, arg2, 1);
+ unlock_user_struct(target_tz, arg2, 0);
}
if (t2h_freebsd_timeval(&tv, arg1)) {
return -TARGET_EFAULT;
@@ -595,6 +595,7 @@ static inline abi_long do_freebsd_ppoll(CPUArchState *env, abi_long arg1,
/* Unlike poll(), ppoll() uses struct timespec. */
if (arg3) {
if (t2h_freebsd_timespec(&ts, arg3)) {
+ unlock_user(target_pfd, arg1, 0);
return -TARGET_EFAULT;
}
ts_ptr = &ts;
@@ -605,6 +606,7 @@ static inline abi_long do_freebsd_ppoll(CPUArchState *env, abi_long arg1,
if (arg4 != 0) {
p = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
if (p == NULL) {
+ unlock_user(target_pfd, arg1, 0);
return -TARGET_EFAULT;
}
target_to_host_sigset(&tstate->sigsuspend_mask, p);
@@ -802,5 +804,177 @@ static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
}
/* sigtimedwait(2) */
+static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2,
+ abi_ulong arg3)
+{
+ abi_long ret;
+ void *p;
+ sigset_t set;
+ struct timespec uts, *puts;
+ siginfo_t uinfo;
+
+ p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+ if (p == NULL) {
+ return -TARGET_EFAULT;
+ }
+ target_to_host_sigset(&set, p);
+ unlock_user(p, arg1, 0);
+ if (arg3) {
+ puts = &uts;
+ ret = t2h_freebsd_timespec(puts, arg3);
+ if (ret != 0) {
+ return ret;
+ }
+ } else {
+ puts = NULL;
+ }
+ ret = get_errno(sigtimedwait(&set, &uinfo, puts));
+ if (!is_error(ret) && arg2) {
+ p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0);
+ if (p == NULL) {
+ return -TARGET_EFAULT;
+ }
+ host_to_target_siginfo(p, &uinfo);
+ unlock_user(p, arg2, sizeof(target_siginfo_t));
+ }
+ return ret;
+}
+
+/* setitimer(2) */
+static inline abi_long do_freebsd_setitimer(int arg1, abi_ulong arg2,
+ abi_ulong arg3)
+{
+ abi_long ret = 0;
+ struct itimerval value, ovalue, *pvalue;
+
+ if (arg2) {
+ pvalue = &value;
+ if (t2h_freebsd_timeval(&pvalue->it_interval, arg2) ||
+ t2h_freebsd_timeval(&pvalue->it_value,
+ arg2 + sizeof(struct target_freebsd_timeval))) {
+ return -TARGET_EFAULT;
+ }
+ } else {
+ pvalue = NULL;
+ }
+ ret = get_errno(setitimer(arg1, pvalue, &ovalue));
+ if (!is_error(ret) && arg3) {
+ if (h2t_freebsd_timeval(&ovalue.it_interval, arg3) ||
+ h2t_freebsd_timeval(&ovalue.it_value,
+ arg3 + sizeof(struct target_freebsd_timeval))) {
+ return -TARGET_EFAULT;
+ }
+ }
+ return ret;
+}
+
+/* getitimer(2) */
+static inline abi_long do_freebsd_getitimer(int arg1, abi_ulong arg2)
+{
+ abi_long ret = 0;
+ struct itimerval value;
+
+ ret = get_errno(getitimer(arg1, &value));
+ if (!is_error(ret) && arg2) {
+ if (h2t_freebsd_timeval(&value.it_interval, arg2) ||
+ h2t_freebsd_timeval(&value.it_value,
+ arg2 + sizeof(struct target_freebsd_timeval))) {
+ return -TARGET_EFAULT;
+ }
+ }
+ return ret;
+}
+
+/* clock_getcpuclockid2(id_t, int, clockid_t *) Not documented. */
+static inline abi_long do_freebsd_clock_getcpuclockid2(abi_ulong arg1,
+ abi_ulong arg2, abi_ulong arg3, abi_ulong arg4)
+{
+ abi_long ret = 0;
+ id_t id; /* 64-bit value */
+ int which;
+ abi_ulong target_clk_id_addr;
+ clockid_t clk_id;
+
+#if TARGET_ABI_BITS == 32
+ id = (id_t)target_arg64(arg1, arg2);
+ which = (int)arg3;
+ target_clk_id_addr = arg4;
+#else
+ id = (id_t)arg1;
+ which = (int)arg2;
+ target_clk_id_addr = arg3;
+#endif
+
+ if (target_clk_id_addr == 0) {
+ return -TARGET_EINVAL;
+ }
+
+ switch (which) {
+ case TARGET_CPUCLOCK_WHICH_PID:
+ ret = get_errno(clock_getcpuclockid2(id, CPUCLOCK_WHICH_PID, &clk_id));
+ break;
+
+ case TARGET_CPUCLOCK_WHICH_TID:
+ ret = get_errno(clock_getcpuclockid2(id, CPUCLOCK_WHICH_TID, &clk_id));
+ break;
+
+ default:
+ ret = -TARGET_EINVAL;
+ break;
+ }
+
+ if (!ret && put_user_s32(clk_id, target_clk_id_addr)) {
+ ret = -TARGET_EFAULT;
+ }
+
+ return ret;
+}
+
+static inline abi_long do_freebsd_futimens(abi_ulong arg1,
+ abi_ulong arg2)
+{
+ struct timespec *tvp, tv[2];
+
+ if (arg2 != 0) {
+ if (t2h_freebsd_timespec(&tv[0], arg2) ||
+ t2h_freebsd_timespec(&tv[1], arg2 +
+ sizeof(struct target_freebsd_timespec))) {
+ return -TARGET_EFAULT;
+ }
+ tvp = tv;
+ } else {
+ tvp = NULL;
+ }
+
+ return get_errno(futimens(arg1, tvp));
+}
+
+static inline abi_long do_freebsd_utimensat(abi_ulong arg1,
+ abi_ulong arg2, abi_ulong arg3, abi_ulong arg4)
+{
+ abi_long ret = 0;
+ void *p;
+ struct timespec *tvp, tv[2];
+
+ if (arg3 != 0) {
+ if (t2h_freebsd_timespec(&tv[0], arg3) ||
+ t2h_freebsd_timespec(&tv[1], arg3 +
+ sizeof(struct target_freebsd_timespec))) {
+ return -TARGET_EFAULT;
+ }
+ tvp = tv;
+ } else {
+ tvp = NULL;
+ }
+
+ p = lock_user_string(arg2);
+ if (p == NULL) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(utimensat(arg1, p, tvp,
+ target_to_host_bitmask(arg4, fcntl_flags_tbl)));
+ unlock_user(p, arg2, 0);
+ return ret;
+}
#endif /* FREEBSD_OS_TIME_H */