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 */
64static 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
94void
95efi_time_init(void)
96{
97}
98
99void
100efi_time_fini(void)
101{
102}
103
104void
105to_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
149time_t
150from_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
220static int
221EFI_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
262time_t
263time(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
275time_t
276getsecs(void)
277{
278
279    return (time(NULL));
280}
281