mirror of https://github.com/acidanthera/audk.git
PcAtChipsetPkg/PcRtc: Fix a Y2K bug
The original driver cannot handle the case when system time runs from 1999/12/31 23:59:59 to 2000/1/1 0:0:0. A simple test to set system time to 1999/12/31 23:59:59 can expose this bug. The patch limits the driver to only support year in 100 range and decide the century value based on the supporting range: Century either equals to PcdMinimalYear / 100 or equals to PcdMinimalYear / 100 + 1. The patch passed the Y2K test. However with year range [1998, 2097], when system time is 2097/12/31 23:59:59, the next second system time will become 1998/1/1 0:0:0. I think it's a acceptable limitation. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Feng Tian <feng.tian@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17624 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
e63ec1beac
commit
fe32096778
|
@ -123,7 +123,8 @@
|
||||||
|
|
||||||
## This PCD specifies the maximal valid year in RTC.
|
## This PCD specifies the maximal valid year in RTC.
|
||||||
# @Prompt Maximal valid year in RTC.
|
# @Prompt Maximal valid year in RTC.
|
||||||
gPcAtChipsetPkgTokenSpaceGuid.PcdMaximalValidYear|2099|UINT16|0x0000000E
|
# @Expression gPcAtChipsetPkgTokenSpaceGuid.PcdMaximalValidYear < gPcAtChipsetPkgTokenSpaceGuid.PcdMinimalValidYear + 100
|
||||||
|
gPcAtChipsetPkgTokenSpaceGuid.PcdMaximalValidYear|2097|UINT16|0x0000000E
|
||||||
|
|
||||||
[PcdsFixedAtBuild, PcdsPatchableInModule]
|
[PcdsFixedAtBuild, PcdsPatchableInModule]
|
||||||
## Defines the ACPI register set base address.
|
## Defines the ACPI register set base address.
|
||||||
|
@ -168,4 +169,4 @@
|
||||||
gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddressMask |0xFFFE|UINT16|0x00000018
|
gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddressMask |0xFFFE|UINT16|0x00000018
|
||||||
|
|
||||||
[UserExtensions.TianoCore."ExtraFiles"]
|
[UserExtensions.TianoCore."ExtraFiles"]
|
||||||
PcAtChipsetPkgExtra.uni
|
PcAtChipsetPkgExtra.uni
|
||||||
|
|
|
@ -100,7 +100,6 @@ PcRtcInit (
|
||||||
RTC_REGISTER_A RegisterA;
|
RTC_REGISTER_A RegisterA;
|
||||||
RTC_REGISTER_B RegisterB;
|
RTC_REGISTER_B RegisterB;
|
||||||
RTC_REGISTER_D RegisterD;
|
RTC_REGISTER_D RegisterD;
|
||||||
UINT8 Century;
|
|
||||||
EFI_TIME Time;
|
EFI_TIME Time;
|
||||||
UINTN DataSize;
|
UINTN DataSize;
|
||||||
UINT32 TimerVar;
|
UINT32 TimerVar;
|
||||||
|
@ -163,8 +162,6 @@ PcRtcInit (
|
||||||
Time.Month = RtcRead (RTC_ADDRESS_MONTH);
|
Time.Month = RtcRead (RTC_ADDRESS_MONTH);
|
||||||
Time.Year = RtcRead (RTC_ADDRESS_YEAR);
|
Time.Year = RtcRead (RTC_ADDRESS_YEAR);
|
||||||
|
|
||||||
Century = RtcRead (RTC_ADDRESS_CENTURY);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Set RTC configuration after get original time
|
// Set RTC configuration after get original time
|
||||||
// The value of bit AIE should be reserved.
|
// The value of bit AIE should be reserved.
|
||||||
|
@ -201,7 +198,7 @@ PcRtcInit (
|
||||||
//
|
//
|
||||||
// Validate time fields
|
// Validate time fields
|
||||||
//
|
//
|
||||||
Status = ConvertRtcTimeToEfiTime (&Time, Century, RegisterB);
|
Status = ConvertRtcTimeToEfiTime (&Time, RegisterB);
|
||||||
if (!EFI_ERROR (Status)) {
|
if (!EFI_ERROR (Status)) {
|
||||||
Status = RtcTimeFieldsValid (&Time);
|
Status = RtcTimeFieldsValid (&Time);
|
||||||
}
|
}
|
||||||
|
@ -218,7 +215,7 @@ PcRtcInit (
|
||||||
Time.Hour = RTC_INIT_HOUR;
|
Time.Hour = RTC_INIT_HOUR;
|
||||||
Time.Day = RTC_INIT_DAY;
|
Time.Day = RTC_INIT_DAY;
|
||||||
Time.Month = RTC_INIT_MONTH;
|
Time.Month = RTC_INIT_MONTH;
|
||||||
Time.Year = RTC_INIT_YEAR;
|
Time.Year = PcdGet16 (PcdMinimalValidYear);
|
||||||
Time.Nanosecond = 0;
|
Time.Nanosecond = 0;
|
||||||
Time.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
|
Time.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
|
||||||
Time.Daylight = 0;
|
Time.Daylight = 0;
|
||||||
|
@ -251,7 +248,7 @@ PcRtcInit (
|
||||||
Time.Hour = RTC_INIT_HOUR;
|
Time.Hour = RTC_INIT_HOUR;
|
||||||
Time.Day = RTC_INIT_DAY;
|
Time.Day = RTC_INIT_DAY;
|
||||||
Time.Month = RTC_INIT_MONTH;
|
Time.Month = RTC_INIT_MONTH;
|
||||||
Time.Year = RTC_INIT_YEAR;
|
Time.Year = PcdGet16 (PcdMinimalValidYear);
|
||||||
Time.Nanosecond = 0;
|
Time.Nanosecond = 0;
|
||||||
Time.TimeZone = Global->SavedTimeZone;
|
Time.TimeZone = Global->SavedTimeZone;
|
||||||
Time.Daylight = Global->Daylight;;
|
Time.Daylight = Global->Daylight;;
|
||||||
|
@ -272,8 +269,8 @@ PcRtcInit (
|
||||||
}
|
}
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvertEfiTimeToRtcTime (&Time, RegisterB, &Century);
|
ConvertEfiTimeToRtcTime (&Time, RegisterB);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Set the Y/M/D info to variable as it has no corresponding hw registers.
|
// Set the Y/M/D info to variable as it has no corresponding hw registers.
|
||||||
|
@ -343,7 +340,6 @@ PcRtcGetTime (
|
||||||
{
|
{
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
RTC_REGISTER_B RegisterB;
|
RTC_REGISTER_B RegisterB;
|
||||||
UINT8 Century;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Check parameters for null pointer
|
// Check parameters for null pointer
|
||||||
|
@ -383,8 +379,6 @@ PcRtcGetTime (
|
||||||
Time->Month = RtcRead (RTC_ADDRESS_MONTH);
|
Time->Month = RtcRead (RTC_ADDRESS_MONTH);
|
||||||
Time->Year = RtcRead (RTC_ADDRESS_YEAR);
|
Time->Year = RtcRead (RTC_ADDRESS_YEAR);
|
||||||
|
|
||||||
Century = RtcRead (RTC_ADDRESS_CENTURY);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Release RTC Lock.
|
// Release RTC Lock.
|
||||||
//
|
//
|
||||||
|
@ -401,7 +395,7 @@ PcRtcGetTime (
|
||||||
//
|
//
|
||||||
// Make sure all field values are in correct range
|
// Make sure all field values are in correct range
|
||||||
//
|
//
|
||||||
Status = ConvertRtcTimeToEfiTime (Time, Century, RegisterB);
|
Status = ConvertRtcTimeToEfiTime (Time, RegisterB);
|
||||||
if (!EFI_ERROR (Status)) {
|
if (!EFI_ERROR (Status)) {
|
||||||
Status = RtcTimeFieldsValid (Time);
|
Status = RtcTimeFieldsValid (Time);
|
||||||
}
|
}
|
||||||
|
@ -447,7 +441,6 @@ PcRtcSetTime (
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
EFI_TIME RtcTime;
|
EFI_TIME RtcTime;
|
||||||
RTC_REGISTER_B RegisterB;
|
RTC_REGISTER_B RegisterB;
|
||||||
UINT8 Century;
|
|
||||||
UINT32 TimerVar;
|
UINT32 TimerVar;
|
||||||
|
|
||||||
if (Time == NULL) {
|
if (Time == NULL) {
|
||||||
|
@ -506,7 +499,7 @@ PcRtcSetTime (
|
||||||
RegisterB.Bits.Set = 1;
|
RegisterB.Bits.Set = 1;
|
||||||
RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
|
RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
|
||||||
|
|
||||||
ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);
|
ConvertEfiTimeToRtcTime (&RtcTime, RegisterB);
|
||||||
|
|
||||||
RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second);
|
RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second);
|
||||||
RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute);
|
RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute);
|
||||||
|
@ -514,7 +507,6 @@ PcRtcSetTime (
|
||||||
RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day);
|
RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day);
|
||||||
RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month);
|
RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month);
|
||||||
RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year);
|
RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year);
|
||||||
RtcWrite (RTC_ADDRESS_CENTURY, Century);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Allow updates of the RTC registers
|
// Allow updates of the RTC registers
|
||||||
|
@ -564,7 +556,6 @@ PcRtcGetWakeupTime (
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
RTC_REGISTER_B RegisterB;
|
RTC_REGISTER_B RegisterB;
|
||||||
RTC_REGISTER_C RegisterC;
|
RTC_REGISTER_C RegisterC;
|
||||||
UINT8 Century;
|
|
||||||
EFI_TIME RtcTime;
|
EFI_TIME RtcTime;
|
||||||
UINTN DataSize;
|
UINTN DataSize;
|
||||||
|
|
||||||
|
@ -612,8 +603,6 @@ PcRtcGetWakeupTime (
|
||||||
Time->TimeZone = Global->SavedTimeZone;
|
Time->TimeZone = Global->SavedTimeZone;
|
||||||
Time->Daylight = Global->Daylight;
|
Time->Daylight = Global->Daylight;
|
||||||
|
|
||||||
Century = RtcRead (RTC_ADDRESS_CENTURY);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Get the alarm info from variable
|
// Get the alarm info from variable
|
||||||
//
|
//
|
||||||
|
@ -644,7 +633,7 @@ PcRtcGetWakeupTime (
|
||||||
//
|
//
|
||||||
// Make sure all field values are in correct range
|
// Make sure all field values are in correct range
|
||||||
//
|
//
|
||||||
Status = ConvertRtcTimeToEfiTime (Time, Century, RegisterB);
|
Status = ConvertRtcTimeToEfiTime (Time, RegisterB);
|
||||||
if (!EFI_ERROR (Status)) {
|
if (!EFI_ERROR (Status)) {
|
||||||
Status = RtcTimeFieldsValid (Time);
|
Status = RtcTimeFieldsValid (Time);
|
||||||
}
|
}
|
||||||
|
@ -680,7 +669,6 @@ PcRtcSetWakeupTime (
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
EFI_TIME RtcTime;
|
EFI_TIME RtcTime;
|
||||||
RTC_REGISTER_B RegisterB;
|
RTC_REGISTER_B RegisterB;
|
||||||
UINT8 Century;
|
|
||||||
EFI_TIME_CAPABILITIES Capabilities;
|
EFI_TIME_CAPABILITIES Capabilities;
|
||||||
|
|
||||||
ZeroMem (&RtcTime, sizeof (RtcTime));
|
ZeroMem (&RtcTime, sizeof (RtcTime));
|
||||||
|
@ -736,7 +724,7 @@ PcRtcSetWakeupTime (
|
||||||
RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
|
RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
|
||||||
|
|
||||||
if (Enable) {
|
if (Enable) {
|
||||||
ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);
|
ConvertEfiTimeToRtcTime (&RtcTime, RegisterB);
|
||||||
} else {
|
} else {
|
||||||
//
|
//
|
||||||
// if the alarm is disable, record the current setting.
|
// if the alarm is disable, record the current setting.
|
||||||
|
@ -837,7 +825,6 @@ CheckAndConvertBcd8ToDecimal8 (
|
||||||
|
|
||||||
@param Time On input, the time data read from RTC to convert
|
@param Time On input, the time data read from RTC to convert
|
||||||
On output, the time converted to UEFI format
|
On output, the time converted to UEFI format
|
||||||
@param Century Value of century read from RTC.
|
|
||||||
@param RegisterB Value of Register B of RTC, indicating data mode
|
@param RegisterB Value of Register B of RTC, indicating data mode
|
||||||
and hour format.
|
and hour format.
|
||||||
|
|
||||||
|
@ -848,11 +835,11 @@ CheckAndConvertBcd8ToDecimal8 (
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
ConvertRtcTimeToEfiTime (
|
ConvertRtcTimeToEfiTime (
|
||||||
IN OUT EFI_TIME *Time,
|
IN OUT EFI_TIME *Time,
|
||||||
IN UINT8 Century,
|
|
||||||
IN RTC_REGISTER_B RegisterB
|
IN RTC_REGISTER_B RegisterB
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
BOOLEAN IsPM;
|
BOOLEAN IsPM;
|
||||||
|
UINT8 Century;
|
||||||
|
|
||||||
if ((Time->Hour & 0x80) != 0) {
|
if ((Time->Hour & 0x80) != 0) {
|
||||||
IsPM = TRUE;
|
IsPM = TRUE;
|
||||||
|
@ -870,14 +857,21 @@ ConvertRtcTimeToEfiTime (
|
||||||
Time->Minute = CheckAndConvertBcd8ToDecimal8 (Time->Minute);
|
Time->Minute = CheckAndConvertBcd8ToDecimal8 (Time->Minute);
|
||||||
Time->Second = CheckAndConvertBcd8ToDecimal8 (Time->Second);
|
Time->Second = CheckAndConvertBcd8ToDecimal8 (Time->Second);
|
||||||
}
|
}
|
||||||
Century = CheckAndConvertBcd8ToDecimal8 (Century);
|
|
||||||
|
|
||||||
if (Time->Year == 0xff || Time->Month == 0xff || Time->Day == 0xff ||
|
if (Time->Year == 0xff || Time->Month == 0xff || Time->Day == 0xff ||
|
||||||
Time->Hour == 0xff || Time->Minute == 0xff || Time->Second == 0xff ||
|
Time->Hour == 0xff || Time->Minute == 0xff || Time->Second == 0xff) {
|
||||||
Century == 0xff) {
|
|
||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// For minimal/maximum year range [1970, 2069],
|
||||||
|
// Century is 19 if RTC year >= 70,
|
||||||
|
// Century is 20 otherwise.
|
||||||
|
//
|
||||||
|
Century = (UINT8) (PcdGet16 (PcdMinimalValidYear) / 100);
|
||||||
|
if (Time->Year < PcdGet16 (PcdMinimalValidYear) % 100) {
|
||||||
|
Century++;
|
||||||
|
}
|
||||||
Time->Year = (UINT16) (Century * 100 + Time->Year);
|
Time->Year = (UINT16) (Century * 100 + Time->Year);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1053,14 +1047,11 @@ IsLeapYear (
|
||||||
@param Time On input, the time data read from UEFI to convert
|
@param Time On input, the time data read from UEFI to convert
|
||||||
On output, the time converted to RTC format
|
On output, the time converted to RTC format
|
||||||
@param RegisterB Value of Register B of RTC, indicating data mode
|
@param RegisterB Value of Register B of RTC, indicating data mode
|
||||||
@param Century It is set according to EFI_TIME Time.
|
|
||||||
|
|
||||||
**/
|
**/
|
||||||
VOID
|
VOID
|
||||||
ConvertEfiTimeToRtcTime (
|
ConvertEfiTimeToRtcTime (
|
||||||
IN OUT EFI_TIME *Time,
|
IN OUT EFI_TIME *Time,
|
||||||
IN RTC_REGISTER_B RegisterB,
|
IN RTC_REGISTER_B RegisterB
|
||||||
OUT UINT8 *Century
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
BOOLEAN IsPM;
|
BOOLEAN IsPM;
|
||||||
|
@ -1081,10 +1072,8 @@ ConvertEfiTimeToRtcTime (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// Set the Time/Date/Daylight Savings values.
|
// Set the Time/Date values.
|
||||||
//
|
//
|
||||||
*Century = DecimalToBcd8 ((UINT8) (Time->Year / 100));
|
|
||||||
|
|
||||||
Time->Year = (UINT16) (Time->Year % 100);
|
Time->Year = (UINT16) (Time->Year % 100);
|
||||||
|
|
||||||
if (RegisterB.Bits.Dm == 0) {
|
if (RegisterB.Bits.Dm == 0) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/** @file
|
/** @file
|
||||||
Header file for real time clock driver.
|
Header file for real time clock driver.
|
||||||
|
|
||||||
Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
which accompanies this distribution. The full text of the license may be found at
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
@ -61,7 +61,6 @@ typedef struct {
|
||||||
#define RTC_ADDRESS_REGISTER_B 11 // R/W
|
#define RTC_ADDRESS_REGISTER_B 11 // R/W
|
||||||
#define RTC_ADDRESS_REGISTER_C 12 // RO
|
#define RTC_ADDRESS_REGISTER_C 12 // RO
|
||||||
#define RTC_ADDRESS_REGISTER_D 13 // RO
|
#define RTC_ADDRESS_REGISTER_D 13 // RO
|
||||||
#define RTC_ADDRESS_CENTURY 50 // R/W Range 19..20 Bit 8 is R/W
|
|
||||||
//
|
//
|
||||||
// Date and time initial values.
|
// Date and time initial values.
|
||||||
// They are used if the RTC values are invalid during driver initialization
|
// They are used if the RTC values are invalid during driver initialization
|
||||||
|
@ -71,7 +70,6 @@ typedef struct {
|
||||||
#define RTC_INIT_HOUR 0
|
#define RTC_INIT_HOUR 0
|
||||||
#define RTC_INIT_DAY 1
|
#define RTC_INIT_DAY 1
|
||||||
#define RTC_INIT_MONTH 1
|
#define RTC_INIT_MONTH 1
|
||||||
#define RTC_INIT_YEAR 2001
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Register initial values
|
// Register initial values
|
||||||
|
@ -287,14 +285,11 @@ RtcTimeFieldsValid (
|
||||||
@param Time On input, the time data read from UEFI to convert
|
@param Time On input, the time data read from UEFI to convert
|
||||||
On output, the time converted to RTC format
|
On output, the time converted to RTC format
|
||||||
@param RegisterB Value of Register B of RTC, indicating data mode
|
@param RegisterB Value of Register B of RTC, indicating data mode
|
||||||
@param Century It is set according to EFI_TIME Time.
|
|
||||||
|
|
||||||
**/
|
**/
|
||||||
VOID
|
VOID
|
||||||
ConvertEfiTimeToRtcTime (
|
ConvertEfiTimeToRtcTime (
|
||||||
IN OUT EFI_TIME *Time,
|
IN OUT EFI_TIME *Time,
|
||||||
IN RTC_REGISTER_B RegisterB,
|
IN RTC_REGISTER_B RegisterB
|
||||||
OUT UINT8 *Century
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -308,7 +303,6 @@ ConvertEfiTimeToRtcTime (
|
||||||
|
|
||||||
@param Time On input, the time data read from RTC to convert
|
@param Time On input, the time data read from RTC to convert
|
||||||
On output, the time converted to UEFI format
|
On output, the time converted to UEFI format
|
||||||
@param Century Value of century read from RTC.
|
|
||||||
@param RegisterB Value of Register B of RTC, indicating data mode
|
@param RegisterB Value of Register B of RTC, indicating data mode
|
||||||
and hour format.
|
and hour format.
|
||||||
|
|
||||||
|
@ -319,7 +313,6 @@ ConvertEfiTimeToRtcTime (
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
ConvertRtcTimeToEfiTime (
|
ConvertRtcTimeToEfiTime (
|
||||||
IN OUT EFI_TIME *Time,
|
IN OUT EFI_TIME *Time,
|
||||||
IN UINT8 Century,
|
|
||||||
IN RTC_REGISTER_B RegisterB
|
IN RTC_REGISTER_B RegisterB
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue