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