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