1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <assert.h>
18 #include <errno.h>
19 #include <trusty/time.h>
20 #include <trusty_syscalls.h>
21
22 #define NS_PER_SEC 1000000000
23
trusty_nanosleep(clockid_t clock_id,uint32_t flags,uint64_t sleep_time)24 int trusty_nanosleep(clockid_t clock_id, uint32_t flags, uint64_t sleep_time) {
25 /* TODO validate clock_ids. */
26 /* No flags, yet. */
27 assert(flags == 0);
28 return _trusty_nanosleep(clock_id, flags, sleep_time);
29 }
30
trusty_nanodelay(clockid_t clock_id,uint32_t flags,uint64_t sleep_time)31 int trusty_nanodelay(clockid_t clock_id, uint32_t flags, uint64_t sleep_time) {
32 int64_t target, time;
33 int rc;
34
35 /* TODO validate clock_ids. */
36 /* No flags, yet. */
37 assert(flags == 0);
38
39 rc = trusty_gettime(clock_id, &time);
40 if (rc)
41 return rc;
42 target = time + sleep_time;
43
44 while (time < target) {
45 rc = trusty_gettime(clock_id, &time);
46 if (rc)
47 return rc;
48 }
49
50 return 0;
51 }
52
clock_nanosleep(clockid_t clock_id,int flags,const struct timespec * req,struct timespec * rem)53 int clock_nanosleep(clockid_t clock_id,
54 int flags,
55 const struct timespec* req,
56 struct timespec* rem) {
57 /* Validate inputs. */
58 if (!req) {
59 errno = EFAULT;
60 return -1;
61 }
62 if (req->tv_sec < 0) {
63 errno = EINVAL;
64 return -1;
65 }
66 if (req->tv_nsec >= NS_PER_SEC || req->tv_nsec < 0) {
67 errno = EINVAL;
68 return -1;
69 }
70 /* Convert timespec to nanoseconds. */
71 uint64_t sleep_time;
72 /*
73 * Note: casting NS_PER_SEC to work around a Clang codegen bug.
74 * See: b/145830721
75 */
76 if (__builtin_mul_overflow(req->tv_sec, (uint64_t)NS_PER_SEC,
77 &sleep_time)) {
78 errno = EINVAL;
79 return -1;
80 }
81 if (__builtin_add_overflow(sleep_time, req->tv_nsec, &sleep_time)) {
82 errno = EINVAL;
83 return -1;
84 }
85 /* Actually sleep. */
86 int ret = trusty_nanosleep(clock_id, flags, sleep_time);
87 /* Handle the result. */
88 if (rem) {
89 /* Trusty should not wake up early, except for clock rounding. */
90 rem->tv_sec = 0;
91 rem->tv_nsec = 0;
92 }
93 if (ret) {
94 /* clock_id was invalid? */
95 errno = EINVAL;
96 return -1;
97 }
98 return 0;
99 }
100
nanosleep(const struct timespec * req,struct timespec * rem)101 int nanosleep(const struct timespec* req, struct timespec* rem) {
102 return clock_nanosleep(CLOCK_BOOTTIME, 0, req, rem);
103 }
104
trusty_gettime(clockid_t clock_id,int64_t * time)105 int trusty_gettime(clockid_t clock_id, int64_t* time) {
106 return _trusty_gettime(clock_id, 0, time);
107 }
108
__clock_gettime(clockid_t clock_id,struct timespec * ts)109 int __clock_gettime(clockid_t clock_id, struct timespec* ts) {
110 if (ts == NULL) {
111 errno = EFAULT;
112 return -1;
113 }
114 int64_t time;
115 int rc = trusty_gettime(clock_id, &time);
116 if (rc) {
117 /* &time is valid, so clock_id must have been invalid. */
118 errno = EINVAL;
119 return -1;
120 }
121 ts->tv_sec = (time_t)(time / NS_PER_SEC);
122 ts->tv_nsec = (long)(time % NS_PER_SEC);
123 return 0;
124 }
125
126 /*
127 * Internally, Musl references __clock_gettime, and then provides an alias for
128 * external users. Since we're providing the function, we need to provide the
129 * internal name for Musl and the external name for the user.
130 */
131 weak_alias(__clock_gettime, clock_gettime);
132