1 /*- 2 * Copyright (c) 2015 Nuxi, https://nuxi.nl/ 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include <sys/param.h> 30 #include <sys/proc.h> 31 #include <sys/stdint.h> 32 #include <sys/syscallsubr.h> 33 34 #include <contrib/cloudabi/cloudabi_types_common.h> 35 36 #include <compat/cloudabi/cloudabi_proto.h> 37 #include <compat/cloudabi/cloudabi_util.h> 38 39 /* Converts a CloudABI clock ID to a FreeBSD clock ID. */ 40 static int 41 cloudabi_convert_clockid(cloudabi_clockid_t in, clockid_t *out) 42 { 43 switch (in) { 44 case CLOUDABI_CLOCK_MONOTONIC: 45 *out = CLOCK_MONOTONIC; 46 return (0); 47 case CLOUDABI_CLOCK_PROCESS_CPUTIME_ID: 48 *out = CLOCK_PROCESS_CPUTIME_ID; 49 return (0); 50 case CLOUDABI_CLOCK_REALTIME: 51 *out = CLOCK_REALTIME; 52 return (0); 53 case CLOUDABI_CLOCK_THREAD_CPUTIME_ID: 54 *out = CLOCK_THREAD_CPUTIME_ID; 55 return (0); 56 default: 57 return (EINVAL); 58 } 59 } 60 61 /* Converts a struct timespec to a CloudABI timestamp. */ 62 int 63 cloudabi_convert_timespec(const struct timespec *in, cloudabi_timestamp_t *out) 64 { 65 cloudabi_timestamp_t s, ns; 66 67 if (in->tv_sec < 0) { 68 /* Timestamps from before the Epoch cannot be expressed. */ 69 *out = 0; 70 return (EOVERFLOW); 71 } 72 s = in->tv_sec; 73 ns = in->tv_nsec; 74 if (s > UINT64_MAX / 1000000000 || 75 (s == UINT64_MAX / 1000000000 && ns > UINT64_MAX % 1000000000)) { 76 /* Addition of seconds and nanoseconds would overflow. */ 77 *out = UINT64_MAX; 78 return (EOVERFLOW); 79 } 80 *out = s * 1000000000 + ns; 81 return (0); 82 } 83 84 /* Fetches the time value of a clock. */ 85 int 86 cloudabi_clock_time_get(struct thread *td, cloudabi_clockid_t clock_id, 87 cloudabi_timestamp_t *ret) 88 { 89 struct timespec ts; 90 int error; 91 clockid_t clockid; 92 93 error = cloudabi_convert_clockid(clock_id, &clockid); 94 if (error != 0) 95 return (error); 96 error = kern_clock_gettime(td, clockid, &ts); 97 if (error != 0) 98 return (error); 99 return (cloudabi_convert_timespec(&ts, ret)); 100 } 101 102 int 103 cloudabi_sys_clock_res_get(struct thread *td, 104 struct cloudabi_sys_clock_res_get_args *uap) 105 { 106 struct timespec ts; 107 cloudabi_timestamp_t cts; 108 int error; 109 clockid_t clockid; 110 111 error = cloudabi_convert_clockid(uap->clock_id, &clockid); 112 if (error != 0) 113 return (error); 114 error = kern_clock_getres(td, clockid, &ts); 115 if (error != 0) 116 return (error); 117 error = cloudabi_convert_timespec(&ts, &cts); 118 if (error != 0) 119 return (error); 120 memcpy(td->td_retval, &cts, sizeof(cts)); 121 return (0); 122 } 123 124 int 125 cloudabi_sys_clock_time_get(struct thread *td, 126 struct cloudabi_sys_clock_time_get_args *uap) 127 { 128 cloudabi_timestamp_t ts; 129 int error; 130 131 error = cloudabi_clock_time_get(td, uap->clock_id, &ts); 132 memcpy(td->td_retval, &ts, sizeof(ts)); 133 return (error); 134 } 135