]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClock.c
8323a4b4b84876aec4e42f68685a445a04719a99
[mirror_edk2.git] / EmbeddedPkg / RealTimeClockRuntimeDxe / RealTimeClock.c
1 /** @file
2 Implement EFI RealTimeClock runtime services via RTC Lib.
3
4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
5 Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
6
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include <PiDxe.h>
18 #include <Library/DebugLib.h>
19 #include <Library/RealTimeClockLib.h>
20 #include <Library/UefiLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/UefiRuntimeLib.h>
23 #include <Protocol/RealTimeClock.h>
24
25 EFI_HANDLE mHandle = NULL;
26
27 //
28 // These values can be set by SetTime () and need to be returned by GetTime ()
29 // but cannot usually be kept by the RTC hardware, so we store them in a UEFI
30 // variable instead.
31 //
32 typedef struct {
33 INT16 TimeZone;
34 UINT8 Daylight;
35 } NON_VOLATILE_TIME_SETTINGS;
36
37 STATIC CONST CHAR16 mTimeSettingsVariableName[] = L"RtcTimeSettings";
38 STATIC NON_VOLATILE_TIME_SETTINGS mTimeSettings;
39
40 STATIC
41 BOOLEAN
42 IsValidTimeZone (
43 IN INT16 TimeZone
44 )
45 {
46 return TimeZone == EFI_UNSPECIFIED_TIMEZONE ||
47 (TimeZone >= -1440 && TimeZone <= 1440);
48 }
49
50 STATIC
51 BOOLEAN
52 IsValidDaylight (
53 IN INT8 Daylight
54 )
55 {
56 return Daylight == 0 ||
57 Daylight == EFI_TIME_ADJUST_DAYLIGHT ||
58 Daylight == (EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT);
59 }
60
61 STATIC
62 BOOLEAN
63 EFIAPI
64 IsLeapYear (
65 IN EFI_TIME *Time
66 )
67 {
68 if (Time->Year % 4 == 0) {
69 if (Time->Year % 100 == 0) {
70 if (Time->Year % 400 == 0) {
71 return TRUE;
72 } else {
73 return FALSE;
74 }
75 } else {
76 return TRUE;
77 }
78 } else {
79 return FALSE;
80 }
81 }
82
83 STATIC CONST INTN mDayOfMonth[12] = {
84 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
85 };
86
87 STATIC
88 BOOLEAN
89 EFIAPI
90 IsDayValid (
91 IN EFI_TIME *Time
92 )
93 {
94 ASSERT (Time->Day >= 1);
95 ASSERT (Time->Day <= mDayOfMonth[Time->Month - 1]);
96 ASSERT (Time->Month != 2 || IsLeapYear (Time) || Time->Day <= 28);
97
98 if (Time->Day < 1 ||
99 Time->Day > mDayOfMonth[Time->Month - 1] ||
100 (Time->Month == 2 && !IsLeapYear (Time) && Time->Day > 28)) {
101 return FALSE;
102 }
103 return TRUE;
104 }
105
106 STATIC
107 BOOLEAN
108 EFIAPI
109 IsTimeValid(
110 IN EFI_TIME *Time
111 )
112 {
113 // Check the input parameters are within the range specified by UEFI
114 if (Time->Year < 1900 ||
115 Time->Year > 9999 ||
116 Time->Month < 1 ||
117 Time->Month > 12 ||
118 !IsDayValid (Time) ||
119 Time->Hour > 23 ||
120 Time->Minute > 59 ||
121 Time->Second > 59 ||
122 !IsValidTimeZone (Time->TimeZone) ||
123 !IsValidDaylight (Time->Daylight)) {
124 return FALSE;
125 }
126 return TRUE;
127 }
128
129 /**
130 Returns the current time and date information, and the time-keeping capabilities
131 of the hardware platform.
132
133 @param Time A pointer to storage to receive a snapshot of the current time.
134 @param Capabilities An optional pointer to a buffer to receive the real time clock
135 device's capabilities.
136
137 @retval EFI_SUCCESS The operation completed successfully.
138 @retval EFI_INVALID_PARAMETER Time is NULL.
139 @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.
140
141 **/
142 EFI_STATUS
143 EFIAPI
144 GetTime (
145 OUT EFI_TIME *Time,
146 OUT EFI_TIME_CAPABILITIES *Capabilities
147 )
148 {
149 if (Time == NULL) {
150 return EFI_INVALID_PARAMETER;
151 }
152
153 //
154 // Set these first so the RealTimeClockLib implementation
155 // can override them based on its own settings.
156 //
157 Time->TimeZone = mTimeSettings.TimeZone;
158 Time->Daylight = mTimeSettings.Daylight;
159
160 return LibGetTime (Time, Capabilities);
161 }
162
163
164
165 /**
166 Sets the current local time and date information.
167
168 @param Time A pointer to the current time.
169
170 @retval EFI_SUCCESS The operation completed successfully.
171 @retval EFI_INVALID_PARAMETER A time field is out of range.
172 @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error.
173
174 **/
175 EFI_STATUS
176 EFIAPI
177 SetTime (
178 IN EFI_TIME *Time
179 )
180 {
181 EFI_STATUS Status;
182 BOOLEAN TimeSettingsChanged;
183
184 if (Time == NULL || !IsTimeValid (Time)) {
185 return EFI_INVALID_PARAMETER;
186 }
187
188 TimeSettingsChanged = FALSE;
189 if (mTimeSettings.TimeZone != Time->TimeZone ||
190 mTimeSettings.Daylight != Time->Daylight) {
191
192 mTimeSettings.TimeZone = Time->TimeZone;
193 mTimeSettings.Daylight = Time->Daylight;
194 TimeSettingsChanged = TRUE;
195 }
196
197 Status = LibSetTime (Time);
198 if (EFI_ERROR (Status)) {
199 return Status;
200 }
201
202 if (TimeSettingsChanged) {
203 Status = EfiSetVariable (
204 (CHAR16 *)mTimeSettingsVariableName,
205 &gEfiCallerIdGuid,
206 EFI_VARIABLE_NON_VOLATILE |
207 EFI_VARIABLE_BOOTSERVICE_ACCESS |
208 EFI_VARIABLE_RUNTIME_ACCESS,
209 sizeof (mTimeSettings),
210 (VOID *)&mTimeSettings);
211 if (EFI_ERROR (Status)) {
212 return EFI_DEVICE_ERROR;
213 }
214 }
215 return EFI_SUCCESS;
216 }
217
218
219 /**
220 Returns the current wakeup alarm clock setting.
221
222 @param Enabled Indicates if the alarm is currently enabled or disabled.
223 @param Pending Indicates if the alarm signal is pending and requires acknowledgement.
224 @param Time The current alarm setting.
225
226 @retval EFI_SUCCESS The alarm settings were returned.
227 @retval EFI_INVALID_PARAMETER Any parameter is NULL.
228 @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.
229
230 **/
231 EFI_STATUS
232 EFIAPI
233 GetWakeupTime (
234 OUT BOOLEAN *Enabled,
235 OUT BOOLEAN *Pending,
236 OUT EFI_TIME *Time
237 )
238 {
239 return LibGetWakeupTime (Enabled, Pending, Time);
240 }
241
242
243 /**
244 Sets the system wakeup alarm clock time.
245
246 @param Enabled Enable or disable the wakeup alarm.
247 @param Time If Enable is TRUE, the time to set the wakeup alarm for.
248
249 @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If
250 Enable is FALSE, then the wakeup alarm was disabled.
251 @retval EFI_INVALID_PARAMETER A time field is out of range.
252 @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.
253 @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
254
255 **/
256 EFI_STATUS
257 EFIAPI
258 SetWakeupTime (
259 IN BOOLEAN Enabled,
260 OUT EFI_TIME *Time
261 )
262 {
263 return LibSetWakeupTime (Enabled, Time);
264 }
265
266
267
268 /**
269 This is the declaration of an EFI image entry point. This can be the entry point to an application
270 written to this specification, an EFI boot service driver, or an EFI runtime driver.
271
272 @param ImageHandle Handle that identifies the loaded image.
273 @param SystemTable System Table for this image.
274
275 @retval EFI_SUCCESS The operation completed successfully.
276
277 **/
278 EFI_STATUS
279 EFIAPI
280 InitializeRealTimeClock (
281 IN EFI_HANDLE ImageHandle,
282 IN EFI_SYSTEM_TABLE *SystemTable
283 )
284 {
285 EFI_STATUS Status;
286 UINTN Size;
287
288 Status = LibRtcInitialize (ImageHandle, SystemTable);
289 if (EFI_ERROR (Status)) {
290 return Status;
291 }
292
293 Size = sizeof (mTimeSettings);
294 Status = EfiGetVariable ((CHAR16 *)mTimeSettingsVariableName,
295 &gEfiCallerIdGuid, NULL, &Size, (VOID *)&mTimeSettings);
296 if (EFI_ERROR (Status) ||
297 !IsValidTimeZone (mTimeSettings.TimeZone) ||
298 !IsValidDaylight (mTimeSettings.Daylight)) {
299 DEBUG ((DEBUG_WARN, "%a: using default timezone/daylight settings\n",
300 __FUNCTION__));
301
302 mTimeSettings.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
303 mTimeSettings.Daylight = 0;
304 }
305
306 SystemTable->RuntimeServices->GetTime = GetTime;
307 SystemTable->RuntimeServices->SetTime = SetTime;
308 SystemTable->RuntimeServices->GetWakeupTime = GetWakeupTime;
309 SystemTable->RuntimeServices->SetWakeupTime = SetWakeupTime;
310
311 Status = gBS->InstallMultipleProtocolInterfaces (
312 &mHandle,
313 &gEfiRealTimeClockArchProtocolGuid,
314 NULL,
315 NULL
316 );
317
318 return Status;
319 }
320