1285307Sed/*-
2285307Sed * Copyright (c) 2015 Nuxi, https://nuxi.nl/
3285307Sed *
4285307Sed * Redistribution and use in source and binary forms, with or without
5285307Sed * modification, are permitted provided that the following conditions
6285307Sed * are met:
7285307Sed * 1. Redistributions of source code must retain the above copyright
8285307Sed *    notice, this list of conditions and the following disclaimer.
9285307Sed * 2. Redistributions in binary form must reproduce the above copyright
10285307Sed *    notice, this list of conditions and the following disclaimer in the
11285307Sed *    documentation and/or other materials provided with the distribution.
12285307Sed *
13285307Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14285307Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15285307Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16285307Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17285307Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18285307Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19285307Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20285307Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21285307Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22285307Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23285307Sed * SUCH DAMAGE.
24285307Sed */
25285307Sed
26285307Sed#include <sys/cdefs.h>
27285307Sed__FBSDID("$FreeBSD: stable/11/sys/compat/cloudabi/cloudabi_clock.c 316327 2017-03-31 08:43:07Z ed $");
28285307Sed
29285754Sed#include <sys/param.h>
30285754Sed#include <sys/proc.h>
31285754Sed#include <sys/stdint.h>
32316327Sed#include <sys/systm.h>
33285754Sed#include <sys/syscallsubr.h>
34285754Sed
35297247Sed#include <contrib/cloudabi/cloudabi_types_common.h>
36297247Sed
37285307Sed#include <compat/cloudabi/cloudabi_proto.h>
38285754Sed#include <compat/cloudabi/cloudabi_util.h>
39285307Sed
40285754Sed/* Converts a CloudABI clock ID to a FreeBSD clock ID. */
41285754Sedstatic int
42285754Sedcloudabi_convert_clockid(cloudabi_clockid_t in, clockid_t *out)
43285754Sed{
44285754Sed	switch (in) {
45285754Sed	case CLOUDABI_CLOCK_MONOTONIC:
46285754Sed		*out = CLOCK_MONOTONIC;
47285754Sed		return (0);
48285754Sed	case CLOUDABI_CLOCK_PROCESS_CPUTIME_ID:
49285754Sed		*out = CLOCK_PROCESS_CPUTIME_ID;
50285754Sed		return (0);
51285754Sed	case CLOUDABI_CLOCK_REALTIME:
52285754Sed		*out = CLOCK_REALTIME;
53285754Sed		return (0);
54285754Sed	case CLOUDABI_CLOCK_THREAD_CPUTIME_ID:
55285754Sed		*out = CLOCK_THREAD_CPUTIME_ID;
56285754Sed		return (0);
57285754Sed	default:
58285754Sed		return (EINVAL);
59285754Sed	}
60285754Sed}
61285754Sed
62285754Sed/* Converts a struct timespec to a CloudABI timestamp. */
63285307Sedint
64285754Sedcloudabi_convert_timespec(const struct timespec *in, cloudabi_timestamp_t *out)
65285754Sed{
66285754Sed	cloudabi_timestamp_t s, ns;
67285754Sed
68285754Sed	if (in->tv_sec < 0) {
69285754Sed		/* Timestamps from before the Epoch cannot be expressed. */
70285754Sed		*out = 0;
71285754Sed		return (EOVERFLOW);
72285754Sed	}
73285754Sed	s = in->tv_sec;
74285754Sed	ns = in->tv_nsec;
75285754Sed	if (s > UINT64_MAX / 1000000000 ||
76285754Sed	    (s == UINT64_MAX / 1000000000 && ns > UINT64_MAX % 1000000000)) {
77285754Sed		/* Addition of seconds and nanoseconds would overflow. */
78285754Sed		*out = UINT64_MAX;
79285754Sed		return (EOVERFLOW);
80285754Sed	}
81285754Sed	*out = s * 1000000000 + ns;
82285754Sed	return (0);
83285754Sed}
84285754Sed
85285908Sed/* Fetches the time value of a clock. */
86285754Sedint
87285908Sedcloudabi_clock_time_get(struct thread *td, cloudabi_clockid_t clock_id,
88285908Sed    cloudabi_timestamp_t *ret)
89285307Sed{
90285754Sed	struct timespec ts;
91285754Sed	int error;
92285754Sed	clockid_t clockid;
93285307Sed
94285908Sed	error = cloudabi_convert_clockid(clock_id, &clockid);
95285754Sed	if (error != 0)
96285754Sed		return (error);
97285908Sed	error = kern_clock_gettime(td, clockid, &ts);
98285754Sed	if (error != 0)
99285754Sed		return (error);
100285908Sed	return (cloudabi_convert_timespec(&ts, ret));
101285307Sed}
102285307Sed
103285307Sedint
104285908Sedcloudabi_sys_clock_res_get(struct thread *td,
105285908Sed    struct cloudabi_sys_clock_res_get_args *uap)
106285307Sed{
107285754Sed	struct timespec ts;
108285754Sed	cloudabi_timestamp_t cts;
109285754Sed	int error;
110285754Sed	clockid_t clockid;
111285307Sed
112285754Sed	error = cloudabi_convert_clockid(uap->clock_id, &clockid);
113285754Sed	if (error != 0)
114285754Sed		return (error);
115285908Sed	error = kern_clock_getres(td, clockid, &ts);
116285754Sed	if (error != 0)
117285754Sed		return (error);
118285754Sed	error = cloudabi_convert_timespec(&ts, &cts);
119285754Sed	if (error != 0)
120285754Sed		return (error);
121307144Sed	memcpy(td->td_retval, &cts, sizeof(cts));
122285754Sed	return (0);
123285307Sed}
124285908Sed
125285908Sedint
126285908Sedcloudabi_sys_clock_time_get(struct thread *td,
127285908Sed    struct cloudabi_sys_clock_time_get_args *uap)
128285908Sed{
129285908Sed	cloudabi_timestamp_t ts;
130285908Sed	int error;
131285908Sed
132285908Sed	error = cloudabi_clock_time_get(td, uap->clock_id, &ts);
133307144Sed	memcpy(td->td_retval, &ts, sizeof(ts));
134285908Sed	return (error);
135285908Sed}
136