TianoCore EDK2 master
Loading...
Searching...
No Matches
VirtualRealTimeClockLib.c
Go to the documentation of this file.
1
17#include <PiDxe.h>
18#include <Library/BaseLib.h>
19#include <Library/DebugLib.h>
20#include <Library/IoLib.h>
22#include <Library/TimerLib.h>
23#include <Library/TimeBaseLib.h>
25
26STATIC CONST CHAR16 mEpochVariableName[] = L"RtcEpochSeconds";
27STATIC CONST CHAR16 mTimeZoneVariableName[] = L"RtcTimeZone";
28STATIC CONST CHAR16 mDaylightVariableName[] = L"RtcDaylight";
29
44EFIAPI
46 OUT EFI_TIME *Time,
47 OUT EFI_TIME_CAPABILITIES *Capabilities
48 )
49{
50 EFI_STATUS Status;
51 INT16 TimeZone;
52 UINT8 Daylight;
53 UINT64 Freq;
54 UINT64 Counter;
55 UINT64 Remainder;
56 UINTN EpochSeconds;
57 UINTN Size;
58
59 if (Time == NULL) {
60 return EFI_INVALID_PARAMETER;
61 }
62
63 // Get the counter frequency
65 if (Freq == 0) {
66 return EFI_DEVICE_ERROR;
67 }
68
69 // Get the epoch time from non-volatile storage
70 Size = sizeof (UINTN);
71 EpochSeconds = 0;
72 Status = EfiGetVariable (
73 (CHAR16 *)mEpochVariableName,
74 &gEfiCallerIdGuid,
75 NULL,
76 &Size,
77 (VOID *)&EpochSeconds
78 );
79 // Fall back to compilation-time epoch if not set
80 if (EFI_ERROR (Status)) {
81 ASSERT (Status != EFI_INVALID_PARAMETER);
82 ASSERT (Status != EFI_BUFFER_TOO_SMALL);
83 //
84 // The following is intended to produce a compilation error on build
85 // environments where BUILD_EPOCH can not be set from inline shell.
86 // If you are attempting to use this library on such an environment, please
87 // contact the edk2 mailing list, so we can try to add support for it.
88 //
89 EpochSeconds = BUILD_EPOCH;
90 DEBUG ((
91 DEBUG_INFO,
92 "LibGetTime: %s non volatile variable was not found - Using compilation time epoch.\n",
93 mEpochVariableName
94 ));
95
97 (CHAR16 *)mEpochVariableName,
98 &gEfiCallerIdGuid,
99 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
100 sizeof (EpochSeconds),
101 &EpochSeconds
102 );
103 }
104
105 Counter = GetPerformanceCounter ();
106 EpochSeconds += DivU64x64Remainder (Counter, Freq, &Remainder);
107
108 // Get the current time zone information from non-volatile storage
109 Size = sizeof (TimeZone);
110 Status = EfiGetVariable (
111 (CHAR16 *)mTimeZoneVariableName,
112 &gEfiCallerIdGuid,
113 NULL,
114 &Size,
115 (VOID *)&TimeZone
116 );
117
118 if (EFI_ERROR (Status)) {
119 ASSERT (Status != EFI_INVALID_PARAMETER);
120 ASSERT (Status != EFI_BUFFER_TOO_SMALL);
121
122 if (Status != EFI_NOT_FOUND) {
123 return Status;
124 }
125
126 // The time zone variable does not exist in non-volatile storage, so create it.
127 Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
128 // Store it
129 Status = EfiSetVariable (
130 (CHAR16 *)mTimeZoneVariableName,
131 &gEfiCallerIdGuid,
132 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
133 Size,
134 (VOID *)&(Time->TimeZone)
135 );
136 if (EFI_ERROR (Status)) {
137 DEBUG ((
138 DEBUG_ERROR,
139 "LibGetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",
140 mTimeZoneVariableName,
141 Status
142 ));
143 return Status;
144 }
145 } else {
146 // Got the time zone
147 Time->TimeZone = TimeZone;
148
149 // Check TimeZone bounds: -1440 to 1440 or 2047
150 if ( ((Time->TimeZone < -1440) || (Time->TimeZone > 1440))
151 && (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE))
152 {
153 Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
154 }
155
156 // Adjust for the correct time zone
157 if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
158 EpochSeconds += Time->TimeZone * SEC_PER_MIN;
159 }
160 }
161
162 // Get the current daylight information from non-volatile storage
163 Size = sizeof (Daylight);
164 Status = EfiGetVariable (
165 (CHAR16 *)mDaylightVariableName,
166 &gEfiCallerIdGuid,
167 NULL,
168 &Size,
169 (VOID *)&Daylight
170 );
171
172 if (EFI_ERROR (Status)) {
173 ASSERT (Status != EFI_INVALID_PARAMETER);
174 ASSERT (Status != EFI_BUFFER_TOO_SMALL);
175
176 if (Status != EFI_NOT_FOUND) {
177 return Status;
178 }
179
180 // The daylight variable does not exist in non-volatile storage, so create it.
181 Time->Daylight = 0;
182 // Store it
183 Status = EfiSetVariable (
184 (CHAR16 *)mDaylightVariableName,
185 &gEfiCallerIdGuid,
186 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
187 Size,
188 (VOID *)&(Time->Daylight)
189 );
190 if (EFI_ERROR (Status)) {
191 DEBUG ((
192 DEBUG_ERROR,
193 "LibGetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",
194 mDaylightVariableName,
195 Status
196 ));
197 return Status;
198 }
199 } else {
200 // Got the daylight information
201 Time->Daylight = Daylight;
202
203 // Adjust for the correct period
204 if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {
205 // Convert to adjusted time, i.e. spring forwards one hour
206 EpochSeconds += SEC_PER_HOUR;
207 }
208 }
209
210 EpochToEfiTime (EpochSeconds, Time);
211
212 // Because we use the performance counter, we can fill the Nanosecond attribute
213 // provided that the remainder doesn't overflow 64-bit during multiplication.
214 if (Remainder <= 18446744073U) {
215 Time->Nanosecond = (UINT32)(MultU64x64 (Remainder, 1000000000U) / Freq);
216 } else {
217 DEBUG ((DEBUG_WARN, "LibGetTime: Nanosecond value not set (64-bit overflow).\n"));
218 }
219
220 if (Capabilities) {
221 Capabilities->Accuracy = 0;
222 Capabilities->Resolution = 1;
223 Capabilities->SetsToZero = FALSE;
224 }
225
226 return EFI_SUCCESS;
227}
228
240EFIAPI
242 IN EFI_TIME *Time
243 )
244{
245 EFI_STATUS Status;
246 UINT64 Freq;
247 UINT64 Counter;
248 UINT64 Remainder;
249 UINTN EpochSeconds;
250
251 if (!IsTimeValid (Time)) {
252 return EFI_INVALID_PARAMETER;
253 }
254
255 EpochSeconds = EfiTimeToEpoch (Time);
256
257 // Adjust for the correct time zone, i.e. convert to UTC time zone
258 if ( (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE)
259 && (EpochSeconds > Time->TimeZone * SEC_PER_MIN))
260 {
261 EpochSeconds -= Time->TimeZone * SEC_PER_MIN;
262 }
263
264 // Adjust for the correct period
265 if ( ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT)
266 && (EpochSeconds > SEC_PER_HOUR))
267 {
268 // Convert to un-adjusted time, i.e. fall back one hour
269 EpochSeconds -= SEC_PER_HOUR;
270 }
271
272 // Use the performance counter to subtract the number of seconds
273 // since platform reset. Without this, setting time from the shell
274 // and immediately reading it back would result in a forward time
275 // offset, of the duration during which the platform has been up.
277 if (Freq != 0) {
278 Counter = GetPerformanceCounter ();
279 if (EpochSeconds > DivU64x64Remainder (Counter, Freq, &Remainder)) {
280 EpochSeconds -= DivU64x64Remainder (Counter, Freq, &Remainder);
281 }
282 }
283
284 // Save the current time zone information into non-volatile storage
285 Status = EfiSetVariable (
286 (CHAR16 *)mTimeZoneVariableName,
287 &gEfiCallerIdGuid,
288 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
289 sizeof (Time->TimeZone),
290 (VOID *)&(Time->TimeZone)
291 );
292 if (EFI_ERROR (Status)) {
293 DEBUG ((
294 DEBUG_ERROR,
295 "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",
296 mTimeZoneVariableName,
297 Status
298 ));
299 return Status;
300 }
301
302 // Save the current daylight information into non-volatile storage
303 Status = EfiSetVariable (
304 (CHAR16 *)mDaylightVariableName,
305 &gEfiCallerIdGuid,
306 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
307 sizeof (Time->Daylight),
308 (VOID *)&(Time->Daylight)
309 );
310 if (EFI_ERROR (Status)) {
311 DEBUG ((
312 DEBUG_ERROR,
313 "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",
314 mDaylightVariableName,
315 Status
316 ));
317 return Status;
318 }
319
320 Status = EfiSetVariable (
321 (CHAR16 *)mEpochVariableName,
322 &gEfiCallerIdGuid,
323 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
324 sizeof (EpochSeconds),
325 &EpochSeconds
326 );
327 if (EFI_ERROR (Status)) {
328 DEBUG ((
329 DEBUG_ERROR,
330 "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",
331 mEpochVariableName,
332 Status
333 ));
334 return Status;
335 }
336
337 return EFI_SUCCESS;
338}
339
353EFIAPI
355 OUT BOOLEAN *Enabled,
356 OUT BOOLEAN *Pending,
357 OUT EFI_TIME *Time
358 )
359{
360 return EFI_UNSUPPORTED;
361}
362
377EFIAPI
379 IN BOOLEAN Enabled,
380 OUT EFI_TIME *Time
381 )
382{
383 return EFI_UNSUPPORTED;
384}
385
397EFIAPI
399 IN EFI_HANDLE ImageHandle,
400 IN EFI_SYSTEM_TABLE *SystemTable
401 )
402{
403 return EFI_SUCCESS;
404}
UINT64 UINTN
UINT64 EFIAPI GetPerformanceCounterProperties(OUT UINT64 *StartValue OPTIONAL, OUT UINT64 *EndValue OPTIONAL)
UINT64 EFIAPI GetPerformanceCounter(VOID)
UINT64 EFIAPI MultU64x64(IN UINT64 Multiplicand, IN UINT64 Multiplier)
Definition: MultU64x64.c:27
UINT64 EFIAPI DivU64x64Remainder(IN UINT64 Dividend, IN UINT64 Divisor, OUT UINT64 *Remainder OPTIONAL)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
UINTN EFIAPI EfiTimeToEpoch(IN EFI_TIME *Time)
Definition: TimeBaseLib.c:119
VOID EFIAPI EpochToEfiTime(IN UINTN EpochSeconds, OUT EFI_TIME *Time)
Definition: TimeBaseLib.c:25
BOOLEAN EFIAPI IsTimeValid(IN EFI_TIME *Time)
Definition: TimeBaseLib.c:269
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
#define EFI_VARIABLE_NON_VOLATILE
EFI_STATUS EFIAPI EfiGetVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT UINT32 *Attributes OPTIONAL, IN OUT UINTN *DataSize, OUT VOID *Data)
Definition: RuntimeLib.c:408
EFI_STATUS EFIAPI EfiSetVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN VOID *Data)
Definition: RuntimeLib.c:498
#define EFI_UNSPECIFIED_TIMEZONE
Definition: UefiSpec.h:58
EFI_STATUS EFIAPI LibSetWakeupTime(IN BOOLEAN Enabled, OUT EFI_TIME *Time)
EFI_STATUS EFIAPI LibRtcInitialize(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
EFI_STATUS EFIAPI LibGetWakeupTime(OUT BOOLEAN *Enabled, OUT BOOLEAN *Pending, OUT EFI_TIME *Time)
EFI_STATUS EFIAPI LibSetTime(IN EFI_TIME *Time)
EFI_STATUS EFIAPI LibGetTime(OUT EFI_TIME *Time, OUT EFI_TIME_CAPABILITIES *Capabilities)