1 /*-
2 * Copyright (c) 1999, 2000
3 * Intel Corporation.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 *
20 * This product includes software developed by Intel Corporation and
21 * its contributors.
22 *
23 * 4. Neither the name of Intel Corporation or its contributors may be
24 * used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS''
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
37 * THE POSSIBILITY OF SUCH DAMAGE.
38 *
39 */
40
41 #include <efi.h>
42 #include <efilib.h>
43
44 #include <time.h>
45 #include <sys/time.h>
46
47 /*
48 * Accurate only for the past couple of centuries;
49 * that will probably do.
50 *
51 * (#defines From FreeBSD 3.2 lib/libc/stdtime/tzfile.h)
52 */
53
54 #define isleap(y) (((y) % 4) == 0 && \
55 (((y) % 100) != 0 || ((y) % 400) == 0))
56 #define SECSPERHOUR (60*60)
57 #define SECSPERDAY (24 * SECSPERHOUR)
58
59 /*
60 * These arrays give the cumulative number of days up to the first of the
61 * month number used as the index (1 -> 12) for regular and leap years.
62 * The value at index 13 is for the whole year.
63 */
64 static const time_t CumulativeDays[2][14] = {
65 {0,
66 0,
67 31,
68 31 + 28,
69 31 + 28 + 31,
70 31 + 28 + 31 + 30,
71 31 + 28 + 31 + 30 + 31,
72 31 + 28 + 31 + 30 + 31 + 30,
73 31 + 28 + 31 + 30 + 31 + 30 + 31,
74 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
75 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
76 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
77 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
78 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 },
79 {0,
80 0,
81 31,
82 31 + 29,
83 31 + 29 + 31,
84 31 + 29 + 31 + 30,
85 31 + 29 + 31 + 30 + 31,
86 31 + 29 + 31 + 30 + 31 + 30,
87 31 + 29 + 31 + 30 + 31 + 30 + 31,
88 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
89 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
90 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
91 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
92 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }};
93
94 void
efi_time_init(void)95 efi_time_init(void)
96 {
97 }
98
99 void
efi_time_fini(void)100 efi_time_fini(void)
101 {
102 }
103
104 void
to_efi_time(EFI_TIME * efi_time,time_t time)105 to_efi_time(EFI_TIME *efi_time, time_t time)
106 {
107 int lyear, month;
108 time_t seconds;
109
110 if (time >= 0) {
111 efi_time->Year = 1970;
112 lyear = isleap(efi_time->Year);
113 month = 13;
114 seconds = CumulativeDays[lyear][month] * SECSPERDAY;
115 while (time > seconds) {
116 time -= seconds;
117 efi_time->Year++;
118 lyear = isleap(efi_time->Year);
119 seconds = CumulativeDays[lyear][month] * SECSPERDAY;
120 }
121
122 efi_time->Month = 0;
123 while (time >
124 CumulativeDays[lyear][month] * SECSPERDAY) {
125 efi_time->Month++;
126 }
127
128 month = efi_time->Month - 1;
129 time -= CumulativeDays[lyear][month] * SECSPERDAY;
130
131 for (efi_time->Day = 0; time > SECSPERDAY; efi_time->Day++)
132 time -= SECSPERDAY;
133
134 for (efi_time->Hour = 0; time > SECSPERHOUR; efi_time->Hour++)
135 time -= SECSPERHOUR;
136
137 for (efi_time->Minute = 0; time > 60; efi_time->Minute++)
138 time -= 60;
139
140 efi_time->Second = time;
141 efi_time->Nanosecond = 0;
142 efi_time->TimeZone = 0;
143 efi_time->Daylight = 0;
144 } else {
145 memset(efi_time, 0, sizeof(EFI_TIME));
146 }
147 }
148
149 time_t
from_efi_time(EFI_TIME * ETime)150 from_efi_time(EFI_TIME *ETime)
151 {
152 time_t UTime;
153 int Year;
154
155 /*
156 * Do a santity check
157 */
158 if (ETime->Year < 1998 || ETime->Year > 2099 ||
159 ETime->Month == 0 || ETime->Month > 12 ||
160 ETime->Day == 0 || ETime->Month > 31 ||
161 ETime->Hour > 23 || ETime->Minute > 59 ||
162 ETime->Second > 59 || ETime->TimeZone < -1440 ||
163 (ETime->TimeZone > 1440 && ETime->TimeZone != 2047)) {
164 return (0);
165 }
166
167 /*
168 * Years
169 */
170 UTime = 0;
171 for (Year = 1970; Year != ETime->Year; ++Year) {
172 UTime += (CumulativeDays[isleap(Year)][13] * SECSPERDAY);
173 }
174
175 /*
176 * UTime should now be set to 00:00:00 on Jan 1 of the file's year.
177 *
178 * Months
179 */
180 UTime += (CumulativeDays[isleap(ETime->Year)][ETime->Month] *
181 SECSPERDAY);
182
183 /*
184 * UTime should now be set to 00:00:00 on the first of the file's
185 * month and year.
186 *
187 * Days -- Don't count the file's day
188 */
189 UTime += (((ETime->Day > 0) ? ETime->Day-1:0) * SECSPERDAY);
190
191 /*
192 * Hours
193 */
194 UTime += (ETime->Hour * SECSPERHOUR);
195
196 /*
197 * Minutes
198 */
199 UTime += (ETime->Minute * 60);
200
201 /*
202 * Seconds
203 */
204 UTime += ETime->Second;
205
206 /*
207 * EFI time is repored in local time. Adjust for any time zone
208 * offset to get true UT
209 */
210 if (ETime->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
211 /*
212 * TimeZone is kept in minues...
213 */
214 UTime += (ETime->TimeZone * 60);
215 }
216
217 return (UTime);
218 }
219
220 static int
EFI_GetTimeOfDay(OUT struct timeval * tp,OUT struct timezone * tzp)221 EFI_GetTimeOfDay(OUT struct timeval *tp, OUT struct timezone *tzp)
222 {
223 EFI_TIME EfiTime;
224 EFI_TIME_CAPABILITIES Capabilities;
225 EFI_STATUS Status;
226
227 /*
228 * Get time from EFI
229 */
230
231 Status = RS->GetTime(&EfiTime, &Capabilities);
232 if (EFI_ERROR(Status))
233 return (-1);
234
235 /*
236 * Convert to UNIX time (ie seconds since the epoch
237 */
238
239 tp->tv_sec = from_efi_time(&EfiTime);
240 tp->tv_usec = 0; /* EfiTime.Nanosecond * 1000; */
241
242 /*
243 * Do something with the timezone if needed
244 */
245
246 if (tzp != NULL) {
247 if (EfiTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE)
248 tzp->tz_minuteswest = 0;
249 else
250 tzp->tz_minuteswest = EfiTime.TimeZone;
251 /*
252 * This isn't quit right since it doesn't deal with
253 * EFI_TIME_IN_DAYLIGHT
254 */
255 tzp->tz_dsttime =
256 EfiTime.Daylight & EFI_TIME_ADJUST_DAYLIGHT ? 1 : 0;
257 }
258
259 return (0);
260 }
261
262 time_t
time(time_t * tloc)263 time(time_t *tloc)
264 {
265 struct timeval tv;
266
267 memset(&tv, 0, sizeof(tv));
268 EFI_GetTimeOfDay(&tv, NULL);
269
270 if (tloc)
271 *tloc = tv.tv_sec;
272 return (tv.tv_sec);
273 }
274
275 time_t
getsecs(void)276 getsecs(void)
277 {
278
279 return (time(NULL));
280 }
281