2 RTC Architectural Protocol GUID as defined in DxeCis 0.96.
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 UINTN mDayOfMonth
[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
23 // The name of NV variable to store the timezone and daylight saving information.
25 CHAR16 mTimeZoneVariableName
[] = L
"RTC";
28 Compare the Hour, Minute and Second of the From time and the To time.
30 Only compare H/M/S in EFI_TIME and ignore other fields here.
32 @param From the first time
33 @param To the second time
35 @return >0 The H/M/S of the From time is later than those of To time
36 @return ==0 The H/M/S of the From time is same as those of To time
37 @return <0 The H/M/S of the From time is earlier than those of To time
46 To check if second date is later than first date within 24 hours.
48 @param From the first date
49 @param To the second date
51 @retval TRUE From is previous to To within 24 hours.
52 @retval FALSE From is later, or it is previous to To more than 24 hours.
61 Read RTC content through its registers.
63 @param Address Address offset of RTC. It is recommended to use macros such as
66 @return The data of UINT8 type read from RTC.
73 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER
, (UINT8
) (Address
| (UINT8
) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER
) & 0x80)));
74 return IoRead8 (PCAT_RTC_DATA_REGISTER
);
78 Write RTC through its registers.
80 @param Address Address offset of RTC. It is recommended to use macros such as
82 @param Data The content you want to write into RTC.
91 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER
, (UINT8
) (Address
| (UINT8
) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER
) & 0x80)));
92 IoWrite8 (PCAT_RTC_DATA_REGISTER
, Data
);
98 @param Global For global use inside this module.
100 @retval EFI_DEVICE_ERROR Initialization failed due to device error.
101 @retval EFI_SUCCESS Initialization successful.
106 IN PC_RTC_MODULE_GLOBALS
*Global
110 RTC_REGISTER_A RegisterA
;
111 RTC_REGISTER_B RegisterB
;
112 RTC_REGISTER_D RegisterD
;
120 // Acquire RTC Lock to make access to RTC atomic
122 if (!EfiAtRuntime ()) {
123 EfiAcquireLock (&Global
->RtcLock
);
126 // Initialize RTC Register
128 // Make sure Division Chain is properly configured,
129 // or RTC clock won't "tick" -- time won't increment
131 RegisterA
.Data
= RTC_INIT_REGISTER_A
;
132 RtcWrite (RTC_ADDRESS_REGISTER_A
, RegisterA
.Data
);
137 RegisterB
.Data
= RtcRead (RTC_ADDRESS_REGISTER_B
);
140 // Clear RTC flag register
142 RtcRead (RTC_ADDRESS_REGISTER_C
);
145 // Clear RTC register D
147 RegisterD
.Data
= RTC_INIT_REGISTER_D
;
148 RtcWrite (RTC_ADDRESS_REGISTER_D
, RegisterD
.Data
);
151 // Wait for up to 0.1 seconds for the RTC to be updated
153 Status
= RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout
));
154 if (EFI_ERROR (Status
)) {
156 // Set the variable with default value if the RTC is functioning incorrectly.
158 Global
->SavedTimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
159 Global
->Daylight
= 0;
160 if (!EfiAtRuntime ()) {
161 EfiReleaseLock (&Global
->RtcLock
);
163 return EFI_DEVICE_ERROR
;
166 // Get the Time/Date/Daylight Savings values.
168 Time
.Second
= RtcRead (RTC_ADDRESS_SECONDS
);
169 Time
.Minute
= RtcRead (RTC_ADDRESS_MINUTES
);
170 Time
.Hour
= RtcRead (RTC_ADDRESS_HOURS
);
171 Time
.Day
= RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH
);
172 Time
.Month
= RtcRead (RTC_ADDRESS_MONTH
);
173 Time
.Year
= RtcRead (RTC_ADDRESS_YEAR
);
176 // Set RTC configuration after get original time
177 // The value of bit AIE should be reserved.
179 RegisterB
.Data
= RTC_INIT_REGISTER_B
| (RegisterB
.Data
& BIT5
);
180 RtcWrite (RTC_ADDRESS_REGISTER_B
, RegisterB
.Data
);
185 if (!EfiAtRuntime ()) {
186 EfiReleaseLock (&Global
->RtcLock
);
190 // Get the data of Daylight saving and time zone, if they have been
191 // stored in NV variable during previous boot.
193 DataSize
= sizeof (UINT32
);
194 Status
= EfiGetVariable (
195 mTimeZoneVariableName
,
201 if (!EFI_ERROR (Status
)) {
202 Time
.TimeZone
= (INT16
) TimerVar
;
203 Time
.Daylight
= (UINT8
) (TimerVar
>> 16);
205 Time
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
210 // Validate time fields
212 Status
= ConvertRtcTimeToEfiTime (&Time
, RegisterB
);
213 if (!EFI_ERROR (Status
)) {
214 Status
= RtcTimeFieldsValid (&Time
);
216 if (EFI_ERROR (Status
)) {
218 // Report Status Code to indicate that the RTC has bad date and time
221 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
222 (EFI_SOFTWARE_DXE_RT_DRIVER
| EFI_SW_EC_BAD_DATE_TIME
)
224 Time
.Second
= RTC_INIT_SECOND
;
225 Time
.Minute
= RTC_INIT_MINUTE
;
226 Time
.Hour
= RTC_INIT_HOUR
;
227 Time
.Day
= RTC_INIT_DAY
;
228 Time
.Month
= RTC_INIT_MONTH
;
229 Time
.Year
= PcdGet16 (PcdMinimalValidYear
);
231 Time
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
236 // Reset time value according to new RTC configuration
238 Status
= PcRtcSetTime (&Time
, Global
);
239 if (EFI_ERROR (Status
)) {
240 return EFI_DEVICE_ERROR
;
244 // Reset wakeup time value to valid state when wakeup alarm is disabled and wakeup time is invalid.
245 // Global variable has already had valid SavedTimeZone and Daylight,
246 // so we can use them to get and set wakeup time.
248 Status
= PcRtcGetWakeupTime (&Enabled
, &Pending
, &Time
, Global
);
249 if ((Enabled
) || (!EFI_ERROR (Status
))) {
254 // When wakeup time is disabled and invalid, reset wakeup time register to valid state
255 // but keep wakeup alarm disabled.
257 Time
.Second
= RTC_INIT_SECOND
;
258 Time
.Minute
= RTC_INIT_MINUTE
;
259 Time
.Hour
= RTC_INIT_HOUR
;
260 Time
.Day
= RTC_INIT_DAY
;
261 Time
.Month
= RTC_INIT_MONTH
;
262 Time
.Year
= PcdGet16 (PcdMinimalValidYear
);
264 Time
.TimeZone
= Global
->SavedTimeZone
;
265 Time
.Daylight
= Global
->Daylight
;;
268 // Acquire RTC Lock to make access to RTC atomic
270 if (!EfiAtRuntime ()) {
271 EfiAcquireLock (&Global
->RtcLock
);
274 // Wait for up to 0.1 seconds for the RTC to be updated
276 Status
= RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout
));
277 if (EFI_ERROR (Status
)) {
278 if (!EfiAtRuntime ()) {
279 EfiReleaseLock (&Global
->RtcLock
);
281 return EFI_DEVICE_ERROR
;
284 ConvertEfiTimeToRtcTime (&Time
, RegisterB
);
287 // Set the Y/M/D info to variable as it has no corresponding hw registers.
289 Status
= EfiSetVariable (
292 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
296 if (EFI_ERROR (Status
)) {
297 if (!EfiAtRuntime ()) {
298 EfiReleaseLock (&Global
->RtcLock
);
300 return EFI_DEVICE_ERROR
;
304 // Inhibit updates of the RTC
306 RegisterB
.Bits
.Set
= 1;
307 RtcWrite (RTC_ADDRESS_REGISTER_B
, RegisterB
.Data
);
310 // Set RTC alarm time registers
312 RtcWrite (RTC_ADDRESS_SECONDS_ALARM
, Time
.Second
);
313 RtcWrite (RTC_ADDRESS_MINUTES_ALARM
, Time
.Minute
);
314 RtcWrite (RTC_ADDRESS_HOURS_ALARM
, Time
.Hour
);
317 // Allow updates of the RTC registers
319 RegisterB
.Bits
.Set
= 0;
320 RtcWrite (RTC_ADDRESS_REGISTER_B
, RegisterB
.Data
);
325 if (!EfiAtRuntime ()) {
326 EfiReleaseLock (&Global
->RtcLock
);
332 Returns the current time and date information, and the time-keeping capabilities
333 of the hardware platform.
335 @param Time A pointer to storage to receive a snapshot of the current time.
336 @param Capabilities An optional pointer to a buffer to receive the real time clock
337 device's capabilities.
338 @param Global For global use inside this module.
340 @retval EFI_SUCCESS The operation completed successfully.
341 @retval EFI_INVALID_PARAMETER Time is NULL.
342 @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.
348 OUT EFI_TIME_CAPABILITIES
*Capabilities
, OPTIONAL
349 IN PC_RTC_MODULE_GLOBALS
*Global
353 RTC_REGISTER_B RegisterB
;
356 // Check parameters for null pointer
359 return EFI_INVALID_PARAMETER
;
363 // Acquire RTC Lock to make access to RTC atomic
365 if (!EfiAtRuntime ()) {
366 EfiAcquireLock (&Global
->RtcLock
);
369 // Wait for up to 0.1 seconds for the RTC to be updated
371 Status
= RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout
));
372 if (EFI_ERROR (Status
)) {
373 if (!EfiAtRuntime ()) {
374 EfiReleaseLock (&Global
->RtcLock
);
381 RegisterB
.Data
= RtcRead (RTC_ADDRESS_REGISTER_B
);
384 // Get the Time/Date/Daylight Savings values.
386 Time
->Second
= RtcRead (RTC_ADDRESS_SECONDS
);
387 Time
->Minute
= RtcRead (RTC_ADDRESS_MINUTES
);
388 Time
->Hour
= RtcRead (RTC_ADDRESS_HOURS
);
389 Time
->Day
= RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH
);
390 Time
->Month
= RtcRead (RTC_ADDRESS_MONTH
);
391 Time
->Year
= RtcRead (RTC_ADDRESS_YEAR
);
396 if (!EfiAtRuntime ()) {
397 EfiReleaseLock (&Global
->RtcLock
);
401 // Get the variable that contains the TimeZone and Daylight fields
403 Time
->TimeZone
= Global
->SavedTimeZone
;
404 Time
->Daylight
= Global
->Daylight
;
407 // Make sure all field values are in correct range
409 Status
= ConvertRtcTimeToEfiTime (Time
, RegisterB
);
410 if (!EFI_ERROR (Status
)) {
411 Status
= RtcTimeFieldsValid (Time
);
413 if (EFI_ERROR (Status
)) {
414 return EFI_DEVICE_ERROR
;
418 // Fill in Capabilities if it was passed in
420 if (Capabilities
!= NULL
) {
421 Capabilities
->Resolution
= 1;
425 Capabilities
->Accuracy
= 50000000;
429 Capabilities
->SetsToZero
= FALSE
;
436 Sets the current local time and date information.
438 @param Time A pointer to the current time.
439 @param Global For global use inside this module.
441 @retval EFI_SUCCESS The operation completed successfully.
442 @retval EFI_INVALID_PARAMETER A time field is out of range.
443 @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error.
449 IN PC_RTC_MODULE_GLOBALS
*Global
454 RTC_REGISTER_B RegisterB
;
458 return EFI_INVALID_PARAMETER
;
461 // Make sure that the time fields are valid
463 Status
= RtcTimeFieldsValid (Time
);
464 if (EFI_ERROR (Status
)) {
468 CopyMem (&RtcTime
, Time
, sizeof (EFI_TIME
));
471 // Acquire RTC Lock to make access to RTC atomic
473 if (!EfiAtRuntime ()) {
474 EfiAcquireLock (&Global
->RtcLock
);
477 // Wait for up to 0.1 seconds for the RTC to be updated
479 Status
= RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout
));
480 if (EFI_ERROR (Status
)) {
481 if (!EfiAtRuntime ()) {
482 EfiReleaseLock (&Global
->RtcLock
);
488 // Write timezone and daylight to RTC variable
490 if (Time
->TimeZone
== EFI_UNSPECIFIED_TIMEZONE
) {
491 Status
= EfiSetVariable (
492 mTimeZoneVariableName
,
498 if (Status
== EFI_NOT_FOUND
) {
499 Status
= EFI_SUCCESS
;
502 TimerVar
= Time
->Daylight
;
503 TimerVar
= (UINT32
) ((TimerVar
<< 16) | (UINT16
)(Time
->TimeZone
));
504 Status
= EfiSetVariable (
505 mTimeZoneVariableName
,
507 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
513 if (EFI_ERROR (Status
)) {
514 if (!EfiAtRuntime ()) {
515 EfiReleaseLock (&Global
->RtcLock
);
517 return EFI_DEVICE_ERROR
;
521 // Read Register B, and inhibit updates of the RTC
523 RegisterB
.Data
= RtcRead (RTC_ADDRESS_REGISTER_B
);
524 RegisterB
.Bits
.Set
= 1;
525 RtcWrite (RTC_ADDRESS_REGISTER_B
, RegisterB
.Data
);
528 // Store the century value to RTC before converting to BCD format.
530 if (Global
->CenturyRtcAddress
!= 0) {
531 RtcWrite (Global
->CenturyRtcAddress
, DecimalToBcd8 ((UINT8
) (RtcTime
.Year
/ 100)));
534 ConvertEfiTimeToRtcTime (&RtcTime
, RegisterB
);
536 RtcWrite (RTC_ADDRESS_SECONDS
, RtcTime
.Second
);
537 RtcWrite (RTC_ADDRESS_MINUTES
, RtcTime
.Minute
);
538 RtcWrite (RTC_ADDRESS_HOURS
, RtcTime
.Hour
);
539 RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH
, RtcTime
.Day
);
540 RtcWrite (RTC_ADDRESS_MONTH
, RtcTime
.Month
);
541 RtcWrite (RTC_ADDRESS_YEAR
, (UINT8
) RtcTime
.Year
);
544 // Allow updates of the RTC registers
546 RegisterB
.Bits
.Set
= 0;
547 RtcWrite (RTC_ADDRESS_REGISTER_B
, RegisterB
.Data
);
552 if (!EfiAtRuntime ()) {
553 EfiReleaseLock (&Global
->RtcLock
);
556 // Set the variable that contains the TimeZone and Daylight fields
558 Global
->SavedTimeZone
= Time
->TimeZone
;
559 Global
->Daylight
= Time
->Daylight
;
565 Returns the current wakeup alarm clock setting.
567 @param Enabled Indicates if the alarm is currently enabled or disabled.
568 @param Pending Indicates if the alarm signal is pending and requires acknowledgment.
569 @param Time The current alarm setting.
570 @param Global For global use inside this module.
572 @retval EFI_SUCCESS The alarm settings were returned.
573 @retval EFI_INVALID_PARAMETER Enabled is NULL.
574 @retval EFI_INVALID_PARAMETER Pending is NULL.
575 @retval EFI_INVALID_PARAMETER Time is NULL.
576 @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.
577 @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
582 OUT BOOLEAN
*Enabled
,
583 OUT BOOLEAN
*Pending
,
585 IN PC_RTC_MODULE_GLOBALS
*Global
589 RTC_REGISTER_B RegisterB
;
590 RTC_REGISTER_C RegisterC
;
595 // Check parameters for null pointers
597 if ((Enabled
== NULL
) || (Pending
== NULL
) || (Time
== NULL
)) {
598 return EFI_INVALID_PARAMETER
;
602 // Acquire RTC Lock to make access to RTC atomic
604 if (!EfiAtRuntime ()) {
605 EfiAcquireLock (&Global
->RtcLock
);
608 // Wait for up to 0.1 seconds for the RTC to be updated
610 Status
= RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout
));
611 if (EFI_ERROR (Status
)) {
612 if (!EfiAtRuntime ()) {
613 EfiReleaseLock (&Global
->RtcLock
);
615 return EFI_DEVICE_ERROR
;
618 // Read Register B and Register C
620 RegisterB
.Data
= RtcRead (RTC_ADDRESS_REGISTER_B
);
621 RegisterC
.Data
= RtcRead (RTC_ADDRESS_REGISTER_C
);
624 // Get the Time/Date/Daylight Savings values.
626 *Enabled
= RegisterB
.Bits
.Aie
;
627 *Pending
= RegisterC
.Bits
.Af
;
629 Time
->Second
= RtcRead (RTC_ADDRESS_SECONDS_ALARM
);
630 Time
->Minute
= RtcRead (RTC_ADDRESS_MINUTES_ALARM
);
631 Time
->Hour
= RtcRead (RTC_ADDRESS_HOURS_ALARM
);
632 Time
->Day
= RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH
);
633 Time
->Month
= RtcRead (RTC_ADDRESS_MONTH
);
634 Time
->Year
= RtcRead (RTC_ADDRESS_YEAR
);
635 Time
->TimeZone
= Global
->SavedTimeZone
;
636 Time
->Daylight
= Global
->Daylight
;
639 // Get the alarm info from variable
641 DataSize
= sizeof (EFI_TIME
);
642 Status
= EfiGetVariable (
649 if (!EFI_ERROR (Status
)) {
651 // The alarm variable exists. In this case, we read variable to get info.
653 Time
->Day
= RtcTime
.Day
;
654 Time
->Month
= RtcTime
.Month
;
655 Time
->Year
= RtcTime
.Year
;
661 if (!EfiAtRuntime ()) {
662 EfiReleaseLock (&Global
->RtcLock
);
666 // Make sure all field values are in correct range
668 Status
= ConvertRtcTimeToEfiTime (Time
, RegisterB
);
669 if (!EFI_ERROR (Status
)) {
670 Status
= RtcTimeFieldsValid (Time
);
672 if (EFI_ERROR (Status
)) {
673 return EFI_DEVICE_ERROR
;
680 Sets the system wakeup alarm clock time.
682 @param Enabled Enable or disable the wakeup alarm.
683 @param Time If Enable is TRUE, the time to set the wakeup alarm for.
684 If Enable is FALSE, then this parameter is optional, and may be NULL.
685 @param Global For global use inside this module.
687 @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled.
688 If Enable is FALSE, then the wakeup alarm was disabled.
689 @retval EFI_INVALID_PARAMETER A time field is out of range.
690 @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.
691 @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
697 IN EFI_TIME
*Time
, OPTIONAL
698 IN PC_RTC_MODULE_GLOBALS
*Global
703 RTC_REGISTER_B RegisterB
;
704 EFI_TIME_CAPABILITIES Capabilities
;
706 ZeroMem (&RtcTime
, sizeof (RtcTime
));
711 return EFI_INVALID_PARAMETER
;
714 // Make sure that the time fields are valid
716 Status
= RtcTimeFieldsValid (Time
);
717 if (EFI_ERROR (Status
)) {
718 return EFI_INVALID_PARAMETER
;
721 // Just support set alarm time within 24 hours
723 PcRtcGetTime (&RtcTime
, &Capabilities
, Global
);
724 Status
= RtcTimeFieldsValid (&RtcTime
);
725 if (EFI_ERROR (Status
)) {
726 return EFI_DEVICE_ERROR
;
728 if (!IsWithinOneDay (&RtcTime
, Time
)) {
729 return EFI_UNSUPPORTED
;
732 // Make a local copy of the time and date
734 CopyMem (&RtcTime
, Time
, sizeof (EFI_TIME
));
738 // Acquire RTC Lock to make access to RTC atomic
740 if (!EfiAtRuntime ()) {
741 EfiAcquireLock (&Global
->RtcLock
);
744 // Wait for up to 0.1 seconds for the RTC to be updated
746 Status
= RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout
));
747 if (EFI_ERROR (Status
)) {
748 if (!EfiAtRuntime ()) {
749 EfiReleaseLock (&Global
->RtcLock
);
751 return EFI_DEVICE_ERROR
;
756 RegisterB
.Data
= RtcRead (RTC_ADDRESS_REGISTER_B
);
759 ConvertEfiTimeToRtcTime (&RtcTime
, RegisterB
);
762 // if the alarm is disable, record the current setting.
764 RtcTime
.Second
= RtcRead (RTC_ADDRESS_SECONDS_ALARM
);
765 RtcTime
.Minute
= RtcRead (RTC_ADDRESS_MINUTES_ALARM
);
766 RtcTime
.Hour
= RtcRead (RTC_ADDRESS_HOURS_ALARM
);
767 RtcTime
.Day
= RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH
);
768 RtcTime
.Month
= RtcRead (RTC_ADDRESS_MONTH
);
769 RtcTime
.Year
= RtcRead (RTC_ADDRESS_YEAR
);
770 RtcTime
.TimeZone
= Global
->SavedTimeZone
;
771 RtcTime
.Daylight
= Global
->Daylight
;
775 // Set the Y/M/D info to variable as it has no corresponding hw registers.
777 Status
= EfiSetVariable (
780 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
784 if (EFI_ERROR (Status
)) {
785 if (!EfiAtRuntime ()) {
786 EfiReleaseLock (&Global
->RtcLock
);
788 return EFI_DEVICE_ERROR
;
792 // Inhibit updates of the RTC
794 RegisterB
.Bits
.Set
= 1;
795 RtcWrite (RTC_ADDRESS_REGISTER_B
, RegisterB
.Data
);
799 // Set RTC alarm time
801 RtcWrite (RTC_ADDRESS_SECONDS_ALARM
, RtcTime
.Second
);
802 RtcWrite (RTC_ADDRESS_MINUTES_ALARM
, RtcTime
.Minute
);
803 RtcWrite (RTC_ADDRESS_HOURS_ALARM
, RtcTime
.Hour
);
805 RegisterB
.Bits
.Aie
= 1;
808 RegisterB
.Bits
.Aie
= 0;
811 // Allow updates of the RTC registers
813 RegisterB
.Bits
.Set
= 0;
814 RtcWrite (RTC_ADDRESS_REGISTER_B
, RegisterB
.Data
);
819 if (!EfiAtRuntime ()) {
820 EfiReleaseLock (&Global
->RtcLock
);
827 Checks an 8-bit BCD value, and converts to an 8-bit value if valid.
829 This function checks the 8-bit BCD value specified by Value.
830 If valid, the function converts it to an 8-bit value and returns it.
831 Otherwise, return 0xff.
833 @param Value The 8-bit BCD value to check and convert
835 @return The 8-bit value converted. Or 0xff if Value is invalid.
839 CheckAndConvertBcd8ToDecimal8 (
843 if ((Value
< 0xa0) && ((Value
& 0xf) < 0xa)) {
844 return BcdToDecimal8 (Value
);
851 Converts time read from RTC to EFI_TIME format defined by UEFI spec.
853 This function converts raw time data read from RTC to the EFI_TIME format
854 defined by UEFI spec.
855 If data mode of RTC is BCD, then converts it to decimal,
856 If RTC is in 12-hour format, then converts it to 24-hour format.
858 @param Time On input, the time data read from RTC to convert
859 On output, the time converted to UEFI format
860 @param RegisterB Value of Register B of RTC, indicating data mode
863 @retval EFI_INVALID_PARAMETER Parameters passed in are invalid.
864 @retval EFI_SUCCESS Convert RTC time to EFI time successfully.
868 ConvertRtcTimeToEfiTime (
869 IN OUT EFI_TIME
*Time
,
870 IN RTC_REGISTER_B RegisterB
876 if ((Time
->Hour
& 0x80) != 0) {
882 Time
->Hour
= (UINT8
) (Time
->Hour
& 0x7f);
884 if (RegisterB
.Bits
.Dm
== 0) {
885 Time
->Year
= CheckAndConvertBcd8ToDecimal8 ((UINT8
) Time
->Year
);
886 Time
->Month
= CheckAndConvertBcd8ToDecimal8 (Time
->Month
);
887 Time
->Day
= CheckAndConvertBcd8ToDecimal8 (Time
->Day
);
888 Time
->Hour
= CheckAndConvertBcd8ToDecimal8 (Time
->Hour
);
889 Time
->Minute
= CheckAndConvertBcd8ToDecimal8 (Time
->Minute
);
890 Time
->Second
= CheckAndConvertBcd8ToDecimal8 (Time
->Second
);
893 if (Time
->Year
== 0xff || Time
->Month
== 0xff || Time
->Day
== 0xff ||
894 Time
->Hour
== 0xff || Time
->Minute
== 0xff || Time
->Second
== 0xff) {
895 return EFI_INVALID_PARAMETER
;
899 // For minimal/maximum year range [1970, 2069],
900 // Century is 19 if RTC year >= 70,
901 // Century is 20 otherwise.
903 Century
= (UINT8
) (PcdGet16 (PcdMinimalValidYear
) / 100);
904 if (Time
->Year
< PcdGet16 (PcdMinimalValidYear
) % 100) {
907 Time
->Year
= (UINT16
) (Century
* 100 + Time
->Year
);
910 // If time is in 12 hour format, convert it to 24 hour format
912 if (RegisterB
.Bits
.Mil
== 0) {
913 if (IsPM
&& Time
->Hour
< 12) {
914 Time
->Hour
= (UINT8
) (Time
->Hour
+ 12);
917 if (!IsPM
&& Time
->Hour
== 12) {
922 Time
->Nanosecond
= 0;
928 Wait for a period for the RTC to be ready.
930 @param Timeout Tell how long it should take to wait.
932 @retval EFI_DEVICE_ERROR RTC device error.
933 @retval EFI_SUCCESS RTC is updated and ready.
940 RTC_REGISTER_A RegisterA
;
941 RTC_REGISTER_D RegisterD
;
944 // See if the RTC is functioning correctly
946 RegisterD
.Data
= RtcRead (RTC_ADDRESS_REGISTER_D
);
948 if (RegisterD
.Bits
.Vrt
== 0) {
949 return EFI_DEVICE_ERROR
;
952 // Wait for up to 0.1 seconds for the RTC to be ready.
954 Timeout
= (Timeout
/ 10) + 1;
955 RegisterA
.Data
= RtcRead (RTC_ADDRESS_REGISTER_A
);
956 while (RegisterA
.Bits
.Uip
== 1 && Timeout
> 0) {
957 MicroSecondDelay (10);
958 RegisterA
.Data
= RtcRead (RTC_ADDRESS_REGISTER_A
);
962 RegisterD
.Data
= RtcRead (RTC_ADDRESS_REGISTER_D
);
963 if (Timeout
== 0 || RegisterD
.Bits
.Vrt
== 0) {
964 return EFI_DEVICE_ERROR
;
971 See if all fields of a variable of EFI_TIME type is correct.
973 @param Time The time to be checked.
975 @retval EFI_INVALID_PARAMETER Some fields of Time are not correct.
976 @retval EFI_SUCCESS Time is a valid EFI_TIME variable.
984 if (Time
->Year
< PcdGet16 (PcdMinimalValidYear
) ||
985 Time
->Year
> PcdGet16 (PcdMaximalValidYear
) ||
988 (!DayValid (Time
)) ||
992 Time
->Nanosecond
> 999999999 ||
993 (!(Time
->TimeZone
== EFI_UNSPECIFIED_TIMEZONE
|| (Time
->TimeZone
>= -1440 && Time
->TimeZone
<= 1440))) ||
994 ((Time
->Daylight
& (~(EFI_TIME_ADJUST_DAYLIGHT
| EFI_TIME_IN_DAYLIGHT
))) != 0)) {
995 return EFI_INVALID_PARAMETER
;
1002 See if field Day of an EFI_TIME is correct.
1004 @param Time Its Day field is to be checked.
1006 @retval TRUE Day field of Time is correct.
1007 @retval FALSE Day field of Time is NOT correct.
1015 // The validity of Time->Month field should be checked before
1017 ASSERT (Time
->Month
>=1);
1018 ASSERT (Time
->Month
<=12);
1019 if (Time
->Day
< 1 ||
1020 Time
->Day
> mDayOfMonth
[Time
->Month
- 1] ||
1021 (Time
->Month
== 2 && (!IsLeapYear (Time
) && Time
->Day
> 28))
1030 Check if it is a leap year.
1032 @param Time The time to be checked.
1034 @retval TRUE It is a leap year.
1035 @retval FALSE It is NOT a leap year.
1042 if (Time
->Year
% 4 == 0) {
1043 if (Time
->Year
% 100 == 0) {
1044 if (Time
->Year
% 400 == 0) {
1058 Converts time from EFI_TIME format defined by UEFI spec to RTC's.
1060 This function converts time from EFI_TIME format defined by UEFI spec to RTC's.
1061 If data mode of RTC is BCD, then converts EFI_TIME to it.
1062 If RTC is in 12-hour format, then converts EFI_TIME to it.
1064 @param Time On input, the time data read from UEFI to convert
1065 On output, the time converted to RTC format
1066 @param RegisterB Value of Register B of RTC, indicating data mode
1069 ConvertEfiTimeToRtcTime (
1070 IN OUT EFI_TIME
*Time
,
1071 IN RTC_REGISTER_B RegisterB
1078 // Adjust hour field if RTC is in 12 hour mode
1080 if (RegisterB
.Bits
.Mil
== 0) {
1081 if (Time
->Hour
< 12) {
1085 if (Time
->Hour
>= 13) {
1086 Time
->Hour
= (UINT8
) (Time
->Hour
- 12);
1087 } else if (Time
->Hour
== 0) {
1092 // Set the Time/Date values.
1094 Time
->Year
= (UINT16
) (Time
->Year
% 100);
1096 if (RegisterB
.Bits
.Dm
== 0) {
1097 Time
->Year
= DecimalToBcd8 ((UINT8
) Time
->Year
);
1098 Time
->Month
= DecimalToBcd8 (Time
->Month
);
1099 Time
->Day
= DecimalToBcd8 (Time
->Day
);
1100 Time
->Hour
= DecimalToBcd8 (Time
->Hour
);
1101 Time
->Minute
= DecimalToBcd8 (Time
->Minute
);
1102 Time
->Second
= DecimalToBcd8 (Time
->Second
);
1105 // If we are in 12 hour mode and PM is set, then set bit 7 of the Hour field.
1107 if (RegisterB
.Bits
.Mil
== 0 && IsPM
) {
1108 Time
->Hour
= (UINT8
) (Time
->Hour
| 0x80);
1113 Compare the Hour, Minute and Second of the From time and the To time.
1115 Only compare H/M/S in EFI_TIME and ignore other fields here.
1117 @param From the first time
1118 @param To the second time
1120 @return >0 The H/M/S of the From time is later than those of To time
1121 @return ==0 The H/M/S of the From time is same as those of To time
1122 @return <0 The H/M/S of the From time is earlier than those of To time
1130 if ((From
->Hour
> To
->Hour
) ||
1131 ((From
->Hour
== To
->Hour
) && (From
->Minute
> To
->Minute
)) ||
1132 ((From
->Hour
== To
->Hour
) && (From
->Minute
== To
->Minute
) && (From
->Second
> To
->Second
))) {
1134 } else if ((From
->Hour
== To
->Hour
) && (From
->Minute
== To
->Minute
) && (From
->Second
== To
->Second
)) {
1142 To check if second date is later than first date within 24 hours.
1144 @param From the first date
1145 @param To the second date
1147 @retval TRUE From is previous to To within 24 hours.
1148 @retval FALSE From is later, or it is previous to To more than 24 hours.
1161 // The validity of From->Month field should be checked before
1163 ASSERT (From
->Month
>=1);
1164 ASSERT (From
->Month
<=12);
1166 if (From
->Year
== To
->Year
) {
1167 if (From
->Month
== To
->Month
) {
1168 if ((From
->Day
+ 1) == To
->Day
) {
1169 if ((CompareHMS(From
, To
) >= 0)) {
1172 } else if (From
->Day
== To
->Day
) {
1173 if ((CompareHMS(From
, To
) <= 0)) {
1177 } else if (((From
->Month
+ 1) == To
->Month
) && (To
->Day
== 1)) {
1178 if ((From
->Month
== 2) && !IsLeapYear(From
)) {
1179 if (From
->Day
== 28) {
1180 if ((CompareHMS(From
, To
) >= 0)) {
1184 } else if (From
->Day
== mDayOfMonth
[From
->Month
- 1]) {
1185 if ((CompareHMS(From
, To
) >= 0)) {
1190 } else if (((From
->Year
+ 1) == To
->Year
) &&
1191 (From
->Month
== 12) &&
1192 (From
->Day
== 31) &&
1195 if ((CompareHMS(From
, To
) >= 0)) {
1204 This function find ACPI table with the specified signature in RSDT or XSDT.
1206 @param Sdt ACPI RSDT or XSDT.
1207 @param Signature ACPI table signature.
1208 @param TablePointerSize Size of table pointer: 4 or 8.
1210 @return ACPI table or NULL if not found.
1214 IN EFI_ACPI_DESCRIPTION_HEADER
*Sdt
,
1215 IN UINT32 Signature
,
1216 IN UINTN TablePointerSize
1222 EFI_ACPI_DESCRIPTION_HEADER
*Table
;
1224 EntryCount
= (Sdt
->Length
- sizeof (EFI_ACPI_DESCRIPTION_HEADER
)) / TablePointerSize
;
1226 EntryBase
= (UINTN
) (Sdt
+ 1);
1227 for (Index
= 0; Index
< EntryCount
; Index
++) {
1229 // When TablePointerSize is 4 while sizeof (VOID *) is 8, make sure the upper 4 bytes are zero.
1232 CopyMem (&Table
, (VOID
*) (EntryBase
+ Index
* TablePointerSize
), TablePointerSize
);
1233 if (Table
->Signature
== Signature
) {
1242 Notification function of ACPI Table change.
1244 This is a notification function registered on ACPI Table change event.
1245 It saves the Century address stored in ACPI FADT table.
1247 @param Event Event whose notification function is being invoked.
1248 @param Context Pointer to the notification function's context.
1253 PcRtcAcpiTableChangeCallback (
1259 EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER
*Rsdp
;
1260 EFI_ACPI_DESCRIPTION_HEADER
*Rsdt
;
1261 EFI_ACPI_DESCRIPTION_HEADER
*Xsdt
;
1262 EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE
*Fadt
;
1266 Status
= EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid
, (VOID
**) &Rsdp
);
1267 if (EFI_ERROR (Status
)) {
1268 Status
= EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid
, (VOID
**) &Rsdp
);
1271 if (EFI_ERROR (Status
)) {
1275 ASSERT (Rsdp
!= NULL
);
1278 // Find FADT in XSDT
1281 if (Rsdp
->Revision
>= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION
) {
1282 Xsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*) (UINTN
) Rsdp
->XsdtAddress
;
1283 Fadt
= ScanTableInSDT (Xsdt
, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE
, sizeof (UINT64
));
1288 // Find FADT in RSDT
1290 Rsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*) (UINTN
) Rsdp
->RsdtAddress
;
1291 Fadt
= ScanTableInSDT (Rsdt
, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE
, sizeof (UINT32
));
1294 if ((Fadt
!= NULL
) &&
1295 (Fadt
->Century
> RTC_ADDRESS_REGISTER_D
) && (Fadt
->Century
< 0x80) &&
1296 (mModuleGlobal
.CenturyRtcAddress
!= Fadt
->Century
)
1298 mModuleGlobal
.CenturyRtcAddress
= Fadt
->Century
;
1299 Status
= PcRtcGetTime (&Time
, NULL
, &mModuleGlobal
);
1300 if (!EFI_ERROR (Status
)) {
1301 Century
= (UINT8
) (Time
.Year
/ 100);
1302 Century
= DecimalToBcd8 (Century
);
1303 DEBUG ((EFI_D_INFO
, "PcRtc: Write 0x%x to CMOS location 0x%x\n", Century
, mModuleGlobal
.CenturyRtcAddress
));
1304 RtcWrite (mModuleGlobal
.CenturyRtcAddress
, Century
);